1

WPFを使用していて、MVVMパターンに従おうとしています。私たちのチームはXceedDataGridコントロールを使用することを決定しましたが、MVVMパターンに適合させるのにいくつかの問題があります。

私が満たさなければならない1つの要件は、ユーザーがグリッド上の列フィルターをいつ変更するかを知る必要があることです。DataGridコントロールの最新バージョンには、このために発生するイベントがあることを認識していますが、残念ながら、古いバージョンのコントロールを使用する必要があります。

しばらく検索したところ、この投稿を見つけました。INotifyCollectionChangedハンドラーをフィルターの可能なリストのそれぞれにフックする必要があることを示しています。これは機能しますが、グリッドの行ソースが変更されるたびにハンドラーのフックを解除する必要があることも示しています。

ページの背後にあるコードで行ソースを明示的に設定すると(そして、ビューのあえぎへの直接参照を使用してModelViewで最初に試みたときに)、それを機能させることができました。

しかし、私が遭遇する最初の問題は、コードビハインドまたはViewModelにロジックを持たずにこれを行う方法です。私の解決策は、DataGridControlクラスを拡張し、次のコードを追加することでした。

    private IDictionary<string, IList> _GridFilters = null;
    public MyDataGridControl() : base()
    {
        TypeDescriptor.GetProperties(typeof(MyDataGridControl))["ItemsSource"].AddValueChanged(this, new EventHandler(ItemsSourceChanged));
    }

    void ItemsSourceChanged(object sender, EventArgs e)
    {
        UnsetGridFilterChangedEvent();
        SetGridFilterChangedEvent();
    }

    public void SetGridFilterChangedEvent()
    {
        if (this.ItemsSource == null)
            return;

        DataGridCollectionView dataGridCollectionView = (DataGridCollectionView)this.ItemsSource;

        _GridFilters = dataGridCollectionView.AutoFilterValues;

        foreach (IList autofilterValues in _GridFilters.Values)
        {
            ((INotifyCollectionChanged)autofilterValues).CollectionChanged += FilterChanged;
        }
    }

    /*TODO: Possible memory leak*/
    public void UnsetGridFilterChangedEvent()
    {
        if (_GridFilters == null)
            return;

        foreach (IList autofilterValues in _GridFilters.Values)
        {
            INotifyCollectionChanged notifyCollectionChanged = autofilterValues as INotifyCollectionChanged;

            notifyCollectionChanged.CollectionChanged -= FilterChanged;
        }

        _GridFilters = null;
    }

これは私の次の問題につながります。ItemsSourceChangedメソッドが呼び出されるまでに、AutoFilterValuesのコレクションが既に変更されていると確信しているため、ハンドラーのフックを効果的に解除することはできません。

私はこれを想定するのは正しいですか?そして、拡張クラス内にその機能をカプセル化したままにして、これらのハンドラーを管理するためのより良い方法を誰かが考えることができますか?

投稿の長さについて申し訳ありませんが、助けてくれてありがとう!

-ファンガー

4

1 に答える 1

0

AutoFilterValuesはその時点ですでに変更されているので、間違ったハンドラーのフックを解除し、メモリリークが発生するのは正しいことです。

解決策はとても簡単です。実行していることを正確に実行しますが、List<IList>AutoFilterValuesを参照するだけでなく使用します。

private List<IList> _GridFilters;

ToList()ハンドラーを設定したフィルターのコピーを作成するために使用します。

_GridFilters = dataGridCollectionView.AutoFilterValues.Values.ToList();

_GridFiltersがになってList<IList>いるため、ループも変更する必要があります。

foreach(IList autofilterValues in _GridFilters) 
  ...

これが機能する理由は、単にAutoFilterValuesプロパティを参照するのではなく、古いフィルターリストの実際のリストが_GridFiltersにコピーされるためです。

これは、多くの状況に適用できる優れた一般的な手法です。

于 2010-11-09T23:46:39.507 に答える