当我第一次开始编写WPF自定义控件时,如果我想添加事件处理程序,我会在获得模板部件后,在控件的OnApplyTemplate重写中执行此操作:
public void override OnApplyTemplate() {
if ( addMenu != null ) {
addMenu.Click -= addMenu_Click;
addMenu = null;
}
addMenu = (MenuItem)Template.FindName("PART_AddMenu", this);
addMenu.Click += addMenu_Click;
}
但是有一天,我注意到OnApplyTemplate()并不总是在我期望的时候调用,即当控件与可视化树断开连接时。也就是说,使用上面的技术,事件处理程序不会总是被删除。所以我想出了一种不同的方法:
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;
}
}
这种方式似乎起到了作用。是否每个人都认为这是在自定义控件中挂接和删除事件处理程序的更好方法?如果没有,那是为什么?
发布于 2011-06-15 04:53:43
此方法很好,但您必须了解,在您可能不希望事件处理程序解除挂钩的情况下,您可能会获得未加载的事件。例如,假设您有一个选项卡控件。当您切换TabItems时,先前TabItem的所有内容都会被卸载,然后在TabItem再次被选中时重新加载。这对于像Button.Click这样的东西很好,因为您不能在非活动选项卡上执行这样的操作,但是任何不需要将项加载到可视化树中的事件都将断开连接,即使这些项仍然存在。
为什么你觉得你需要清理所有的事件处理程序?我意识到在某些情况下,它们可以挂起另一个对象的引用,但这是一个不寻常的情况,通常最好的处理方法是在以这种方式使用时清除它们。这里有一些更好的细节:How built-in WPF controls manage their event handlers to an attached event?
发布于 2019-06-11 03:23:16
WPF控件(如ComboBox)使用OnTemplateChangedInternal()
方法注销在OnApplyTemplate()
中注册的事件。您可以重写该方法,因为它是Control的内部方法,但是您也可以重写受保护的OnTemplateChanged()
方法来执行相同的操作-它由PresentationFramework基类中的OnTemplateChangedInternal()
调用。
下面是可以放入您的自定义控件的示例代码:
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);
}
我不确定这样做的所有含义,但它似乎是模拟WPF控件所做的最接近的方法。
https://stackoverflow.com/questions/6349695
复制相似问题