Is there any way I can pause all UI Update commands in Winforms?
Or I have a slight feeling I'm trying to go about this the completely wrong way, so is there another way around my problem: I basically load a saved state of a control, which loads new controls all over it. However I do some of this in the UI thread, and some of the data loading from another thread, which then fills the UI.
So the effect I have when it is loading is that the user can see a few of the controls appearing in one place, then moving to another place on the form, changing values, etc.
I'd like to get a loading screen instead of this and load the controls in the background. It's quite a large application and its not THAT important so redesigning my code isn't really an option.
Can I simply stop all Update() commands on a control while a method is executing?
You can use the SuspendLayout and ResumeLayout methods to wrap the setup of UI in one operation (without the update of the rendering).
Basically (assuming SomeMethod is in the form class):
private void SomeMethod()
{
this.SuspendLayout();
// all UI setup
this.ResumeLayout();
}
it really depends on your form logic, in general you should not overload the Load or Show method with too much things so that the form can be shown and drawn quickly and always look responsive.
in some cases it could help to use the SuspendLayout and ResumeLayout methods, see here:
Control.SuspendLayout Method
I have a WinForms application that, at some point, will do some calculations that take a couple of seconds. During this time, I disable the controls. Additionally I want to display a popup that kind of 'blocks' the application more visibly.
I tried placing a Panel on top of the Form in order to do so, but there I'm somehow not able to add any text to it. I.e. the Labels and ImageBoxes I put there are somehow not displayed or behind the Panel.
Any suggestions how I could achieve this in a quick and easy way? .. I mean, without redesigning the whole Form.
Your problem with the things not showing up in your additional panel is that everything is happening in the same thread, but your calculations are blocking everything from appearing because they are hogging up the thread. You should look into using a backgroundWorker, which is one of the tools in WinForms. You should throw the function call that performs the calculations into the DoWork method of the backgroundWorker, then the form itself can continue to function during the calculations.
See http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx for examples
Create a Dialog Box (windows form) to popup during the processing, then you can have the Dialog Box close once your processing is completed.
By using a Dialog Box not a Message Box, you can still have control over closing the window when your processing is done.
You could create a simple UserControl with just a Label and an ImageBox, maybe with public setter for their values. You can add it to your form setting its Visible property to false. Then you can make it visible during your calculations and go back top invisible in the end.
I was wondering if I am doing correctly.
I instantiate a Form (let's call this Form_B) within my class (also a form) and handle Form_B's Load event. Within this event I do some initialization.
Form_B can be displayed by the user multiple times, and I call ShowDialog on my instance variable.
The problem is that the Load is called each time I show the form. I tried debugging and also tried with Show() instead of ShowDialog(). Show() fails as I closed the window but ShowDialog() does not fail, but calls Load every time it is displayed.
Is it incorrect to continue using the instance once the form is closed?
Thanks,
Stefan
Using the Load event to initialize a form is an anachronism from the VB6 days. It was really important back then, that unfortunately carried over in the design of the Winforms designer. It made Load the default event for a form.
That is however not the .NET way, you initialize a class object with the constructor. The only time you need to override OnLoad() (another .NET way, events are for code in other classes) is when you care about the size and position of the form. It won't be the design Size and Location when the user changed the Windows theme or runs the video adapter at a higher DPI setting. So you might want to use OnLoad to move the window or rearrange the controls. Not actually a very common thing to do.
So, fix your problem first by using the constructor instead. If you still need OnLoad then just use a bool flag that keeps track of whether or not it already ran.
private bool initialized = false;
protected override void OnLoad(EventArgs e) {
if (!initialized) {
initialized = true;
// etc...
}
base.OnLoad(e);
}
And yes, this only works if you use ShowDialog(). A form that's displayed with Show() automatically disposes itself when it is closed. That doesn't happen with ShowDialog() to avoid problems retrieving the dialog results. Re-creating the dialog instance is the better way, unless you really care about keeping the last entered values. That's however a really expensive way to do so, form objects take a lot of .NET and Windows resources.
That is the correct behaviour of the Load event, each time it is loaded it is called. If you want to reuse the form and avoid the the Load event, rather than close the form you should hide it and use the show method to bring it out when needed.
The load event is called once all the components of the form are loaded. If you redisplay the form, its components load again and therefore the Load event is triggered once more.
You could trigger a custom event that would only be triggered in your form's constructor if that's what you're looking for but I think it's bad practice to use a form after it's been closed.
I'm having the same problem. After searching awhile, I think the "ShowDialog" is an exception.
Since it's 2018 right now, MS has opened .Net. I've checked the source and found this.
this.CalledOnLoad = false;
this.CalledMakeVisible = false;
in the ShowDialog() function.
https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Form.cs,ab288b84e00f8282
I have a requirement where the user wants to be able to click a button to show a dialog with some information. They want the ability to move the dialog off of the form and put focus back on the calling form and make changes to the calling form with the dialog still open.
It is basically a map on the main form and the dialog is a map legend.
Is this possible? How would I accomplish this task? It seems like I would need to do something with a panel like how Visual Studio does this with their dockable panels.
Call the Show method instead of ShowDialog.
This method is a non-blocking call (unlike ShowDialog, it will return immediately, not after the new form closes) and will not show the form modally.
You'll probably want to pass the parent form as the parameter so that it will show as a child form.
You can show the dialog in non-modal way.
Like this:
formLegend.Show();
Insead of calling legendForm.ShowDialog(), just use legendForm.Show(). It will display the legend form without restricting the map's usage.
I have a very strange behavior that only seems to happen on one form.
Basically I am creating an instance of a Form, and calling Show() to display the form non-blocking. In that form's Load event handler, I have some logic that may call this.Close() under certain circumstances. This closes the form, but then the form Show() method in the client code throws an ObjectDisposedException.
The stack trace from the ObjectDisposedException is as follows:
at System.Windows.Forms.Control.CreateHandle()
at System.Windows.Forms.Form.CreateHandle()
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.ContainerControl.FocusActiveControlInternal()
at System.Windows.Forms.Form.SetVisibleCore(Boolean value)
at System.Windows.Forms.Control.Show()
...etc.
This is what I'm seeing happen:
Control.Show() is called
my form is launched
the OnFormLoad method is called
the FormLoad event handler is called, inside of which I call this.Close()
the OnFormClosing method is called
the FormClosing event handler is called
Dispose is called on my form and all it's user controls
and then somewhere toward the end of the Control.Show() method, it tries to get a handle to the form, which freaks out and throws an exception because the object is marked disposed.
My real question is, why can I do this exact same thing on every other form I have without exceptions? Is it a GC issue? I've tried putting a GC.Collect() call right after the this.Close() and it makes no difference. Like I said, it happens 100% of the time on this form, and never anywhere else, regardless of child user controls, scope of the form variable, etc.
Any ideas?
The best way to do so :
this.BeginInvoke(new MethodInvoker(this.Close));
this is the most simple way you wont get ObjectDisposedException
I know this is an old issue but no one seemed to have posted the obvoius answer.
You say you call Control.Show() and then Form.Close() and then the form is Disposed of. Well, unless you use MDI or use ShowDialog that's just as documented. Though, the short version of the Close() documentation is "Closes the form", it actually also disposes it implicitly under certain conditions.
See the remarks section:
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close.aspx
If you want to show a form again. Use the Hide() method instead of Close().
Hope that helps other searching souls.
And guys, don't stop searching at "I don't know why it works sometimes". That becomes buggy software with lots of defensive "I'll call this method again just in case" stuff. Not good.
Ok, hate to answer my own question, but this was driving me nuts, and it was one of the hardest bugs to reproduce I've ever seen.
On my form I'm overriding the OnFormLoad and OnFormClose methods, where I save/restore the form's Size, Location, and WindowState to/from the registry. I took this code out and it fixed the problem. The weird thing is, I put it back and the problem didn't come back.
I finally reproduced the problem: you have to let the form open fully, maximize it, and then close it so that the Maximized state is saved to the registry. Then when you open it again, it will set it to Maximized, and if it closes in the Load handler, it tries to access the Size/Location as it's closing. Apparently accessing these values in the OnFormClosing method causes the form to try to focus IF AND ONLY IF the form is maximized, which is illegal, since the form has been disposed.
So basically, you can't access Form display properties in the OnFormClosing method of a form, if that form is going to call Close from it's Load event.(Unless you check the Disposed prop first)
pretty specific piece of Winforms wisdom I know, but I'm writing it down anyway.
If you want to close a form as if the user pressed the cross in the upper right corner (usually means cancel), just add the following code.
this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.Close();
This also works in the form load function:
private void MyForm_Load (object sender, EventArgs e)
{
// do some initializations
if (!ContinueLoadingForm())
{
this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.Close();
return;
}
// continue loading the form
}
If you don't want the form to be visible for a short while, set the Visible property false (for example in the designer or constructor), and set it back to true when you are certain the program can continue loading.
In load event is not realy good idea close the form. Do it after the Activated event.
protected override void CreateHandle()
{
base.CreateHandle();
if (FormMustClose) //FormMustClose is a variable in the loadevent.
{
Close();
}
}
One possibility:
They may have a timer on this form, that is being initialized and enabled in their FormLoad event. The timer would need to be disabled and stopped as well, before the form was closed, if the timer is trying to access the form when it's fired.
I've seen forms before that do this...
It seems to me, without looking closely at it, that the cleanest way to accomplish what you want might be to make a custom form class deriving from Form, and override OnFormLoad(...) and/or Show() to check for your condition and cancel out early.
That said, I don't know why it would work sometimes and not other times.
Have you tried stepping into the .net code to see what line of code is being called when the exception is occuring? If you have VS 2008 you can do so by going to Tools --> Options --> Debugging and select the Enable .NET Framework Source Stepping. Be warned, this may take a while to download all of the necessary files, but this way you can step into the form.Show() and see exactly what is going on.
Ok, it turns out it's a little simpler and more generic than I thought, but still weird and obscure.
If you're saving/loading the form Size/Location/WindowState when the form loads/closes like we do, you have to make sure that the OnLoad method calls base.OnLoad first so that the Form Load event handler fires, and THEN set the properties. Not doing so will only cause a problem if the form calls Close from inside the Load method. You'll get an ObjectDisposedException on the Show call after the form closing event is done.
My head hurts.
Form.Shown() Is the trick too.
As I understand it, setting the DialogResult of the form will close the form - may have to be other than DialogResult.None. (i.e. you don't need to then call the Form.Close() method).
The issue is also in part that if elsewhere in code, you are accessing a property of the form or control within it, that may prevent the form from closing.
It may also be best if as has been suggested, you have a property e.g.
private bool _loadedOk = false;
in your form which you set in your initialisation code. In one of the later events after Form_Loaded, you then interrogate this and close the form if it's false.
Perhaps someone can suggest the best event to do this in??
If you want to close the form without flicker, the best way I found was override SetVisibleCore Method:
public partial class MyForm : Form
{
...
protected override void SetVisibleCore(bool value)
{
if (value && !IsHandleCreated && !ContinueLoadingForm())
{
base.SetVisibleCore(false);
this.Close();
return;
}
base.SetVisibleCore(value);
}
}
Then you can simply do:
...
var myForm = new MyForm();
myForm.Show();
...
The Form only will appear if ContinueLoadingForm() be true, this works with ShowDialog() and Application.Run() as well.
Expanding on RCMAN's answer in this thread (which got me 99% of the way to the finish line) ...
Here is the code I ended up using which also avoids the screen flicker:
Me.FormBorderStyle = FormBorderStyle.None
Me.Opacity = 0.01
Me.MinimumSize = New Size(1, 1)
Me.Size = Me.MinimumSize
Me.Location = New Point(1, 1)
BeginInvoke(New MethodInvoker(AddressOf Me.Close))
Additionally, to avoid the message "This program might not have run correctly" I applied a manifest change as described by mik here:
How to prevent "This program might not have installed correctly" messages on Vista