2

在 WPF 中,我创建了一个为我动态创建按钮的控件。在某些情况下,按钮可能会更改并且需要重新创建。我目前正在使用以下内容:

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

我想知道WrapPanel_Main.Children.Clear();我的代码部分是否足以从内存中删除按钮和事件,或者我是否让东西(如事件处理程序)漂浮在那里?

与往常一样,我也愿意接受有关改进上面显示的代码的建议。

4

2 回答 2

3

简而言之,您无需担心这一点。

当您将事件处理程序附加到该事件处理程序未使按钮保持活动状态的按钮时,该按钮将使事件处理程序引用的任何内容保持活动状态。事件处理程序正在引用您的窗口,因此在按钮离开内存之前,您基本上无法从内存中清除窗口。由于按钮的寿命比窗口长并没有任何意义,因此不会发生这种情况。

换句话说,您需要注意的情况是事件处理程序中使用的项目的寿命需要比拥有该事件的类短。

于 2013-01-10T21:05:40.463 回答
0

正如@Servy 提到的,它可能不需要分离这些处理程序,但如果你真的想要我能想到的唯一方法是使用Reflection.

这是一个基于您的问题的小示例(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)
        {
            // :(
        }
    }
}

用法:

RemoveButtonClickHandlers(WrapPanel_Main.Children);
WrapPanel_Main.Children.Clear();
于 2013-01-10T21:17:02.027 回答