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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With