微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从自定义控件的模板部分中删除事件处理程序

如何解决从自定义控件的模板部分中删除事件处理程序

| 当我第一次开始编写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;
  }
}
这种方法似乎可以解决问题。是否所有人都同意这是在自定义控件中挂接和删除事件处理程序的更好方法?如果没有,那为什么呢?     

解决方法

        此方法很好,但是您必须了解,有时您可能不希望事件处理程序被释放,但您会获得卸载事件。例如,假设您有一个选项卡控件。当您切换TabItems时,先前的TabItem的内容全部被卸载,然后在再次选择TabItem时重新加载。这对Button.Click之类的东西很好,因为您不能在非活动选项卡上执行此类操作,但是即使该项目仍然存在,所有不需要该项目加载到可视化树中的事件都将被断开连接。 为什么感觉需要清理所有事件处理程序?我意识到在某些情况下它们可以挂在另一个对象的引用上,但这是一种不寻常的情况,通常最好通过以这种方式使用它们进行清理来处理。这里有一些更好的细节:内置的WPF控件如何管理它们对附加事件的事件处理程序?     ,        WPF控件(例如ComboBox)使用
OnTemplateChangedInternal()
方法注销在
OnApplyTemplate()
中注册的事件。您可以重写该方法,因为它位于PresentationFramework dll的内部,但是您可以重写受保护的
OnTemplateChanged()
方法以执行相同的操作-在Control基类中由
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控件功能的最接近方法。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。