2

ハイパーリンク コントロールを使用してレンダリングする必要があるクラスにプロパティがあるとします。ハイパーリンクは、クリックすると何らかのアクションがトリガーされるように、ビュー モデルのコマンドにバインドされます。このようなもの:

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

データ項目がグリッドから削除されたときに、ICommand の実装である dataGrid.DataContext.Command[GetSolutionSummaryCmd] と、ハイパーリンク列を持つ各データ レコードとの間のバインディングが破棄され、データ項目がガベージ コレクションされるようにするにはどうすればよいですか? そうしないと、ここでメモリ リークが発生する可能性があります。

また、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 
}

これとは対照的に、CanExecuteChanged を発生させることができる必要があります。

4

1 に答える 1

2

ここでの提案を使用して、この問題の解決策を実装しました。リークは、上記のスタイルで使用されているハイパーリンク要素によって引き起こされていたことは間違いありません。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 のインスタンス数が増えていないことを示しています。

于 2013-01-09T12:09:22.940 に答える