Home Contact

X

Coder, not artist.

News

Current archive is at: http://cskardon.wordpress.com/ - I aim to move it all soon! All code on here is free, but as a consequence it's up to you to check it, ha! If you have any questions, feel free to email: cskardon -- @ -- xclave dot co dot uk I'm sure you can decrypt the address there!

Twitter












Archives

Post Categories

Image Galleries

Syndication:

Dispose of a WPF UserControl (ish)

I've been playing with WPF a little bit, and quite frankly got a bit stuck, (Meh! Who'd have thought).
The problem is as follows:

I create a UserControl - we'll call it 'MyUserControl' (wouldn't want to break traditions now would we). In said user control I have a button, that when pressed will fire off a new thread. This new thread will (say) poll a file / service - whatever - every 10 seconds or so, and update a Label accordingly. When I close the app, if the app is polling, then the app won't actually die, basically because the thread that is doing the polling doesn't know to stop.

So, we have our polling code:

   1:    public void PollService()
   2:    {
   3:      while(Polling)
   4:      {
   5:        string result = Service.Poll();
   6:        UpdateLabel(_lblResults, result);
   7:      }
   8:    }

 
with UpdateLabel defined thusly:

   1:    private void delegate UpdateLabelDelegate(Label label, string text);
   2:    private void UpdateLabel(Label label, string text)
   3:    {
   4:      if(!Dispatcher.CheckAccess())
   5:      {
   6:        Dispatcher.Invoke(DispatcherPriority.Send, new UpdateLabelDelegate(UpdateLabel), label, text);
   7:        return;
   8:      }
   9:     
  10:      label.Content = text;
  11:    }


We also have a property: Polling, which is used to control wether the control is polling the service or not:

   1:    public bool Polling {
   2:      get { return _polling; }
   3:      set
   4:      {
   5:        _polling = value;
   6:        if(_polling)
   7:          new Thread(PollService).Start();
   8:      }
   9:    }


As you can see, when Polling = true; is called, a new Thread is spun off to do the polling. So, in theory (and in practice actually), if we have a Window with a 'MyUserControl' instance on it (called _myUC), we can call:

  _myUC.Polling = true;


to start polling, or

  _myUC.Polling = false;


to end polling.

Now, this is great, if I shut down the window when Polling == false, the app will shut down fine. If Polling == true though, well, that's a different kettle of fish altogether, the thread keeps running in the background leaving the app running (albeit in a hidden stylee). Now, normally, in a WinForms app, I would simply implement IDisposable and do something like:

   1:    public void Dispose()
   2:    {
   3:      Polling = false;
   4:    }


Then I'd know my control would bog off as I want it to.
"So implement already!" - I hear you say. Wish I could, but WPF doesn't use IDisposable, sooooo what to do?

Right, what's next on my hit list? Closed? Closing? OnClosing? OnClosed? Gah! None there!!
In fact none of the events on the control are of any use. The only one that sounded plausible was 'Unloaded' which (I incorrectly) presumed would be raised when the Window closed. No such luck!

Googling for terms such as: "WPF Dispose Control", "WPF Dispose UserControl", "Why the F**k can't I dispose", "WPF IDisposable" all come up with nothing of any use (aside from the fact that WPF doesn't support IDisposable). Erm, right, time to take the battle to the IDE...

 this.
 
   [ Scroll up ]
   [ Scroll down ]
   [ Hover tentatively over Dispatcher ]
  
hmmmm... well, why not...
 
this.Disp [CTRL+ENTER]
 System.Windows.Threading.Dispatcher
 
 Argh NO! Damn you intellisense!!!
 
  [ CTRL+Backspace ] x lots
 
 D i s p a t c h e r .
 
 Thats better...
 
   [ Scroll down ]
  
What's this??? 'ShutDownStarted' an event about shutting down? Ok, it's for the Dispatcher to shut down, but when the Window is closed, well, that's what is gonna happen... right? May as well try it, it's not gonna hurt after all... So, into the constructor we get:

   1:    public MyUserControl()
   2:    {
   3:      /* init code */
   4:      Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
   5:    }

 
which in turn (via the *wonders* of intellisense) generates:

   private void Dispatcher_ShutdownStarted( object sender, EventArgs e )
   {
   }

Can it be? I put my faithful:
Polling = false;
code in, cross my fingers, and F5 that bad boy....

Compiled (good start)
Running (good going)
Start polling (Poll going)
Close app (.......)

App closed.
Holy fig rolls batman! The thread has been stopped! Setting a breakpoint on the Polling = false; line does indeed show it getting hit when the form is shut... So the next time the erroneous thread runs, it realises Polling does in fact == false, and stops.

Conclusions

To be honest, this is a bit, well, sh!t, and I'm convinced there are better ways of achieving this goal. However, having said that, I've had no joy in google or numerous forums. Hopefully someone can point out the errors of my ways (and yes, I imagine that seperating the polling logic into another non-wpf class would do it - but I wanted to see if I could do it this way!!).

Feedback

# re: Dispose of a WPF UserControl (ish)

Hi,

I was wanting to execute some code when my control was either disposed of or when the main application window was shutdown by the user. I was stifled at every turn until I saw this post. Thanks a lot for your attention to detail here!

Dan, MCP, MCTS 1/19/2009 8:00 PM | Daniel Kemper

# re: Dispose of a WPF UserControl (ish)

I'm glad it helped! Thank you for the comment! 1/20/2009 8:25 AM | Chris

# re: Dispose of a WPF UserControl (ish)

You are awesome man, god knows how much I looked for such thing. Thanks alot. 3/9/2009 6:58 PM | Faraz

# re: Dispose of a WPF UserControl (ish)

Great, thanks. 6/30/2009 2:56 AM | Erich

# re: Dispose of a WPF UserControl (ish)

Thanks a lot!

I had just the same problem and by reading almost one day many forums I found the same question many times but not a proper solution. Then I found this...
7/2/2009 5:21 AM | Jouko

# re: Dispose of a WPF UserControl (ish)

Hey,

The easier solution is to declare your thread differently. By default, a new Thread is created with IsBackground = false. That means that the thread will keep the application alive if it's still running.

If you create and start the thread like this instead then you'll hopefully find that it aborts when the app shuts down:

if(_polling)
{
Thread t = new Thread(PollService);
t.IsBackground = true;
t.Start();
}

Hope that's of use!

Dan. 7/28/2009 5:47 AM | Dan Puzey

# re: Dispose of a WPF UserControl (ish)

Hi Dan,

That is of use! :)

I guess part of me still wants to have the ability to Dispose though. I'd like to end my thread when I want to, i.e. clear resources etc.

From what it looks like the Background thread is just terminated, and as a consequence, if I was in the middle of writing something to a file (for example) presumably there is a risk of invalid files etc...

For my example given though - IsBackground would have solved a lot of ache :)

Thanks!

Chris 7/28/2009 6:10 AM | Chris

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: