Odd behavior with WindowState

  • Thread starter Thread starter Jerad Rose
  • Start date Start date
J

Jerad Rose

I have a WinForms application in .NET 2.0. I'm trying to set the
WindowState property of my form prior to it being visible, but it's doing
some weird stuff.

My code looks something like this:

private void Form1_Load(object sender, EventArgs e)
{
this.Visible = false;
this.WindowState = FormWindowState.Maximized;
}

However, when the form finally shows, it is not maximized -- it's still set
to normal.

On the other hand, if I don't set this.Visible = false, then it will
maximize the form, but it will also immediately make the form visible when
the this.WindowState property is set.

Neither of these are the desired results. I am performing some operations
based on the form size after it is maximized, so I need the form's size to
reflect the maximized state, but I don't want the form to be visible until
after these operations are complete.

Question 1) Why does it behave this way? Is this intended, or was this just
an oversight (or even a bug)?

Question 2) Are there any workarounds to this? I have tried some other
things (setting Opacity = 0, which resulted in a weird flicker) but nothing
is producing a clean, flicker-free result.

Thanks in advance.
Jerad
 
private void Form1_Load(object sender, EventArgs e)
{
this.Visible = false;
this.WindowState = FormWindowState.Maximized;
}

I am in the habit of setting visible=false at the top of form_load, and
visible=true at the bottom. Somewhere between, I set windowstate if
necessary. I have never had a problem like you describe, no flicker,
nothing. I am suspicious of your not setting visible to true in the sample
above.
However, when the form finally shows, it is not maximized -- it's still set
to normal.

Where is it made visible?
On the other hand, if I don't set this.Visible = false, then it will
maximize the form, but it will also immediately make the form visible when
the this.WindowState property is set.

Yes, I agree - that is why I have the habit I mentioned above.
Neither of these are the desired results. I am performing some operations
based on the form size after it is maximized, so I need the form's size to
reflect the maximized state, but I don't want the form to be visible until
after these operations are complete.

You could use form.MaximizedBounds for the size of the form when it is
maximized. From your above remarks, it sounds like you are working around
the fact that setting windowstate in form_load does not immediately change
form.width (for example). Better, I think, to use MaximizedBounds and do all
this work in the load event.
 
AMercer said:
I am in the habit of setting visible=false at the top of form_load, and
visible=true at the bottom. Somewhere between, I set windowstate if
necessary. I have never had a problem like you describe, no flicker,
nothing. I am suspicious of your not setting visible to true in the
sample
above.

Why would you do something silly like that? The form isn't visible at the
start of form load and is made visible for you at the end. You're just
adding 2 lines of unecessary code.

Michael
 
Jerad Rose said:
Question 1) Why does it behave this way? Is this intended, or was this
just an oversight (or even a bug)?

The problem is in your code. It's not a bug or oversight, you're just not
doing what the designers expect.
Question 2) Are there any workarounds to this? I have tried some other
things (setting Opacity = 0, which resulted in a weird flicker) but
nothing is producing a clean, flicker-free result.

Yes but that is certainly not it. Why not just set the WindowState property
to Maximized in the properties window? Otherwise I think you can set it in
the forms constructor.

Michael
 
AMercer said:
I am in the habit of setting visible=false at the top of form_load, and
visible=true at the bottom. Somewhere between, I set windowstate if
necessary.

Why? The 'Load' event handler will be executed before the form is shown for
the first time. So there is no need to set the 'Visible' property to
'False' at the beginning in this case. However, what you can do is to show
the form manually in the handler by calling the form's 'Show' method or
setting its 'Visible' property to 'True'.
 
This reply is to both Herfried and Michael.

Circumstances can arise where drawing happens before the load event
completes. I don't know all the causes for these draws, but my workaround is
visible false at the top of the load event, and true at the bottom. It has
become a habit even in simple cases where it is unnecessary.

What causes a redraw before load has completed? Well, setting visible to
true in the load event will do it. But this aside, I just don't know what
the causes are. I have one form where all controls are added at runtime, and
absent visible false then true, I get flicker (it really looks like two draws
that happen one immediately after the other). I have another form where a
lengthy load event sets the visibility, size, and location of several
controls (a label, an rtb, a few checkboxes, and a few buttons) based on
runtime conditions. Again, absent visible false then true, I get a double
draw.

Over the years, many posers have complained about things like this. Many
descriptive words have been used, but flicker is the most common. I think
the OP has run into one of these situations. I believe the OP like I believe
most of the other posers because I have seen the same thing. There may be a
better workaround than visible false at the top and true at the bottom
(SuspendLayout maybe?), but it works for me and it solves a real problem.

