我正在使用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/

10-14 17:18