Click here to Skip to main content
15,868,419 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
Hi
I'm opening a form as shown below from my main form when the user makes a selection of a menu item.

private void commToolStripMenuItem_Click(object sender, EventArgs e)
            {
                Command_Form Command_Form1 = new Command_Form();
                Command_Form1.ShowDialog();
               // Command_Form1.Dispose();    this didn't help
            }
Inside the form "Command_Form1"
I close it like this when the user clicks on the close button

private void Close_button_Click(object sender, EventArgs e)
          {
            this.Close();    //I get the exception here
          }
This process works fine once but on the second closing of the form
(Which I hope is a completely different/new instance of the form) I get the error in the title of this post.
This is the output in the debug window.
*A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll*
All the topics that list this error go on about not trying to do anything to a form that has not been displayed but this happens when I click on a button in the form.
It would seem to me that pretty much ensures the form has been displayed if I'm able to click its button.
The other posts I've found that list this type of error go on about making thread safe calls so I tried this as an experiment but it didn't make any difference.
private void Close_button_Click(object sender, EventArgs e)
               {
       if (this.InvokeRequired)
                   {
                       CloseCallback d = new CloseCallback(Close_button_Click);
                       Invoke(d, new object[] { sender, e });
                   }
                   else
                   {
                       this.Close();
I have multiple threads in my application but they are created by the controls I'm using not by me explicitly.
I am passing data from a serial port to/from the form by Marshling the received/sent data via a delegate[s].
It makes sense that the serial port would run on a different thread than the form but why would a button click on a form be in a diffrent thread than the form????
The whole thread thing is very confuzing
How do I figure out what threads originated where and what is going on in the threads that I didn't create explicitly?
Why would I need to invoke the form's close method via a delegate?
Heck is there anything I can do in this multi threading environment that is thread safe How do I know if what I'm doing is unsafe/safe if I don't know what/where/why/who/when is creating threads?
Posted
Updated 9-Feb-11 7:22am
v4

Try this (no guarantees):

C#
public class MyParentForm:Form
{
    private Command_Form Command_Form1 = null; 

    private void commToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Command_Form1 = new Command_Form();
        Command_Form1.Disposed += new EventHandler(cmdForm_Disposed)
        Command_Form1.ShowDialog();
    }

    void myForm_Disposed(object sender, EventArgs e)
    {
        Command_Form1 = null;
    }
}
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 9-Feb-11 13:29pm    
John, I don't thing the problem is here. I use my way which works, please see my answer.
--SA
Sergey Alexandrovich Kryukov 9-Feb-11 13:36pm    
Sorry, put important fix. I knew many situations when re-creating a dialog form or creation at wrong time creates problems.
--SA
Phillip Coiner 9-Feb-11 13:38pm    
Hi John
I had to change
EventHandler(cmdForm_Disposed)
to
EventHandler(mydForm_Disposed) in order to get it to compile
but I still get the exception thrown on Close();
I tried F11 to step into Close() on the debugger but I get the exception as soon as I do.
I don't think you problem with the dialog is threading. The dialog is shown from UI and closed from UI, so no Invoke required. Of course you should never operate forms from threads other than UI.

What you need is lazy pattern. Create you dialog only once:

C#
class MyClass /* ... */ { //can be your main form or something else working as a signleton

void ShowCommands {
   if (Command_Form1 == null)
      Command_Form1 = new Command_Form();
   Command_Form1.ShowDialog();
   //...
} //ShowCommands

Command_Form Command_Form1; //fixed!

} //MyClass


The only step you need is to override Form.FormClosing so the dialog in not closed but got hidden. The event argument's Cancel should be assigned to true to prevent "real" closing, and the form should by hidden:

C#
Command_Form1.FormClosing += (sender, eventArg) => {
    eventArg.Cancel = true;
    Command_Form1.Hide();
}; //Command_Form1.FormClosing


The bonus effect of such approach is that you always have you dialog form in the most recent state: control property, selection, focused control, etc., which is more convenient for the user.

—SA
 
Share this answer
 
v5
Comments
Phillip Coiner 9-Feb-11 13:43pm    
Hi SA
In the form I instantiate serial port object.
I want to have other forms that use the serial port so I think I want/need to close the form and make a new one that has a serial port perform other functions.
I am unsettled by the thought of leaving forms hanging around consuming resources when I'm not using them also....thanks for the suggestion maybe I'll think about redesigning the architecture but I can't see why my current approach shouldn't work.
fjdiewornncalwe 9-Feb-11 15:27pm    
Hey Phillip, I think you should reconsider instantiating the serial port within your UI objects. My personal preference/best practice is to ensure that UI is only dealing with UI. Move the data and operations out of the UI and into another class. In other words, I would have the UI only show results from within the serial port object, but that the serial port object is owned by a higher, application management level object.
Sergey Alexandrovich Kryukov 9-Feb-11 16:37pm    
Marcus, than you for this note.

Philip, Marcus is absolutely right.
Generally, if you do not design to separate UI from functionality well enough -- you're screwed! may be even worse than right now. I suggest you removed it.
Right, Marcus?

And try to use my advice with dialog's lazy creation. I'll tell you, this simple design pattern already helped me to resolve much more difficult situation with ShowDialog.
Try it and accept my answer.

--SA
Phillip Coiner 9-Feb-11 16:55pm    
Hi Marcus
The serial port class is a different class.
I instantiate a serial port object on my form and configure it with dialog box which is also a separate class but I don’t see this as a particularly flawed from an architecture standpoint ……….…well except for the not working twice part :o)

