2

In WPF I have created a control that dynamically creates buttons for me. On some occasions the buttons may change and need be recreated. I am currently using the following:

public void GenerateButtons()
{
    WrapPanel_Main.Children.Clear();

    foreach (ActivatedItem thisItem in Controller.ItemList.Where(sl => sl.IsTypeCompatible(typeof(ActivatedItem))))
    {
        Button newButton = new Button() { Content = thisItem, ToolTip = thisItem.Desc, Width = 50, Height = 25 };
        newButton.Click += new System.Windows.RoutedEventHandler(this.DynamicButtonClick);
        WrapPanel_Main.Children.Add(newButton);
    }
}

I am wondering if the WrapPanel_Main.Children.Clear(); section of my code is enough to remove the buttons and the events from memory or if I am leaving stuff (like the event handlers) floating around out there?

As always I am open to suggestions on bettering the code shown above as well.

Anthony Nichols
  • 1,532
  • 1
  • 21
  • 44
  • Anthony have you tried adding / testing the `WrapPanel_Main.Children.Clear();`? if so what results did it yield..? – MethodMan Jan 10 '13 at 20:25
  • The `WrapPanel_Main.Children.Clear();` code removed the buttons from the WrapPanel, but I am not sure if they are being stored somewhere else and if it removes the even handlers and I don't know how to test for that. I don't know what 'magic' goes on behind the scenes for Event Handlers. – Anthony Nichols Jan 10 '13 at 20:39
  • can you do a foreach loop to check for Controls..? just curious.. – MethodMan Jan 10 '13 at 20:40

2 Answers2

3

In short, you don't need to worry about this.

When you attach an event handler to the button that event handler isn't keeping the button alive, the button is keeping whatever is referenced by the event handler alive. The event handler is referencing your window, so essentially you can't clear the window from memory until the button leaves memory. Since it doesn't really make sense for the button to live longer than the window this won't happen.

In other words, the situation you need to watch out for is where the items used in the event handler need to have a shorter life than the class that owns the event.

Servy
  • 193,745
  • 23
  • 295
  • 406
  • Thanks -- just what I was looking for; I followed all of that except the last line... But maybe I will understand that if I ever have a need to do something like that. – Anthony Nichols Jan 10 '13 at 21:18
  • @Servy thank you for the information , is that also relevant to winforms? – jonathana Dec 03 '17 at 14:53
  • @jonathana This is describing the behavior of events in general; none of this is specific to any framework. – Servy Dec 04 '17 at 14:14
0

As @Servy mentioned its probably not a needed to detach these handlers, but if you really want to the only way I could think to do this is with Reflection.

Here is a small example based on your question (Button click event for buttons in WrapPanel)

public void RemoveButtonClickHandlers(UIElementCollection elements)
{
    foreach (var button in elements.OfType<Button>())
    {
        try
        {
            var handlers = typeof(UIElement).GetProperty("EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(button, null);
            if (handlers != null)
            {
                var clickEvents = (RoutedEventHandlerInfo[])handlers.GetType()
                .GetMethod("GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                .Invoke(handlers, new object[] { ButtonBase.ClickEvent });
                foreach (var clickEvent in clickEvents)
                {
                    button.Click -= (RoutedEventHandler)clickEvent.Handler;
                }
            }
        }
        catch (Exception ex)
        {
            // :(
        }
    }
}

Usage:

RemoveButtonClickHandlers(WrapPanel_Main.Children);
WrapPanel_Main.Children.Clear();
sa_ddam213
  • 39,994
  • 7
  • 93
  • 106