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