So, I stand by my suggestion. Visible false at the top, do your thing, then
visible true at the bottom. It is an effective workaround given that we
can't see how the black box works - the causes of drawing during load remain
undocumented.
 
Thanks for the responses, everyone.

To respond to a few of your points...

From AMercer:
I am in the habit of setting visible=false at the top of form_load, and
visible=true at the bottom. Somewhere between, I set window if necessary.
I have never had a problem like you describe, no flicker, nothing. I am
suspicious of your not setting visible to true in the sample above.

If I did this, I would also see no flicker. But then my problem would be
the controls not rendering properly because of the bounds not being set on
the form properly. For example, put this code on a blank form:

private void Form1_Load(object sender, EventArgs e)
{
this.Visible = false;
Console.WriteLine(this.Bounds.ToString());

this.WindowState = FormWindowState.Maximized;
Console.WriteLine(this.Bounds.ToString());

this.Visible = true;
Console.WriteLine(this.Bounds.ToString());
}

And you will see that the second this.Bounds is still as it was before it
was maximized. If, prior to making your form visible, you make various
changes to the positioning of your controls, it is relative to the normal
window's bounds, rather than the maximized window's bounds.
Where is it made visible?

It is shown naturally after the Load event. If, using the above example, I
were to leave off "this.Visible = true;", it would still show, but only show
a normal window.
You could use form.MaximizedBounds for the size of the form when it is
maximized. From your above remarks, it sounds like you are working around
the fact that setting window in form_load does not immediately change
form.width (for example). Better, I think, to use MaximizedBounds and do
all this work in the load event.

This is actually a good suggestion -- I was not aware of this property.
However, I'm not using Bounds to position my controls -- the .NET framework
is. Specifically, I have SplitContainers whose position I am trying to set
before the form is shown, but it is showing these based off the form's
Bounds, which is incorrect until it is made visible. That's my problem.

From Michael C:
The problem is in your code. It's not a bug or oversight, you're just not
doing what the designers expect.

While I won't argue that there are better ways to do what I'm doing, that
still doesn't explain:

1) Why setting the WindowState causes the form to show permaturely (when not
explicitly setting Visible = false).

2) Why setting the WindowState with the form explicily hidden (Visible =
false) does not update the window's Bounds to reflect the Maximized state.

It seems there is no way for .NET framework to recognize that a window has
been maximized without having to show it. This, to me, seems to be either
an oversight or a bug (or limitation due to OS) -- I can't make sense out of
why this would have been intentional (by design). I recognize that I could
be wrong though, so please clarify if I'm still missing something.
Yes but that is certainly not it. Why not just set the WindowState
property to Maximized in the properties window? Otherwise I think you can
set it in the forms constructor.

Specifically, I am saving and loading the user's settings for the form from
the last time it was loaded and closed. I want it to open as maximized if
they closed it as maximized, and as normal if they closed it as normal.

I did try the same code above in the constructor rather than on Load, but
with the same results -- it would not recognize that the form was maximized
until it was shown, and therefore the Bounds was not set properly. The only
difference is that if I don't explicitly set Visible to false/true, it will
leave the form hidden on setting WindowState rather than showing it. But in
this case, the resulting output would always reflect the bounds of the
normal form window -- it wouldn't recogniz it as being maximized at all
during the constructor code.

Thanks again for the responses, but I'm still stuck. The best workaround
I've been able to come up with so far, is set as many settings as possible
prior to showing the form, and then show the form so that I can set my
SplitContainer's SplitterDistances properly.

Jerad
 
AMercer said:
This reply is to both Herfried and Michael.

Circumstances can arise where drawing happens before the load event
completes. I don't know all the causes for these draws, but my workaround
is
visible false at the top of the load event, and true at the bottom. It
has
become a habit even in simple cases where it is unnecessary.

What causes a redraw before load has completed? Well, setting visible to
true in the load event will do it. But this aside, I just don't know what
the causes are. I have one form where all controls are added at runtime,
and
absent visible false then true, I get flicker (it really looks like two
draws
that happen one immediately after the other). I have another form where a
lengthy load event sets the visibility, size, and location of several
controls (a label, an rtb, a few checkboxes, and a few buttons) based on
runtime conditions. Again, absent visible false then true, I get a double
draw.

