wpf、typedescriptorを見るときにハンドラーを適切に外す方法
-
30-09-2019 - |
質問
私はWPFを使用しており、MVVMパターンに従っています。私たちのチームは、XCeed Datagridコントロールを使用することを決定しましたが、MVVMパターンに適合させるのに苦労しています。
私が満たさなければならない要件の1つは、ユーザーがグリッド上の列フィルターをいつ変更するかを知る必要があることです。 Datagridコントロールの最新バージョンには、このために提起されるイベントがあることを知っていますが、残念ながら、古いバージョンのコントロールを使用する必要があります。
しばらく検索した後、私は見つけました これ 役職。 InotifyCollectionChanged Handlerを、可能なフィルターの各リストにフックする必要があると述べています。これは機能しますが、グリッドの行ソースが変更されるたびにハンドラーを外す必要があるとも言います。
ページのCodeBehindで行のソースを明示的に設定したときに機能させることができました(そして、ビューへの直接参照を使用してモデルビューでの最初の試みで あえぎ!)
しかし、私が遭遇した最初の問題は、コードの背後や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メソッドが呼び出されるまでに、自動ろ過のコレクションがすでに変更されているため、ハンドラーを効果的に外すことはできません。
私はこれを仮定するのに正しいですか?そして、誰もがこれらのハンドラーを管理するより良い方法を考えると、拡張クラス内でその機能をカプセル化することを可能にしますか?
投稿の長さについて申し訳ありませんが、助けてくれてありがとう!
- ファンガー
解決
その時点でオートフィルターバリューがすでに変更されていることは正しいので、間違ったハンドラーを見て、メモリリークが発生します。
ソリューションは非常に簡単です。あなたがしていることを正確に行いますが、使用してください List<IList>
AutoFilterValuesを参照するだけでなく、
private List<IList> _GridFilters;
そして使用します ToList()
フィルターのコピーを作成するには、ハンドラーを設定します。
_GridFilters = dataGridCollectionView.AutoFilterValues.Values.ToList();
_gridfiltersは現在aです List<IList>
, 、ループも変更する必要があります。
foreach(IList autofilterValues in _GridFilters)
...
これが機能する理由は、古いフィルターリストの実際のリストが、AutoFilterValuesプロパティを単に参照するのではなく、_gridFiltersにコピーされるためです。
これは、多くの状況で適用可能な素晴らしい一般的な手法です。