Реализация 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.

Другие вопросы по тегам