从控件中注销类处理程序 - WPF

4

我已在WPF的文本框上注册了GotFocusEvent事件处理程序。

EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(TextBox_GotFocus));

现在,有没有一种方法可以从文本框中删除已注册的处理程序?
更新: 我查看了以下链接 WPF自定义路由事件-如何取消订阅? 然而,它对我没有帮助,因为提到的控件是自定义控件,而在我的情况下,它是默认的TextBox控件。
我无法在我的情况下找到RemoveHandler。有什么建议吗?

可能是WPF自定义路由事件 - 如何取消订阅?的重复问题。 - Sinatr
@Nicholas,我在TextBox中没有找到RemoveHandler。有什么建议吗? - Gopichandar
您无法注销 ClassHandler - Novitchi S
дҪ дҪҝз”Ё EventManager.RegisterClassHandler жңүе…·дҪ“зҡ„еҺҹеӣ еҗ—пјҹдёәд»Җд№ҲдёҚдҪҝз”Ё UIElement.RegisterHandler е‘ўпјҹжӯЈеҰӮ @Novitchi жӯЈзЎ®жҢҮеҮәзҡ„йӮЈж ·пјҢжӮЁж— жі•еҸ–ж¶ҲжіЁеҶҢзұ»еӨ„зҗҶзЁӢеәҸгҖӮ - feO2x
我知道可以使用 bool 来查找,但我正在寻找最优解决方案。 - Gopichandar
显示剩余2条评论
3个回答

2

正如您在评论中所述,类处理程序无法注销。我对您的建议是:在处理程序开头添加一个if语句,检查实际方法体是否应执行。代码如下:

private void MyTextBoxClassHandler (object sender, RoutedEventArgs e)
{
    if (CheckIfHandlerShouldExecute() == false)
        return;

    // The actual code that should be executed in the handler resides here.
}

这并不会阻止调用处理程序,但如果某个条件不满足,则不会执行您的逻辑。


我已经在我的问题评论中提到过这一点。这可能是一个解决方法,但不是答案。 - Gopichandar
1
答案是,如评论中所述,没有API可以注销类处理程序。解决此问题的唯一方法是不使用类处理程序,而是使用其他机制,例如通过样式在所有文本框上设置的附加属性。当提供某个值时,此附加属性会向文本框注册和注销自身(您可以在此处了解更多信息:http://briannoyes.net/2012/12/20/attached-behaviors-vs-attached-properties-vs-blend-behaviors/)。 - feO2x
3
请为自己和人类做个好事(无恶意),写下 if (!ShouldHandlerExecute()) return; - EricG
1
@EricG 我通常不喜欢使用 ! 运算符,因为我认为在阅读源代码时很容易被忽略 - == false 不容易被忽略。 - feO2x

1

无法注销类处理程序,但您可以在静态类中管理事件,在那里注册类处理程序一次并根据需要添加/删除实例处理程序。您可以公开普通的EventHandlers或使用响应式扩展来实现:

public static class GlobalEvents
{
    static readonly ClassHandlerSubject s_TextBoxGotFocus = new ClassHandlerSubject(typeof(TextBox), UIElement.GotFocusEvent);
    public static IObservable<RoutedEventArgs> TextBoxGotFocus => s_TextBoxGotFocus.Events;

    class ClassHandlerSubject
    {
        readonly Lazy<Subject<RoutedEventArgs>> m_Subject;
        public IObservable<RoutedEventArgs> Events => m_Subject.Value;

        public ClassHandlerSubject(Type classType, RoutedEvent routedEvent) =>
            m_Subject = new Lazy<Subject<RoutedEventArgs>>(() =>
            {
                EventManager.RegisterClassHandler(classType, routedEvent, new RoutedEventHandler(OnEventReceived));
                return new Subject<RoutedEventArgs>();
            });

        private void OnEventReceived(object sender, RoutedEventArgs e) => m_Subject.Value.OnNext(e);
    }
}

使用方法如下:
//subscribe
var subscription = GlobalEvents.TextBoxGotFocus.Subscribe(TextBox_GotFocus);
//... receive events
//remove my subscription
subscription.Dispose();

0

如果你只有一个类的实例需要订阅事件。 与@Alex类似,我会在类内部调用静态事件。在构造函数中,我会获取一个实例引用,然后用于我的事件。

public partical class MyWindow : Window
{
    public static MyWindow Current { get; private set; }

    public MyWindow() : base()
    {
        InitializeComponent();
        Current = this;
    }

    static MyWindow()
    {
        EventManager.RegisterClassHandler(typeof(MyWindow),
                System.Windows.Input.Keyboard.KeyUpEvent,
                new System.Windows.Input.KeyEventHandler(AllKeyUp_static), true);
    }

    private static void AllKeyUp_static(object sender, System.Windows.Input.KeyEventArgs e)
    {
        Current?.AllKeyUp_instance(sender, e);
    }

    private void AllKeyUp_instance(object sender, System.Windows.Input.KeyEventArgs e)
    {
         // HANDLE EVENT
    }
}

这将做两件事情。首先,它可以防止之前的类实例变得无法回收用于垃圾处理。其次,它会自动分配当前实例以利用该事件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接