سؤال

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.

هل كانت مفيدة؟

المحلول

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.

نصائح أخرى

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();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top