The form has a status box to show the state of the serial port open/closed baud rate parity stop start bits and a connect/disconnect button.
It seems my forms would end up being just as complex having to pass all the connections and port status to each one instead of each one containing their own instance of these objects plus if I did all this I still would want to create and delete forms as needed.
The serial port configuration could be done in one spot but I liked having it right there to show the user what the state of things are at any given moment.

This app will be used to configure and control a RF device.
One form is a nothing but a terminal emulator, the other form has buttons so that instead of typing commands at the terminal it sends / and retrieves packets from the device , the other form……..not started yet would be a front panel emulator with controls that simulate the buttons on the device…which would be subset of the command sending form with different graphics.
Another form would generate RSA keys to lock/unlock features of the device………I have this working as a command line application.
All forms could use the serial port from one location but I hate to start ripping stuff out that is working just fine as an individual form because I can’t create and destroy an object more than once.
I can't believe/am astonished that creating and deleting windows forms is considered/is a bug generating process???

Isn’t object reuse considered the reason to have all this C# stuff in the first place?
I still would like to be able to figure out what the heck is causing the trouble.. …….even if I have to rip everything out and move it around to accommodate the API.
Thanks again to everyone for their suggestions and help……….even if it hasn’t fixed anything yet it is good to be able to talk to someone about it.
Sergey Alexandrovich Kryukov 9-Feb-11 17:28pm    
Technically, you address this comment to me, not Marcus, did you know that?

I'm not sure you have to dig out all the problem in your current design. You see, it is abusive. You faced a problem on close, and, instead of realizing the real problem, started to do artificial processing in Invoke. Do you know how invoke works? It pack delegate with all parameters and put it to some queue in UI thread; UI thread process main getmessage/dispatch message cycle, gets the delegate and parameters from the queue and does the actual call. So, if you invoke in the same thread, it's useless (see Control.InvokeRequred, check it, for your understanding). You can learn things, of course, but you main course should be re-design.

Hope you will listen to a good friendly advice.

Best,
--SA
Hello friend..
As u told you are passing data from a serial port to/from the form by Marshling the received/sent data via a delegate[s]. Here, you had open the port, but you did not close the port. Thats why when you try to open it second time, its open and generate the error at the time of closing.
What you want to do, just close the port in Form.Closing(). Your problem will get solved.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900