Ben
Ben

Reputation: 31

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. The event handler requires an integer to be passed into it, like so:

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?

Upvotes: 0

Views: 115

Answers (3)

ASh
ASh

Reputation: 35679

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;

Upvotes: 1

canton7
canton7

Reputation: 42245

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.


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();
}

Upvotes: 2

Dan Scott
Dan Scott

Reputation: 564

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:

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

Upvotes: -1

Related Questions