wpf ICommand绑定数据网格记录导致内存泄漏

时间:2013-01-07 22:35:35

标签: wpf data-binding memory-leaks

假设我在一个需要使用超链接控件呈现的类上有一个属性。超链接将绑定到视图模型上的命令,以便单击它可触发某些操作。像这样:

<Style x:Key="HyperlinkStyle" TargetType="{x:Type igDP:CellValuePresenter}">
   <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type igDP:CellValuePresenter}">
                    <Border BorderBrush="{StaticResource DataGridCellOuterBorder}" BorderThickness="1,0,0,0"  >
                        <TextBlock Margin="5">
                                <Hyperlink                                      
                                    Command="{Binding ElementName=dataGrid, Path=DataContext.Commands[GetSolutionSummaryCmd], Mode=OneTime}"
                                    CommandParameter="{Binding Path=(igDP:DataRecord.DataItem), Mode=OneTime}">
                                    <TextBlock Text="{TemplateBinding Value}"/>                                                                      
                                </Hyperlink>                                                                                
                            </TextBlock>
                    </Border>                 
                </ControlTemplate>
            </Setter.Value>
        </Setter>       
    </Style>

如何确保从网格中删除数据项时,dataGrid.DataContext.Command [GetSolutionSummaryCmd],ICommand的实现和带有超链接列的每个数据记录之间的绑定被破坏,因此数据项可以是垃圾收集?否则,我发现这里存在泄漏内存的可能性。

此外,GetSolutionSummaryCmd是RelayCommand的实例,如下所示:

public class RelayCommand  : ICommand
{
    readonly protected Predicate<object> _canExecute;
    readonly protected Action<object> _execute;

    public RelayCommand(Predicate<object> canExecute, Action<object> execute)
        : this(canExecute, execute, true)
    {
    }

    public RelayCommand(Predicate<object> canExecute, Action<object> execute, bool isCommandAllowed)
    {
        _canExecute = canExecute;
        _execute = execute;
        IsAllowed = isCommandAllowed;
    }

    public void RaiseCanExecuteChanged()
    {
        if (this.CanExecuteChanged != null)
            this.CanExecuteChanged(this, EventArgs.Empty);
    }

    #region ICommand Members

    public virtual bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged;

    public virtual void Execute(object parameter)
    {
        _execute(parameter);
    }    

    #endregion 
}

this相反,我需要能够引发CanExecuteChanged。

1 个答案:

答案 0 :(得分:2)

我使用了here建议来实现此问题的解决方案。泄漏肯定是由上述Style中使用的超链接元素引起的。 ANTS探查器在内存快照之间为System.Windows.EffectiveValueEntry []指示了一个正实例计数。当我查看此类的对象引用图时,始终会引用链中的超链接实例。

更改了基础数据,以便在单击时始终可以执行超链接。这意味着不必引发ICommand的CanExecuteChanged事件,允许我像这样定义某种NoReferenceRelayCommand类:

    public class NoReferenceRelayCommand : ICommand
    {
        protected readonly Action<object> _execute;

        public NoReferenceRelayCommand(Action<object> execute)
        {
            Guard.ThrowIfArgumentIsNull(execute);
            _execute = execute;
        }

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

        #endregion
    }

超过10小时的性能分析解决方案显示System.Windows.EffectiveValueEntry的实例编号不会增加。