Over the years, many posers have complained about things like this. Many
descriptive words have been used, but flicker is the most common. I think
the OP has run into one of these situations. I believe the OP like I
believe
most of the other posers because I have seen the same thing. There may be
a
better workaround than visible false at the top and true at the bottom
(SuspendLayout maybe?), but it works for me and it solves a real problem.

So, I stand by my suggestion. Visible false at the top, do your thing,
then
visible true at the bottom. It is an effective workaround given that we
can't see how the black box works - the causes of drawing during load
remain
undocumented.

Can you post some code that demonstrates this problem? I have all sorts of
forms that create controls in the load event and move things all over the
place and I've never had an issue. I would suggest it's better to solve the
problem than apply a workaround to every form whether it needs it or not.

Michael
 
Jerad Rose said:
While I won't argue that there are better ways to do what I'm doing, that
still doesn't explain:

1) Why setting the WindowState causes the form to show permaturely (when
not explicitly setting Visible = false).

2) Why setting the WindowState with the form explicily hidden (Visible =
false) does not update the window's Bounds to reflect the Maximized state.

I take it all back, I've tried it and it does look like a bug. It's always a
good idea to know what you're talking about before speaking :-)
Thanks again for the responses, but I'm still stuck. The best workaround
I've been able to come up with so far, is set as many settings as possible
prior to showing the form, and then show the form so that I can set my
SplitContainer's SplitterDistances properly.

I don't have a solution. I might try a couple of other things if I get the
chance today.
 
... I would suggest it's better to solve the
problem than apply a workaround to every form whether it needs it or not.

I disagree, see below for why.
Can you post some code that demonstrates this problem?

Ok, here's one. Make a form with no controls. In its load event, put

ControlBox = True ' forces a draw normal state
Threading.Thread.Sleep(1000) ' so you see it if your machine is very fast
WindowState = FormWindowState.Maximized ' later, a maximized draw

For what follows, I assume that you are able to reproduce the double draw
effect.

My earlier post stated that setting Visible to true will force a draw in the
load event. The above ControlBox assignment is a second case. I assert
that there are more double draw cases, and I don't know what they are, so
don't ask me to dig out any more. Knowing two leaves me uncertain about the
whole picture, and if I come up with a third, I will still be uncertain. The
burden is not on me to do this research, testing, and documentation, it is on
Microsoft. Nowhere in the documentation about Visible and ControlBox is the
idea of an immediate draw discussed. Also, please don't tell me that I
should set ControlBox in the designer. It will probably fix this problem,
but the documentation gives no reason to prefer the designer over code. I
see no merit in replacing my workaround (with no basis in the documentation)
with a 'do it in the designer' workaround (also with no basis in the
documentation).

As far as the load event goes, the double draw phenomenon is what the
workaround addresses. So, once more and with gusto, I stand by visible false
at the top and true at the bottom. It takes care of all of the double draw
behaviors, including those that I know about and those that I don't know
about. The workaround has never failed me, although it sounds like it is not
helping the OP solve his problem. FYI, I started using this workaround a
while ago, back in the vs2003 fw1.1 days. One could argue that it is time
revisit it - against that, this roof ain't broke, so why fix it?
 
AMercer said:
My earlier post stated that setting Visible to true will force a draw in
the
load event. The above ControlBox assignment is a second case. I assert
that there are more double draw cases, and I don't know what they are, so
don't ask me to dig out any more. Knowing two leaves me uncertain about
the
whole picture, and if I come up with a third, I will still be uncertain.
The
burden is not on me to do this research, testing, and documentation, it is
on
Microsoft. Nowhere in the documentation about Visible and ControlBox is
the
idea of an immediate draw discussed. Also, please don't tell me that I
should set ControlBox in the designer. It will probably fix this problem,
but the documentation gives no reason to prefer the designer over code. I
see no merit in replacing my workaround (with no basis in the
documentation)
with a 'do it in the designer' workaround (also with no basis in the
documentation).

As far as the load event goes, the double draw phenomenon is what the
workaround addresses. So, once more and with gusto, I stand by visible
false
at the top and true at the bottom. It takes care of all of the double
draw
behaviors, including those that I know about and those that I don't know
about. The workaround has never failed me, although it sounds like it is
not
helping the OP solve his problem. FYI, I started using this workaround a
while ago, back in the vs2003 fw1.1 days. One could argue that it is time
revisit it - against that, this roof ain't broke, so why fix it?

Fair enough, although I still think that applying a workaround to *every*
form for something that I have not encountered in 6 years of dot net
programming is unecessary.
 
Back
Top