我有以下代码。
所以基本上它会在引发DelegateCommand
事件时执行基于弱引用委托的命令(Selector.SelectionChanged
。
public static readonly DependencyProperty SelectionCommandProperty
= DependencyProperty.RegisterAttached(
"SelectionCommand",
typeof(ICommand),
typeof(CommonUtilities),
new PropertyMetadata(null, OnSelectionCommandPropertyChanged));
private static void OnSelectionCommandPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = d as Selector;
var command = e.NewValue as ICommand;
if (selector != null && command != null)
{
selector.SelectionChanged
+= (o, args) => command.Execute(selector.SelectedItem);
}
}
public static ICommand GetSelectionCommand(DependencyObject d)
{
return d.GetValue(SelectionCommandProperty) as ICommand;
}
public static void SetSelectionCommand(DependencyObject d, ICommand value)
{
d.SetValue(SelectionCommandProperty, value);
}
请注意,上下文是静态的。
这会导致泄漏吗?我可以猜测它并不是因为据我所知,匿名处理程序将生效,直到所有“外部”变量(即selector
,command
此处)的范围不适用于GC。一旦他们进行了GC,当View
(具有selector
)和ViewModel
(即提供command
)从父GUI卸载时,匿名代表也会发生不被束缚。
我在这儿吗?
答案 0 :(得分:2)
以下是此示例中的参考资料:
这意味着可以对视图和视图模型进行垃圾回收,使Selector
和ICommand
保持活动状态。
垃圾收集器能够处理循环引用;因此即使Selector
引用了委托,并且委托引用了Selector
,这些仍然可以被垃圾收集。
只要这个匿名委托保持活动状态,ICommand
就会保持活动状态,这仅由Selector
实例的生命周期决定。只要Selector
被垃圾收集,委托和ICommand
最终也会被垃圾收集。
因此,在简单的情况下,不,您的代码不会导致泄漏。
然而,在某种情况下,您的代码会泄漏处理程序,我假设您的视图模型具有如下属性:
public ICommand OnSelectionChanged
{
get { return _onSelectionChanged; }
private set
{
_onSelectionChanged = value;
RaisePropertyChanged("OnSelectionChanged");
}
}
然后在视图中绑定,如果更改此OnSelectionChanged
命令的值,则附加属性将泄漏事件处理程序,因为您永远不会取消订阅执行旧命令的委托。
因此,不是只执行一个命令,而是执行此属性的所有先前值。
我会更喜欢以下实现:
private static void OnSelectionCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = d as Selector;
if (selector != null)
{
var oldCommand = e.OldValue as ICommand;
var newCommand = e.NewValue as ICommand;
if(oldCommand == null && newCommand != null)
{
selector.SelectionChanged += OnSelectionChanged;
}
else
{
selector.SelectionChanged -= OnSelectionChanged;
}
}
}
private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selector = (Selector)sender;
var command = GetSelectionCommand(selector);
if(command != null)
{
command.Execute(selector.SelectedItem);
}
}
答案 1 :(得分:0)
匿名处理程序的生命周期严格依赖于您的选择器对象,而不是外部变量,因此它将一直存在,直到您取消订阅或者选择器对象被垃圾收集。所以这样就不会导致内存泄漏。
请注意,相同对象可能有多个订阅,因此您可能需要在某些时候取消订阅。