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 O开发者_如何学CnApplyTemplate() 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?
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?
WPF controls (such as ComboBox) uses the OnTemplateChangedInternal()
method to unregister events that are registered in OnApplyTemplate()
. You can't override that method, as it's internal to the PresentationFramework dll, but you can override the protected OnTemplateChanged()
method to do the same - it's called by OnTemplateChangedInternal()
in the Control base class.
Here's sample code that could go into your custom control:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
EditableTextBoxSite = GetTemplateChild("PART_EditableTextBox") as TextBox;
EditableTextBoxSite.TextChanged += new TextChangedEventHandler(this.OnEditableTextBoxTextChanged);
this.EditableTextBoxSite.PreviewTextInput -= new TextCompositionEventHandler(this.OnEditableTextBoxPreviewTextInput);
}
protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
{
base.OnTemplateChanged(oldTemplate, newTemplate);
if (this.EditableTextBoxSite == null)
return;
this.EditableTextBoxSite.TextChanged -= new TextChangedEventHandler(this.OnEditableTextBoxTextChanged);
this.EditableTextBoxSite.PreviewTextInput -= new TextCompositionEventHandler(this.OnEditableTextBoxPreviewTextInput);
}
I'm not sure about all the implications of doing this, but it does seem to be the closest way to emulate what WPF controls do.
精彩评论