在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();
部分是否足以从内存中删除按钮和事件,或者我是否留下那些漂浮在那里的东西(如事件处理程序)?
与往常一样,我也欢迎提出改进上述代码的建议。
答案 0 :(得分:3)
简而言之,您不必担心这一点。
当您将事件处理程序附加到按钮时,事件处理程序不会保持按钮处于活动状态,该按钮会保留事件处理程序所引用的任何内容。事件处理程序正在引用您的窗口,因此基本上您无法从内存中清除窗口,直到按钮离开内存。因为按钮比窗口寿命更长是没有意义的,所以不会发生这种情况。
换句话说,您需要注意的情况是事件处理程序中使用的项目所需的生命周期比拥有该事件的类更短。
答案 1 :(得分: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();