Реализация 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
"s LiveFilteringProperties
Коллекция через строку. Учитывая это ограничение, возможно ли вообще фильтровать по свойствам в другом классе (в этом случае EmployerID EmployerID)?
Может ли кто-нибудь, кто имеет опыт работы с ICollectionViewLiveShaping
скажите, если то, что я пытаюсь сделать в этой ситуации, является даже жизнеспособным вариантом? Честно говоря, я не знаю, так ли это из-за полного отсутствия документации и примеров. Даже если это неосуществимо, по крайней мере, было бы хорошо узнать, трачу ли я свое время или нет.
2 ответа
Все, что вам нужно сделать, это 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;
}
Мы используем 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; }
и прямо в RowsView
(сделайте это свойство с { get; set; }
, и используйте обычный ObservableCollection<>
. Другими словами - ICollectionViewLiveShaping отлично подходит для небольшого количества строк (например, <100), но для чего-то большего,ICollectionView
в сочетании с массовым обновлением и руководством Refresh()
лучше с точки зрения скорости.
Я экспериментировал с этим, и похоже, что он не предназначен для того, что вы (и я) хотите: Автоматическая фильтрация при изменении условий фильтрации. Он фильтруется автоматически при изменении некоторых свойств источника элемента DataGrid, но не при изменении условий фильтра - необходимо вручную вызвать ICollectionViewSource.Refresh.