【问题标题】:wpf ICommand binding in data grid records causing memory leak数据网格记录中的 wpf ICommand 绑定导致内存泄漏
【发布时间】:2012-12-21 17:37:54
【问题描述】:

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

<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。

【问题讨论】:

  • 那么是内存泄漏还是你认为会有内存泄漏?
  • 确实有泄漏。使用 ANT 探查器,我看到这些超链接对象没有被 GC 回收。

标签: wpf data-binding memory-leaks


【解决方案1】:

我使用了here 的建议来解决这个问题。泄漏肯定是由上述样式中使用的超链接元素引起的。 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 的实例数没有增加。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-17
    • 2014-10-20
    • 2011-01-26
    • 2019-12-18
    • 1970-01-01
    • 2013-10-30
    • 2023-01-25
    相关资源
    最近更新 更多