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
Related
This is really really the most annoying thing in my programming life:
I have a form which is kept alive along with my application. I have no code calling to some method which will dispose it, I don't want it to be disposed by any reason, and I'm sure if it happens, the reason would not be in my code. This form is a custom form which has a method called Next(), this Next() simply displays the next item info on the form.
The worst thing occurred when I pressed on a button which caused the call to Next() and there was an exception saying "Object reference not set to an instance of an object". What? And here is the code, I saved a reference of my form into a Form variable called "currentShownForm" (there is only 1 of my forms are shown at a time, all of these should live along with my application):
private void ShowForm(CustomRibbonForm form)
{
if (!form.Visible)
{
if (currentShownForm != null) currentShownForm.Hide();
form.Show();
currentShownForm = form;
}
}
and the Next() is called like this if I press the button Next:
currentShownForm.Next();
The enigma is in the form.Show();
With the method ShowForm() above, do you think the currentShowForm can be null??? What? Any case? The only moment it is null is before the first form is shown. After the first is shown, it will be the first form, any other next form is shown will be referred by it. So how it becomes null in some case??? The code in ShowForm() method is the only one can change the reference of currentShownForm in my project.
That really baffled me a lot, I couldn't believe in what I saw. Oh my God, I didn't have any clue on this, any idea, but I had to try the most ridiculous thing like this:
private void ShowForm(CustomRibbonForm form){
if (!form.Visible)
{
if (currentShownForm != null) currentShownForm.Hide();
currentShownForm = form;
form.Show();
}
}
Wow, before trying this, I didn't thing it could make any thing different, but it did work. The currentShownForm was not null when I pressed the Next button. What is the magic of the swap between the two lines of code in ShowForm??? I think of only 1 reason for that, the form.Show() somehow disposed the form itself? But why was it still shown?
The noticeable thing is my form is not .NET form (just inherits from .NET form), it is a custom form, and again it's from DotNetBar lib, wow, I have an idea about writing a book of the most annoying things you should know when working with DotNetBar (At least, I've had about 5 things to write, I bet there will be more if I still use it).
Please see the code above and give me some explanation on why it could happen that way? I can't explain it, in fact, I suppose that's a bug.
Your help would be highly appreciated!
Thank you!
UPDATE
Now, at least I know the original thing from which the problem occurs but still don't understand why:
In fact my form has some Custom controls, the involved control here is a CustomComboBox. This comboBox is a 2-in-1 control consisting of a normal ComboBox (again, a DotNetBar combobox namely ComboBoxEx) and a focusable Label (a custom UserControl). All the controls register a ParentChanged event to register some events for their parent form, like this:
protected override void OnParentChanged(EventArgs e){
if(Parent is CustomRibbonForm){
((CustomRibbonForm)Parent).RefreshControls += (s,ev) => {
Show();
Hide();
};
}
}
My form has a defined event called RefreshControls which will be raised when needed. It has a public method to raise that event called RefreshAllControls. And the call to that method is placed after ShowForm() in the Activated event handler for my main form (not the form I'm talking about) like this:
Activated += (s,e) => {
ShowForm(myForm);
myForm.RefreshAllControls();
};
And here is what next: When I comment out the Show(); and Hide(); in the OnParentChanged method, it works OK in both cases:
protected override void OnParentChanged(EventArgs e){
if(Parent is CustomRibbonForm){
((CustomRibbonForm)Parent).RefreshControls += (s,ev) => {
//Show();
//Hide();
};
}
}
But if not, only 1 case works (the currentShowForm is assigned before the call to form.Show(). It's closer to the cause to the problem but it's still not easy to understand.
Hope you have something to explain to me with this update! Thank you
Next UPDATE
Now I know the currentShownForm is null because the first assignment was in fact never done, the form is shown but the currentShownForm = form is not executed and because currentShownForm is initially null, it's still null after the call to ShowForm() method.
It's very close to the cause but it's still very strange:
private void ShowForm(CustomRibbonForm form){
if (!form.Visible)
{
if (currentShownForm != null) currentShownForm.Hide();
form.Show(); //<------ I marked a break point here.
currentShownForm = form; //<----- I also marked a break point here.
}
}
After marked two break points following each other in the same method, it seems to be sure that all the break points will be stepped through, but only the first is stepped through. After that, the main UI is shown and the second break point is bypassed???????? What?????????????? There are many of events occurred after the call to form.Show(), most of them are events in my Custom controls (relating to Focus, LostFocus and Paint events). This is the first time I've seen such a strange code stepping. Now this is very close to the cause, hope you have something to say. Thank you
When Form2 is closed, via it's X button, the Main form is sometimes hidden as well, but not always. Often times the Main form is hidden after initial 'newForm' button click and other times many open-close operations are required before the Main form gets hidden on Form2's closing. Why is this happening? Why is it irregular?
This is a small test code for a larger application I'm working on. In that application a thread continuously reads the network stream and when a particular message is encountered a modal form is displayed. The user can close that modal form or it can be told to close itself by a different network message. In this event, to give the user some time to view the data that the form is displaying I implemented a delayed form closing for that form. When the form is running its delay closing code, another message can come in over the network that will open up a new instance of this form in which case, I observed, that once the timer of the original form runs out, the original form is left displayed until the new instance is closed. Calling Hide in the FormClosing event handler closes the original form if more than one instances of it are running, but it has this side effect of hiding the entire application (the Main form) when the last instance of this form is closed, either by the user or by the delayed closing code. And again, the entire application is not always hidden, but it does happen.
//Main form's 'newForm' button
private void btn_newForm_Click(object sender, EventArgs e)
{
Form2 f = new Form2();
f.ShowDialog();
}
public partial class Form2 : Form
{
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
Hide();
}
}
Update (from the application I'm working on):
The problem is shown visually below. The top part of the picture, labeled "A", represents the situation where the first modal dialog (greyed out) was instantiated and it is in the process of being auto closed after 4 seconds have elapsed. The second instance (blue window heading) is active and awaiting input. In the lower part of the picture, labeled "B", the counter to closing of the first instance has completed, yet the first instance remains visible. Adding Hide does not change picture "A" but picture "B" would only be showing the active modal dialog, which is what I want. If Hide is not used and we have the case shown in "B", once the active modal dialog is closed the inactive dialog will disappear together with the active one, but no sooner. At this time my main form will be hidden as well, sometimes.
Your main form doesn't get hidden, it disappears behind another window. The flaw in your code is that for a brief moment none of your windows can get the focus. Your main window can't get the focus, it got disabled by your dialog and won't get re-enabled until the dialog is fully closed. Your dialog can't get the focus, you hide it. So Windows goes looking for another window to give the focus to and can only pick a window owned by another application. Like Visual Studio, nice and big so your main window is well covered by it.
Not sure what you are trying to do, it doesn't make sense to call Hide() since the dialog will close a couple of microseconds later. Just delete the statement.
I am not sure if I am right but maybe you forgot to add e.Cancel = true; to your closing event.
Second, I think using a modal form is only usefull when you expect an action like OK or CANCEL from user, that is where DialogResults comes handy. It sounds strange if this happens time to time not all the time! maybe you can try like this:
//Main form's 'newForm' button
//Define form in your mainform
private Form2 f;
private void btn_newForm_Click(object sender, EventArgs e)
{
if(f != null) { f.Show(); return; }
f = new Form2()
f.FormClosing += delegate { f.Hide(); };
f.Show();
}
I know the topic is quite old, but I recently had to look for answers for this precise question.
Why hiding the (child modal) form instead of closing it ?
I may be wrong, but I think that in some cases, hidding the modal child form instead of closing it is sometimes useful.
For example, I'm using a class that is a custom tree of grids. Think of something like an Excel Document with multiples tables (sheets) and each table can have child tables. A very powerful manner to store datas that can be used by multiple objects and multiple forms at a time.
Now, this "TreeTable_Class" object has an inbuilt custom form that actually shows the content of one of its tables at a time in a GridView, and you can select which table to show by selecting it in a Treeview. You can see here that the "Database Editor" is actually and MDI Form that can load the Form from any TreeTable_Class.
And this is the Form I use to edit the content of a Cell for a given (selected) Table (I've chosen another cell with long text content from another table in this database)
Now, when you choose to close the custom form instead of hiding it, that form will be unaccessible, you can't show it anymore, and you get an exception (no instance of the object) Somewhat, it isn't disposed yet (so the check If MyForm Is Nothing Then... is useless) I know I have to implement the GarbageCollector and dispose the Child Form manually, but it's outside the scope of this topic.
Anyway, my class could use a large amount of memory, of datas, and if I had to rebuilt ALL the contents each time I want to show a new instance of that form, that would be a large amount of workload in my application. That's why I have chosen to hide the form instead of closing it until the main application exits or when a specific CloseFormAndDispose() method is explicitly called, either by the program, or if I make this option available for the user via an user interface.
Workaround try :
This is the workaround I've found to override the "form replaced by another because none of the parent/child ones could be retrieved" :
Sorry, I'm in VB.. but you can use a tool to convert this to C#, or do it manually, it's pretty simple..
// This is the child, a Cell Editor that can edit the content of a Cell.
Protected WithEvents _CellEditor As CellEditor_Form = Nothing
This Editor form is a member of TreeTable_Form, a form that can actually show and edit the content of the whole Database File (a single file)
And this TreeTable_Form class contains a routine that handles CellEditor closing event
Public Partial Class TreeTable_Form
// Sorry. The "WithEvents" in C# is a litte bit complex to me... So, in VB :
Protected WithEvents _CellEditor As CellEditor_Form = Nothing
// ...
// CellEditor handling method (I used a Code converter...) :
// The original VB declaration is :
// Protected Sub RecallFormAfterCellEditorHidden() Handles _CellEditor.Closed
// You'll have to write specific Event handler for _CellEditor object declared above...
protected void RecallFocusAfterCellEditorHidden()
{
Application.DoEvents();
this.Focus();
}
End Class
This tiny protected void RecallFormAfterCellEditorHidden() method in your Class (if you are using a class that contains Forms) or in your Main From, assuming that your main form contains the child forms (dialogs) will try to force the focus on your Application or MainForm...
By the way, TreeTable_Form is actually a component of TreeTable_Class. The later is an object that can be used anywhere you want. In a Main Form Application, in another Class, in a dialog, anywhere... and could be passed by reference to share its contents between several items. And this TreeTable_Class contains a RecallFocusAfterTreeViewerHidden() method that handles the closing of that form. That means, the Form or Application that actually uses the class will get the focus each time you close the its child Form. I've made it that way to get an object that could be used anywhere
We still get problems !
However, this method will make your application flicker a bit each time you close your child dialog, and doesn't succeed at 100% ! Sometimes, my parent form still disappear from screen and gets struck behind another window. Alt+TAB wont helt either. But this happens less than without this method trick. I don't have any better answer at this time, still searching... I'll come back here if I find out how. I'm using this custom made application in my work to write memos during meetings for example, and produce PV (procès verbal - french sorry) in PDF or DOCx on the fly...
And I'm sorry, I'm in VB, not C#. Hope this helps a little, until we find a better workaround for this...
Please do not close the question straight away. The almost similar problem is also discussed in the following threads.
Windows Forms and ShowDialog problem
Form.ShowDialog() or Form.ShowDialog(this)?
But, these do not solve my problem.
The problem never occurred in my development machine. It occurred in the user machine but not always. In fact it occurred only 3 or 4 times.
When it happens it seems the application/calling form is frozen. If I can guess (as I am not seeing it on the screen) where the close button is and click on it on the called form, it closes and application goes back to usable state until it occurs again.
My views are encapsulated within the presenter, so I am not calling ShowDialog() from within the view but through the presenter.
MainPresenter
{
MainPresenter(IMainView view)
{
_view = view;
}
…
…
OpenSecondView()
{
var secondPresenter =_presenterFactory.Create<SecondPresenter>();
secondPresenter.Ininialize(_view);
}
}
// Initialize method in the SecondPresenter
Initialize(owner)
{
_secondView.ShowDialog(owner);
}
I am using observing presenter style of MVP explained here
http://www.aspiringcraftsman.com/2008/11/23/model-view-presenter-styles/
Questions:
How can I reproduce the problem in my development machine and fix it?
If I use Show() and set TopMost = true, is it possible this problem
to occur?
What are the things I should consider that may cause this problem?
If Show() absolutely guarantees that the problem will not occur, I will go with Show(). I kind of lost faith in ShowDialog() on this.
Any help will be greatly appreciated.
** The problem does not occur for a specific screen/view. It occurs randomly.
** For all the forms except main form, ShowInTaskBar is set to false.
You can try using TopMost = true for the form
Have you tried adding a this.Activate() in the load event for the form, because I have had a similar problem.
This is my Entry Form of my Application.
While Clicking the OK button, It will go to next form for further
processing.My Second form is
In the second Form, I have to choose,any one option button and then press ok button.After pressing ok button,i just calling some function and then it will return to Form1.But Form1 has not getting its control for some seconds.It looks like getting collapsed and needs to be refreshed.but i don't know how to refresh a form? Please Guide me to get out of this issue...
It looks like,
Call
this.Invalidate();
or
this.Refresh();
On the Form to update it.
You can redraw the Form by:
Form1.Invalidate();
or
Form1.Refresh();
EDIT:
Some loops and operations on the same thread of Form1 may cause it to stop responding. If it does, you may use the BackgroundWorker class to avoid it.
Calling the Invalidate method does not force a synchronous paint; to
force a synchronous paint, call the Update method after calling the
Invalidate method. When this method is called with no parameters, the
entire client area is added to the update region.
Control.Invalidate()
And use BeginUpdate() and EndUpdate() if possible.
You can use the Form.Invalidate(); or Form.Refresh(); methods.
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