Updating MinimumSize while resizing does not work ?

P

Pierre Arnaud

Hello,

I have come across a problem for which I don't see any solution
in the managed world. Here is the simplest way to reproduce it :

- Create a Form with a MinimumSize set to 100 x 100.

- When the ResizeBegin event is fired, change the MinimumSize
to 50 x 50.

As soon as I start dragging the right side of my form, I'd expect
the new MinimumSize to become active, yet Windows somehow keeps
track of the original MinimumSize : I cannot reduce the size of
my window below 100 x 100.

Checking with SPY++, I see that the Form properly reports an
updated MinimumSize when the WM_GETMINMAXINFO event gets fired :

- WM_MOUSEMOVE
- WM_SIZING
- WM_WINDOWPOSCHANGING
- WM_GETMINMAXINFO
- WM_NCCALCSIZE
- WM_NCPAINT
....
- WM_WINDOWPOSCHANGED
- WM_SIZE
...

Yet, as soon as I move to far to the left (where Width would
become less than 100 pixels wide), I only get a tight loop of :

- WM_MOUSEMOVE
- WM_SIZING

And WM_SIZING no longer changes.

Is this by design ?

I expected to be able to change the minimum size on the fly
(in my real application, I need to update it based on the
new window size, as the window contents rearranges itself,
the minimum can become smaller than what I had first assumed).

Is there any way to make my scenario work ? Even dirty WndProc
tricks will do, as long as I can make Windows forget about the
initial reply to WM_GETMINMAXINFO !

Pierre

Author of Creative Docs .NET -- http://www.creativedocs.net/
 
L

Linda Liu [MSFT]

Hi Pierre,

I performed a test based on your description. I set up a WinForms
application, set the MinimumSize of the form to 400 x 400 and the Size of
the form to 500 x 500. I handle the form's ResizeBegin event. Below is the
code of the form's ResizeBegin event handler.

using System.Diagnostics;

public class Form1 : Form
{
private void Form1_ResizeBegin(object sender, EventArgs e)
{
this.MinimumSize = new Size(100, 100);
// When the program is running with debugging and the below code
is executed, the information will be written in the Output window.
Debug.WriteLine("resize begin:" +
this.MinimumSize.Width.ToString());
}
}

Build the project and press F5 to run the program. I found the facts as
follows.

1. When I begin to resize the form for the first time, I saw the
information is written in the Output window: resize begin:100, but the form
can only be minimized to 400 x 400. When I begin to resize the form for
the second time, I could minimize the form to 100 x 100.

2. If I move the form before resize it, the information "resize begin:100"
is written in the Output window as well. Then if I resize the form, I could
minimize the form to 100 x 100 at this time.

Until now, we can see that even if the value of the MinimumSize property of
the form is modified, this will take effect in the next time. So I
recommend you to change the value of the MinimumSize property outside the
form's ResizeBegin, Resize and ResizeEnd event handlers. The detailed place
where you should put this code depends on your real requirement.

Hope this helps.

If you have any questions, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Linda,

I am glad you were able to reproduce the problem. However, your solution
does not work for me. I really need to be able to update the MinimumSize
on the fly, while the user is dragging the right hand border of the window.

The only solution I see for now is to set MinimumSize to {0;0} and then
somehow handle the WM_SIZING event in order to avoid having the user
make the window to narrow.

But I'd be glad if you could provide me an explanation of why Windows is
behaving that way. I see nothing in the documentation for the WM_*
messages sent while the resizing is happening, which states that the
initial WM_GETMINMAXINFO size should take precedence over the next
values.

I fear I've stumbled across a .NET/WinForms bug with respect to this
behaviour.

Thank you for your time.

Pierre
 
S

Stoitcho Goutsev \(100\)

Pierre,

WM_GETMINMAXINFO is sent twise: before entering the size/move modal loop and
once before exiting. It looks like the min track size value returned from
the message is used. On the other hand OnResizeBegin is fired in response to
WM_ENTERSIZEMOVE and apperantly setting MinimumSize here is too late - new
size needs to be set upon receiving WM_GETMINMAXINFO.
Unfortunately controls doesn't have corresponding event for
WM_GETMINMAXINFO, thus it needs to be handled in the WndProc override.

