Реализация ICollectionViewLiveShaping
Может ли кто-нибудь помочь мне правильно реализовать ICollectionViewLiveShaping
с целью фильтрации? Я не нашел много полезной документации в Интернете по этой проблеме. Вот что у меня есть:
public ICollectionView WorkersEmployed { get; set; }
WorkersEmployed = new CollectionViewSource { Source = GameContainer.Game.Workers }.View;
Я не использую GetDefaultView
, потому что мне нужно несколько экземпляров фильтров в этой коллекции. Если это имеет значение, GameContainer.Game.Workers
является ObservableCollection
.
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
. Лучший пример, который я мог найти, был этот, но, к сожалению, я все еще не мог заставить его работать. Учитывая то, что у меня здесь, может ли кто-нибудь дать мне толчок в правильном направлении, чтобы активировать фильтрацию в реальном времени?
Любая помощь будет принята с благодарностью.
Просто из любопытства, это действительно сложная задача? Если это так, кажется, люди, которые разработали ICollectionViewLiveShaping
, сделали довольно плохую работу.
Обновление: Похоже, что единственный способ добавить свойство в коллекцию ICollectionViewLiveShaping
LiveFilteringProperties
- через строку. Учитывая это ограничение, можно ли даже фильтровать свойства в другом классе (EmployerID EmployerID в этом случае)?
Может ли кто-нибудь, у кого есть опыт работы с ICollectionViewLiveShaping
, сказать, что то, что я пытаюсь сделать в этой ситуации, является даже жизнеспособным вариантом? Я честно не знаю, есть ли это или нет из-за полного отсутствия документации и доступных примеров. Даже если это не осуществимо, было бы, по крайней мере, полезно знать, трачу ли я свое время или нет.
Ответы
Ответ 1
Все, что вам нужно сделать, это 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;
}
Ответ 2
Я экспериментировал с этим, и похоже, что он не предназначен для того, что вам (и мне) нужно: автоматическая фильтрация при изменении условий фильтрации. Он автоматически фильтруется при изменении некоторых свойств источника элемента DataGrid, но не при изменении условий фильтра - вы должны вручную вызвать ICollectionViewSource.Refresh.
Ответ 3
Мы используем 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; }
И в вызове Initialise() после создания ViewModel (или, возможно, в конструкторе):
// 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; }
public ICollectionViewLiveShaping RowsLiveView { get; set; }
public ICollectionViewLiveShaping RowsLiveView { get; set; }
и непосредственно к RowsView
(сделайте его свойством с помощью { get; set; }
и используйте обычный ObservableCollection<>
. Другими словами - ICollectionViewLiveShaping отлично подходит для небольшого количества строк (например, <100), но для чего-то большего, ICollectionView
в сочетании с массовым обновлением и ручным Refresh()
лучше с точки зрения скорости.