How is ICollectionViewLiveShaping
implemented for the purpose of filtering? Is it something like:
public ICollectionView WorkersEmployed { get; set;
We are using WPF + MVVM + Visual Studio 2017.
We want to convert this to add live filtering:
public ObservableCollection Rows { get; set; }
The method below has two key advantages:
Please let me know if this worked for you, any issues and I'll update the instructions to make easier.
And the steps:
Create a special ObservableCollection that does not fire update events. This is a one-off. We want to fire the update bulk update event ourselves, which is faster.
public class NonNotifyingObservableCollection : ObservableCollection
{
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { /* Do nothing */ }
}
Convert to a private variable which uses this new collection.
private NonNotifyingObservableCollection rows;
// ... and in constructor
rows = new NonNotifyingObservableCollection();
Add these variables:
private ICollectionView rowsView;
public ICollectionViewLiveShaping RowsLiveView { get; set; }
And in the Initialise() call after the ViewModel is constructed (or perhaps in the constructor):
// 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");
});
Now we add items to the backing collection, then call .Refresh()
to refresh the view:
this.rowsView.Add(new RowViewModel( /* Set properties here. */ ));
We then bind the grid to RowsLiveView
, (instead of binding to Rows
in the original code).
Now we can update the IsVisible
property, then call .Refresh()
to redraw the grid.
rows[0].IsVisible=false;
this.rowsView.Refresh(); // Hides the first row.
Update: This answer could be simplified. The whole point of ICollectionViewLiveShaping
is to autorefresh without the need to call .Refresh()
. Given that we have a NonNotifyingObservableCollection
and we are manually controlling everything with a .Refresh()
, could remove public ICollectionViewLiveShaping RowsLiveView { get; set; }
and, directly to RowsView
(make it a property with { get; set; }
, and use normal ObservableCollection<>
. In other words - ICollectionViewLiveShaping is great for a small amount of rows (e.g. <100), but for anything more, ICollectionView
in combination with a bulk update and a manual Refresh()
is better from a speed point of view.