Search code examples
wpfcustom-controls

Removing event handlers from custom control's template parts


When I first started writing WPF custom controls, if I wanted to add an event handler, I would do so in the control's OnApplyTemplate override, after getting the template part:

public void override OnApplyTemplate() {
  if ( addMenu != null ) {
    addMenu.Click -= addMenu_Click;
    addMenu = null;
  }
  addMenu = (MenuItem)Template.FindName("PART_AddMenu", this); 
  addMenu.Click += addMenu_Click;
}

But then one day I noticed that OnApplyTemplate() is not always called when I'd expect it to be, i.e. when the control is disconnected from the visual tree. That is, using the above technique, the event handlers won't always be removed. So I came up with a different way:

public MyCustomControl()
{
  Loaded += this_Loaded;
}

void this_Loaded(object sender, RoutedEventArgs e)
{
  Unloaded += this_Unloaded;

  addMenu = (MenuItem)Template.FindName("PART_AddMenu", this);
  addMenu.Click += addMenu_Click;
}

void this_Unloaded(object sender, RoutedEventArgs e)
{
  Unloaded -= this_Unloaded;

  if (addMenu != null)
  {
    addMenu.Click -= addMenu_Click;
    addMenu = null;
  }
}

This way seems to do the trick. Does everyone concur that this is the better way of hooking up and removing event handlers in a custom control? If not, then why?


Solution

  • This method is fine, but you do have to understand that you get the unloaded event at times that you might not want the event handlers unhooked. For example, let's say you have a tab control. When you switch TabItems the content of the previous TabItem all gets Unloaded and then reloaded when the TabItem becomes selected again. This is fine for things like Button.Click because you can't perform such actions on an inactive tab, but any events that don't require the item to be loaded into the visual tree will be disconnected even though the items still exist.

    Why do you feel you need to clean up all event handlers? I realize that there are some cases where they can hang onto a reference of another object, but this is an unusual case and is usually best handled by cleaning them up when used in that way. Here's some better details on this: How built-in WPF controls manage their event handlers to an attached event?