WPF - removing a control that has a DispatcherTimer doesn't seem to go away
I've seen the question asked on StackOverflow on how to properly remove controls in WPF. Generally there is some comment how you don't dispose them manually(or can't) and as long as you are not holding a reference to them they will be cleared eventually by the GC. I noticed quite by accident that one of my controls that I thought I removed was sticking around and still doing work even though I removed it from its parent.
I've recreated the example in as few lines as possible. The control has a DispatcherTimer. Here is the WPF code behind for the 开发者_如何转开发control I want to remove.
public partial class MyControl : UserControl
{
private DispatcherTimer timer;
public MyControl()
{
InitializeComponent();
timer = new DispatcherTimer();
timer.Tick += TimerOnTick;
timer.Interval = TimeSpan.FromSeconds(1);
timer.Start();
}
private void TimerOnTick(object sender, EventArgs args)
{
//this continues to get written out even after this control is removed.
System.Diagnostics.Debug.WriteLine("Tick From MyControl.");
}
}
Here is the code behind for a window that adds and removes my control.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void AddClicked(object sender, RoutedEventArgs e)
{
anyControlHolder.Children.Add(new MyControl());
}
private void RemoveClicked(object sender, RoutedEventArgs e)
{
anyControlHolder.Children.Clear();
}
}
The problem I'm having when I run this code and then dynamically add and remove the custom usercontrol (MyControl) is that it's timer keeps ticking (in this example you can see it write out a message in the output window) and it keeps doing work in its tick event. What pattern should I use to at least cause the timer to stop ticking when the control is removed?
You can hook into your control's Unloaded event and call timer.Stop()
inside. I just tested this scenario, and the Unloaded event is raised when anyControlHolder.Children.Clear()
was called, thus stopping the debug messages.
Code:
public partial class MyControl : UserControl {
private DispatcherTimer timer;
public MyControl() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(MyControl_Loaded);
this.Unloaded += new RoutedEventHandler(MyControl_Unloaded);
}
void MyControl_Loaded(object sender, RoutedEventArgs e) {
timer = new DispatcherTimer();
timer.Tick += TimerOnTick;
timer.Interval = TimeSpan.FromSeconds(1);
timer.Start();
}
void MyControl_Unloaded(object sender, RoutedEventArgs e) {
timer.Stop();
}
private void TimerOnTick(object sender, EventArgs args) {
Debug.WriteLine("Tick From MyControl.");
}
}
Hope this helps!
The other thing I would would be to remove the event handler that you added for your tick event. Any thing that you manually add you should remove.
As far as implementing a WeakEventPattern you may want to look at this article
精彩评论