Here is an examle how this can be done.


const int WM_GETMINMAXINFO = 0x0024;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_GETMINMAXINFO)
{
this.MinimumSize = new Size(100, 100);
}
base.WndProc(ref m);
}


I don't know wheter the OS behaves like this or it's a bug in the Form
class. Looking in the class though I don't see a reason for this not work if
Windows OS takes into accoung min track size values returned by the second
WM_GETMINMAXINFO message. Unfortunately at the moment I don't have time to
dig into this deeper.
 
P

Patrice

Could worth to try to repro this using WinAPI but IMO not really surprising
and likely at the OS level. The minimum size is IMO taken and "cached" when
resize begins.

Else Windows would have to repeateadly read again this info in case the
resize process would have changed it (and would come accross more debatable
issues such as what to do if the new minimum size is bigger than the current
size etc...) plus it would generate more messages which was likely preferred
to be avoided when resizing was not a cheap operation.
 
G

Guest

Patrice said:
Could worth to try to repro this using WinAPI but IMO not really surprising
and likely at the OS level. The minimum size is IMO taken and "cached" when
resize begins.

This makes sense.
Else Windows would have to repeateadly read again this info in case the
resize process would have changed it [...]

Yes, but that's exactly what I see with Spy++ : Windows keeps asking
for the MINMAXINFO every time I move the mouse. Really strange.
(and would come accross more debatable
issues such as what to do if the new minimum size is bigger than the current
size etc...) plus it would generate more messages which was likely preferred
to be avoided when resizing was not a cheap operation.

You have a point, there. I'll try another approach tomorrow and let you
know of the results.

Thanks a lot.

Pierre
 
G

Guest

the message is used. On the other hand OnResizeBegin is fired in response to
WM_ENTERSIZEMOVE and apperantly setting MinimumSize here is too late - new
size needs to be set upon receiving WM_GETMINMAXINFO.

I tried that, too. I had a test application with WndProc handling the
WM_GETMINMAXINFO itself, but it didn't work any better.

Thanks anyway for the idea.

Pierre
 
G

Guest

My experiments have shown that the information returned by
the first WM_GETMINMAXINFO message sent while the user is
resizing a window gets indeed cached by Windows. Subsequent
WM_GETMINMAXINFO cannot increase the minimum size.

The only solution is to return a minimum size of [1;1] in the
initial WM_GETMINMAXINFO and then handle the WM_SIZING
message in order to restrict the moves of the window rectangle
based on my own minimum size information.

So this has nothing to do with WinForms and everything to do
with the way Windows "optimizes" the message handling. I'd
have loved to find this better documented on MSDN Library.

Pierre
 
S

Stoitcho Goutsev \(100\)

Pierre,

In my test application changing the min size in WndProc upon receiving
WM_GETMINMAXINFO works OK. I mean I have from restricted to 400x400, but I
can change this in WndProc to 100x100 and it works.

Are your tests show differently or you cannot use it for some other reasons?

..
 
P

Pierre Arnaud

Stoitcho said:
Pierre,

In my test application changing the min size in WndProc upon receiving
WM_GETMINMAXINFO works OK. I mean I have from restricted to 400x400,
but I can change this in WndProc to 100x100 and it works.

Are your tests show differently or you cannot use it for some other
reasons?

Well, it works if you just want to specify the size once at the
beginning of the resizing operation. In my case, I must be able
to update this *while* the user is dragging (e.g. 400x400 first,
then as we reach a width of 420, I want to be able to specify a
new minimum size of 350, etc.)

Pierre
 
S

Stoitcho Goutsev \(100\)

Pierre,

It looks like you hit OS limitation here. Apperanly you cannot use
MinimumSize for that and you should try to use the rest of the events
related to control resizing.
 
P

Pierre Arnaud

Stoitcho,
It looks like you hit OS limitation here. Apperanly you cannot use
MinimumSize for that and you should try to use the rest of the events
related to control resizing.

You are right. I am now using a minimum size of [1;1] and handling the
WM_SIZING events to restrict the window resizing to my currently active
minimum size.

Pierre
 
L

Linda Liu [MSFT]

Hi Pierre,

The WM_GETMINMAXINFO message is sent to a window when the size or position
of the window is about to change. An application can use this message to
override the window's default maximized size and position, or its default
minimum or maximum tracking size.
I really need to be able to update the MinimumSize on the fly, while the
user is dragging the right hand border of the window.

Since each time we resize the form, the WM_GETMINMAXINFO message is sent to
the form to ask the MinimumSize, we could change the form's MinimumSize
property in the overridden WndProc method and the new setting takes effect
immediately. Could you tell me how you update the MinimumSize on the fly? I
think you could move the logic of updating the MinimumSize property to the
overridden WndProc method.

The following is a sample.

private const long WM_GETMINMAXINFO = 0x24;

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_GETMINMAXINFO)
{
// put your logic to update the MinimumSize property of the
form here
//this.MinimumSize = new Size(200, 200);
}
base.WndProc(ref m);
}

Hope this helps.
If you have anything concerns, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
S

Stoitcho Goutsev \(100\)

Linda,

What is said si correct, but not completely. As we discussed earlier in this
thread. WM_GETMINMAXINFO is set twise during the operation of resizing. Once
before entering the resize/move modal loop and once at the end of the loop.
The problem is that the information returned in response to the first
message is probably cached and used for the whole resize session. In other
words the MinimumSize can be changed only before the actuall resizing.

Pierre's problem is that the minmum size is calculated during the resizing
(inside thesize/move modal loop) and there is too late - windows has alreay
cached the minmum track size.

If you change the MinimumSize of a form or control in any of the control
events that has anything to do with interactive resizing e.g. Reszize,
ResizeBegin, ResizeEnd, etc the changes won't take effect until the next
resize operation.

BTW this not windows forms proble it looks like this is a probably bug in
the Windows OS itself.
 
L

Linda Liu [MSFT]

Hi Stoitcho,

Thanks for your insight.

Yes, you're right. If we change the MinimumSize property of a form in its
Resize or ResizeBegin or ResizeEnd event handler, the change won't take
effect until the next resize operation.

But we could do it in the overridden WndProc method. I don't know what the
logic is that Pierre uses to calculate the minimum size, but I think Pierre
could move the code of updating the minimum size to the WndProc method to
make the change take effect for the current resize session.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
S

Stoitcho Goutsev \(100\)

Linda,

Yes, that was my suggestion, but it seems it doesn't work for him.
 
P

Pierre Arnaud

I tried overriding the WM_GETMINMAXINFO in WndProc, and it did not
help, as Windows seems to be caching the first size returned by
this message.

But never mind, as I have stated elsewhere in this now deep thread,
I've solved my problem by setting the minimum size to 1;1 and then
handling the WM_SIZING messages instead, which allow me to control
very exactly the size of the window.

My resize logic is a bit strange in that you'd normally expect the
contents of a window to have a predictive minimum size. In my case,
it is not. Whenever I change the window size, the contents of the
window can rearrange to better use the available size (e.g. use
shorter labels, smaller buttons, whatever) and this produces a
smaller minimum size as originally expected. So when the user
drags the window frame to resize the form, I go through a full
layout phase which might update the controls and then I determine
the current minimum size.

You may consider this thread as closed as my issue was solved.
Thank you very much to all of you who produced advice.

And sorry for my delay in responding. My first child was born
on Monday, so I've not been spending much time online.

By the way, for the curious: http://www.opac.ch/naissance/2006/
 
L

Linda Liu [MSFT]

Hi Pierre,

Thank you for your reply and CONGRATULATIONS!

If you have any question in the future, please don't hesitate to contact us.

Best regards,

Linda Liu
Microsoft Online Community Support
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top