我正在使用WPF,并尝试遵循MVVM模式。我们的团队已决定使用Xceed DataGrid控件,但要使其适应MVVM模式,我遇到了一些困难。
我必须满足的一项要求是,我需要知道用户何时更改网格上的列过滤器。我知道DataGrid控件的最新版本为此引发了一个事件,但是不幸的是,我必须使用该控件的旧版本。
搜索了一段时间后,我发现了this帖子。它说我需要将一个INotifyCollectionChanged处理程序挂接到每个可能的过滤器列表。这行得通,但同时也说,只要网格的行源发生更改,我就需要取消处理程序的钩子(Hook)。
当我在页面的代码隐藏位置中显式设置行源时,(在我第一次尝试使用对 View 抽气的直接引用的ModelView中,)我能够使它起作用。
不过,我遇到的第一个问题是如何做到这一点,而又无需在代码中包含ViewModel或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的集合已经更改,因此我不能有效地解钩处理程序。我猜对了吗?谁能想到一种更好的方法来管理这些处理程序,同时又允许我将该功能封装在扩展类中?
抱歉,帖子的长度太长了,在此先感谢您的帮助!
-真菌
最佳答案
您是正确的,此时AutoFilterValues已经更改,因此您将取消钩接错误的处理程序,从而导致内存泄漏。
解决方案非常简单。完全按照自己的方式进行操作,但要使用List<IList>
而不是仅引用AutoFilterValues:
private List<IList> _GridFilters;
并使用
ToList()
复制您在其上设置处理程序的过滤器的副本:_GridFilters = dataGridCollectionView.AutoFilterValues.Values.ToList();
由于_GridFilters现在是
List<IList>
,因此您还必须更改循环:foreach(IList autofilterValues in _GridFilters)
...
这样做的原因是将旧过滤器列表的实际列表复制到_GridFilters中,而不是简单地引用AutoFilterValues属性。
这是一种很好的通用技术,适用于许多情况。
关于wpf - WPF,如何在观看TypeDescriptor时正确地解钩处理程序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4138399/