Реализация 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() лучше с точки зрения скорости.