实现ICollectionViewLiveShaping

时间:2013-07-25 17:47:43

标签: c# icollectionview

为了过滤,有人可以帮我正确实施ICollectionViewLiveShaping吗?关于这个问题,我没有在网上找到很多有用的文档。这就是我所拥有的:

public ICollectionView WorkersEmployed { get; set; }

WorkersEmployed = new CollectionViewSource { Source = GameContainer.Game.Workers }.View;

我没有使用GetDefaultView,因为我需要在此集合上有多个过滤器实例。如果重要,GameContainer.Game.WorkersObservableCollection

ApplyFilter(WorkersEmployed);

private void ApplyFilter(ICollectionView collectionView)
{
    collectionView.Filter = IsWorkerEmployed;
}

public bool IsWorkerEmployed(object item)
{
    Worker w = item as Worker;
    return w.EmployerID == this.ID;
}

这一切都有效,但当然必须手动刷新,这就是我尝试使用ICollectionViewLiveShaping的原因。我能找到的最好的例子是this,但不幸的是我还是无法让它发挥作用。鉴于我在这里有什么,任何人都可以给我一个正确的方向,让实时过滤工作?

非常感谢任何帮助。

出于好奇,这真的是一项艰巨的任务吗?如果是这样,设计ICollectionViewLiveShaping的人似乎做得很糟糕。

更新:似乎向ICollectionViewLiveShaping的{​​{1}}集合添加属性的唯一方法是通过字符串。鉴于这种限制,是否可以按另一个类中的属性进行过滤(在本例中为Workers'EmployerID)?

任何对LiveFilteringProperties有任何经验的人都可以告诉我,在这种情况下我想做什么甚至是一个可行的选择吗?老实说我不知道​​是不是因为缺乏文档和可用的例子。即使这是不可行的,也至少知道我是否在浪费时间。

3 个答案:

答案 0 :(得分:11)

您需要做的只是add a property LiveFilteringProperties,您希望过滤器在属性更改时调用,并为集合IsLiveFiltering设置true to enable live filtering }}

确保在PropertyChanged属性发生变化时引发EmployerID事件,即Worker类应实现INotifyPropertyChangedEvent

这将起作用 -

public ICollectionViewLiveShaping WorkersEmployed { get; set; }

ICollectionView workersCV = new CollectionViewSource
                         { Source = GameContainer.Game.Workers }.View;

ApplyFilter(workersCV);

WorkersEmployed = workersCV as ICollectionViewLiveShaping;
if (WorkersEmployed.CanChangeLiveFiltering)
{
    WorkersEmployed.LiveFilteringProperties.Add("EmployerID");
    WorkersEmployed.IsLiveFiltering = true;
}

答案 1 :(得分:1)

我们正在使用WPF + MVVM + Visual Studio 2017。

我们想将其转换为添加实时过滤:

public ObservableCollection<RowViewModel> Rows { get; set; }

以下方法具有两个主要优点:

  • 它旨在与WPF运行时有效配合,以使用批量更新将屏幕渲染减至最少。
  • 所以很快。
  • 并且由于下面列出了样板代码,因此与您在网络上找到的任何其他文档相比,它更易于遵循。

如果有任何问题,请告诉我,是否适合您,我将更新说明以简化操作。

步骤:

第1步:不通知集合包装器

创建一个不会触发更新事件的特殊ObservableCollection。这是一次性的。我们想自己触发更新批量更新事件,这更快。

public class NonNotifyingObservableCollection<T> : ObservableCollection<T>
{
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { /* Do nothing */ }
}

步骤2:转换为NonNotifyingObservableCollection

转换为使用此新集合的私有变量。

private NonNotifyingObservableCollection<RowViewModel> rows;
// ... and in constructor
rows = new NonNotifyingObservableCollection<RowViewModel>();

第3步:添加包装器

添加以下变量:

private ICollectionView rowsView;
public ICollectionViewLiveShaping RowsLiveView { get; set; }

并且在构造ViewModel之后(或者可能在构造函数中)在Initialise()调用中:

// Call on the dispatcher.
dispatcher.InvokeAsync(() =>
{
    this.rowsView = CollectionViewSource.GetDefaultView(this.rows);
    this.rowsView.Filter = o =>
        {
            // This condition must be true for the row to be visible on the grid.
            return ((RowViewModel)o).IsVisible == true;
        };
    this.RowsLiveView = (ICollectionViewLiveShaping)this.rowsView;
    this.RowsLiveView.IsLiveFiltering = true;
    // For completeness. Changing these properties fires a change notification (although
    // we bypass this and manually call a bulk update using Refresh() for speed).
    this.RowsLiveView.LiveFilteringProperties.Add("IsVisible");
});

第4步:添加项目

现在,我们将项目添加到支持集合中,然后调用.Refresh()刷新视图:

this.rowsView.Add(new RowViewModel( /* Set properties here. */ ));

然后,将网格绑定到RowsLiveView(而不是原始代码中绑定到Rows)。

第5步:更新实时过滤

现在,我们可以更新IsVisible属性,然后调用.Refresh()重新绘制网格。

rows[0].IsVisible=false;
this.rowsView.Refresh(); // Hides the first row.

更新

更新:此答案可以简化。 ICollectionViewLiveShaping的全部要点是自动刷新,而无需调用.Refresh()。假设我们有一个NonNotifyingObservableCollection,并且我们正在使用.Refresh()手动控制所有内容,则可以删除public ICollectionViewLiveShaping RowsLiveView { get; set; }并直接删除到RowsView(使用{{1}使其成为属性},并使用常规的{ get; set; }。换句话说,ICollectionViewLiveShaping非常适合少量的行(例如<100),但是对于ObservableCollection<>而言,它还可以与批量更新和手动{从速度的角度来看,{1}}更好。

答案 2 :(得分:0)

我对此进行了实验,看起来它不适合您(和我)想要的东西:更改过滤条件时自动过滤。它会在DataGrid项目源的某些属性发生更改时自动过滤,但在过滤条件发生变化时则不会自动过滤 - 您必须手动调用ICollectionViewSource.Refresh。