1

我有以下代码。

所以基本上它在引发事件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。一旦它们被 GCed,当View(that has selector) 和ViewModel(that issupping command) 从父 GUI 卸载时,匿名委托也将被取消挂钩。

我在这里吗?

4

2 回答 2

2

以下是此示例中的参考:

  • 看法:
    • 选择器
  • 视图模型:
    • 指令
  • 选择器:
    • 匿名代表
    • 指令
  • 匿名代表:
    • 选择器
    • 指令

这意味着视图和视图模型可以被垃圾收集,留下SelectorICommand活着。

垃圾收集器能够处理循环引用;所以即使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);
    }
}
于 2012-12-13T13:13:11.800 回答
0

匿名处理程序的生命周期严格取决于您的选择器对象,而不是外部变量,因此它会一直存在,直到您取消订阅或选择器对象被垃圾回收。所以这样就不会导致内存泄漏。

请注意,同一对象可能有多个订阅,因此您可能需要在某个时候取消订阅。

于 2012-12-13T13:12:31.873 回答