简体   繁体   English

如何取消订阅需要传入变量的 lambda 事件?

[英]How do I unsubscribe from a lambda event that needs variables passing into it?

I have a custom control in WPF (MenuButton) and want to add a click event handler to a list of them.我在 WPF (MenuButton) 中有一个自定义控件,并希望将单击事件处理程序添加到它们的列表中。 The event handler requires an integer to be passed into it, like so:事件处理程序需要将 integer 传递给它,如下所示:

List<MenuButton> mbButtons;

private void SetUpButtons()
{
    Random r = new Random();

    foreach (MenuButton item in mbButtons)
    {
        SubscribeToClickEvent(item, r.Next(0, 11));
    }
}

private void SubscribeToClickEvent(MenuButton mb, int i)
{
    mb.Click += (sender, e) => MyClickEvent(sender, e, i);
}

But how do I then unsubscribe from the event for each button?但是我如何取消订阅每个按钮的事件呢?

You need to store the delegate, and use it again to unsubscribe.您需要存储委托,并再次使用它来取消订阅。

private RoutedEventHandler handler;

private void SubscribeToClickEvent(MenuButton mb, int i)
{
    handler = (sender, e) => MyClickEvent(sender, e, i);
    mb.Click += handler;
}

private void UnsubscribeFromClickEvent(MenuButton mb)
{
    mb.Click -= handler;
    handler = null;
}

Of course, add your own logic to handle the case where SubscribeToClickEvent is called more than once.当然,添加您自己的逻辑来处理多次调用SubscribeToClickEvent的情况。


You edited your question to have an array of buttons, so here's an adjusted answer:您将问题编辑为具有一系列按钮,因此这是一个调整后的答案:

You will need to keep a list of delegate instances to remove:您需要保留要删除的委托实例列表:

private List<MenuButton> mbButtons;
private readonly List<(MenuButton button, RoutedEventHandler handler)> clickHandlers = new List<(MenuButton, RoutedEventHandler)>();

private void SetUpButtons()
{
    Random r = new Random();

    foreach (MenuButton item in mbButtons)
    {
        SubscribeToClickEvent(item, r.Next(0, 11));
    }
}

private void SubscribeToClickEvent(MenuButton mb, int i)
{
    RoutedEventHandler handler = (sender, e) => MyClickEvent(sender, e, i);
    clickHandlers.Add((mb, handler));
    mb.Click += handler;
}

private void UnsubscribeFromClickEvents()
{
    foreach (var (button, handler) in clickHandlers)
    {
        button.Click -= handler;
    }
    clickHandlers.Clear();
}

it makes more sense to keep relevant data in button instance, and retrive it in event handler:将相关数据保存在按钮实例中并在事件处理程序中检索它更有意义:

List<MenuButton> mbButtons;

private void SetUpButtons()
{
    Random r = new Random();

    foreach (MenuButton item in mbButtons)
    {
        item.Tag = r.Next(0, 11);
        item.Click += MyClickEvent;
    }
}

private void MyClickEvent(object sender, RoutedEventArgs e)
{
    var mb = (MenuButton)sender;
    int i = (int)mb.Tag;
}

then unsubscribe without any difficulties using known method name:然后使用已知方法名称毫无困难地取消订阅:

mb.Click -= MyClickEvent;

It's been a while since I worked with WPF but I'm pretty sure you can just have another method that does the opposite:自从我使用 WPF 以来已经有一段时间了,但我很确定您可以使用另一种相反的方法:

private void UnsubscribeToClickEvent(MenuButton mb, int i) 
{
    mb.Click -= (sender, e) => MyClickEvent(sender, e, i);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM