1

The program I am writing includes a console. I've created a UserControl called Console. This Console class has multiple background workers doing various tasks. The problem I have run into is that if I place this control on a form and then close it, I occasionally run into problems where the BackgroundWorker threads are making calls to disposed objects.

Based on this thread, I need to stop the form closing and handle the close request myself. I have most of this written successfully, but the major problem I'm running into is subscribing to the ParentForm's FormClosing event.

I've been trying to use this.ParentForm but I can't find a good place where this isn't null.

Of course, I can't do this in the constructor, as it is being generated at this point.

I also can't use this in the ParentChanged event as mentioned in this thread. When this fires, this.Parent is no longer null, but that's not this.ParentForm. I realize sometimes it could be, but for example, I currently have this sitting in a tab control so that's not quite what I want.

Then we also have this suggestion to try hooking into the this.Load function (I'm referencing the second answer, not the selected one) but again, this.ParentForm is null here. As before, this.Parent has a value but it's not quite what I want.

Finally, I thought I found the solution to my problem when I came across this thread suggesting to override OnCreateControl but yet again... no luck, both are null.

After the form is loaded, I have added a button that I can press, and at that point, I have been able to determine that this.ParentForm does in fact get populated correctly.

My question- where can I get the UserControl's this.ParentForm where it isn't null so I can subscribe to it's events?

Edit: Adding some of my code per LarsTech's request:

The result of this code is:

This.Parent has a value

This.ParentForm is null

private MyConsole(string COMPort)
{
    // I do this so that the console window is created by the time I have started my Background Workers
    this.CreateHandle();

    // Generate the form
    InitializeComponent();
        
    // set the COM Port Name
    _COMPort = COMPort;
    ReadOnly = true;
    ActiveCloseRequest = false;

    // This just creates 1 or 2 background workers
    StartBackgroundWorkers();

    this.ParentChanged += MyConsole_ParentChanged;            
}
void MyConsole_ParentChanged(object sender, EventArgs e)
{
    if (this.Parent == null)
    {
        Console.WriteLine("This.Parent is null");
    }
    else
    {
        Console.WriteLine("This.Parent has a value");
    }
    if (this.ParentForm == null)
    {
        Console.WriteLine("This.ParentForm is null");
    }
    else
    {
        Console.WriteLine("This.ParentForm has a value");
    }
}
Community
  • 1
  • 1
bkribbs
  • 734
  • 1
  • 6
  • 24
  • How is this tagged asp and wpf? Is this silverlight or can you specify which UI framework you are using because it sounds a lot more like winforms. – Ron Beyer Aug 25 '15 at 17:58
  • Sorry, that was a mistake, you're quite right. I've changed it. – bkribbs Aug 25 '15 at 17:59
  • Make your control inherit `ISupportInitialize` which will make the designer use `BeginInit` and `EndInit` calls when creating your control. You can then get the parent form using `this.FindForm()` in the `EndInit` method. – Ron Beyer Aug 25 '15 at 18:05
  • I'm already inheriting from `UserControl`, so I can't also inherit from `ISupportInitialize` can I? – bkribbs Aug 25 '15 at 18:08
  • Yes, its an interface, not a concrete class, you can inherit from multiple interfaces but only one concrete class, it would look like `public MyControl : UserControl, ISupportInitialize { ... }` – Ron Beyer Aug 25 '15 at 18:09
  • Ah, I should have known that. I was thrown off by you saying inherit, I didn't realize that also applied when using interfaces. I'll give that a shot. – bkribbs Aug 25 '15 at 18:11
  • I see where several other `UserControl`'s I've created call `BeginInit()` and `EndInit` but for some reason this one does not. I didn't manually delete them though I may have done something else that would have gotten rid of it. Any idea? – bkribbs Aug 25 '15 at 18:22
  • Make sure to delete the control, rebuild your project, and then add it to the form again, it won't work if you just change it without re-adding it. – Ron Beyer Aug 25 '15 at 18:28
  • Can we move to chat? http://chat.stackoverflow.com/rooms/87914/discussion-between-bkribbs-and-ron-beyer – bkribbs Aug 25 '15 at 18:38
  • I apologize, I can't, I'm working. – Ron Beyer Aug 25 '15 at 18:40
  • It's not clear to me why the ParentForm property can't be used in the ParentChanged event. I'm pretty sure that works. – LarsTech Aug 25 '15 at 18:42
  • I just verified that `this.Parent` is not `null` but `this.ParentForm` is. Not sure why that's the case. – bkribbs Aug 25 '15 at 18:46
  • You would have to show us that code that does that. – LarsTech Aug 25 '15 at 18:47
  • Sorry, I meant I verified in the `ParentChanged` event that `this.Parent` is not `null` but `this.ParentForm` is. My code for that is just checking if they are null or not and printing a line to indicate either way. – bkribbs Aug 25 '15 at 18:49
  • Again, you would have to show us the code that does that. – LarsTech Aug 25 '15 at 18:50
  • Done. Could creating the handle myself have anything to do with it? – bkribbs Aug 25 '15 at 18:55
  • I can't recreate your issue, but I wouldn't manually create the handle. I would probably prefer to start your background workers in that ParentChanged event, making sure 1) the ParentForm isn't null, and 2) the workers haven't been started yet. – LarsTech Aug 25 '15 at 19:00
  • I commented out the creating of the handle, as well as the starting of the workers. Nothing changed, I still got This.Parent having a value and This.ParentForm being null. – bkribbs Aug 25 '15 at 19:03
  • Having your Parent have a value but ParentForm be null is odd. I get values for both Parent and ParentForm. How are you creating this control? Obviously you aren't using the designer since it has a parameter in the constructor. – LarsTech Aug 25 '15 at 19:10
  • I believe it was created through the designer, I just added a parameter to the constructor. I added a new UserControl, called it MyConsole, stuck a RichTextBox on that control, then just went into the MyConsole class and did lots of editing there. – bkribbs Aug 25 '15 at 19:18
  • I meant, you aren't placing this UserControl on a Form using the designer — it would throw an exception without a parameterless constructor. So how is this UserControl getting placed on a form? Use the `@` sign in StackOverflow to signal a user in comments. – LarsTech Aug 25 '15 at 19:23
  • @LarsTech I thought you get a notification when you're the last comment. Sorry about that! Right- first I do `MyConsole console = new MyConsole("COM7")` then I have another form which has a tab control on it. I then generate a new tabpage and do `TabPage.Controls.Add(console);` and then I add that tabpage to the tabcontrol. Make sense? – bkribbs Aug 25 '15 at 20:24
  • Well, the bottom line is, the code you posted doesn't reproduce the problem. Try recreating the problem in a new project, and if it happens, post that code. – LarsTech Aug 26 '15 at 14:34

1 Answers1

0

Have you tried doing the cleanup inside the Dispose() method of the UserControl instead? It is usually a more logical place to do this, as a form closing will then dispose its children controls.

Unfortunately, the auto-generated user control template puts the Dispose() method in the associated .Designer.cs file. But you can move the method to your main file instead and modify it to perform the cleanup.

jgg99
  • 336
  • 1
  • 6