ItemsControl.ItemsSource Производительность MVVM

У меня есть (не виртуализированный) ItemsControl, который связывает свой ItemsSource с ObeservableCollection экземпляров ViewModel. Теперь, когда загружено большое количество экземпляров модели, все компоненты ViewModel необходимо добавить в эту коллекцию ObservableCollection. Как я могу добавить большое количество ViewModels без зависания потока пользовательского интерфейса?

Я предполагаю, что поток пользовательского интерфейса зависает, потому что каждый раз, когда добавляется новый элемент, ItemsControl должен обновляться и делать макет и т. Д. Снова и снова.

  • Следует ли приостановить привязку, добавить все элементы, а затем возобновить? Если да, то как?
  • Должен ли я переопределить ObservableCollection для реализации AddRange, чтобы для добавления нескольких элементов запускалось только одно событие CollectionChanged? Или как вариант просто заменить всю коллекцию?
  • Или лучше добавить каждый элемент отдельно и вызывать Dispatcher.Invoke для каждого элемента отдельно? Так что я бы часто разблокировал.

Как вы обрабатываете большие динамические списки, которые нельзя виртуализировать?


person bitbonk    schedule 17.03.2010    source источник
comment
Что ты используешь? WPF / Silverlight? WinForms? Что-то другое?   -  person slugster    schedule 17.03.2010
comment
Должно быть очевидно, что это не формы Windows, потому что ни один из упомянутых классов не существует в формах Windows.   -  person bitbonk    schedule 17.03.2010
comment
есть ли какая-то конкретная причина, по которой ваш itemscontrol не может использовать виртуализацию пользовательского интерфейса?   -  person Joachim Kerschbaumer    schedule 10.05.2011


Ответы (2)


Вы можете создать класс, производный от ObservableCollection, который позволяет временно приостановить CollectionChanged такие события:

public class SuspendableObservableCollection : ObservableCollection
{
    private bool suspended;

    public bool Suspended 
    {
        get
        {
            return this.suspended;
        }
        set
        {
            this.suspended = value;
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(
                NotifyCollectionChangedAction.Reset));
        }
    }

    protected override void OnCollectionChanged(
        NotifyCollectionChangedEventArgs args)
    {
       if (!Suspended)
       {
           base.OnCollectionChanged(args);
       }
    }
}
person Wim Coenen    schedule 17.03.2010
comment
Мой вопрос больше о том, как я могу улучшить производительность, а не о том, как реализовать такую ​​коллекцию. Также, если я временно приостанавливаю такие события, как вы, предполагаете, что ItemsControl будет отображать неправильное состояние после возобновления приостановки. И если затем возникает новое событие CollectionChanged, оно все равно будет отображать неправильное состояние, потому что оно не получило всех изменений, которые были внесены в коллекцию, пока она была приостановлена. - person bitbonk; 17.03.2010
comment
1) Разве реализация такой коллекции не позволяет повысить производительность? 2) Я добавил событие сброса, чтобы исправить описанную вами проблему. - person Wim Coenen; 17.03.2010
comment
Похоже, это не улучшает производительность. Вероятно, потому что tze ItemsControl необходимо генерировать сразу много элементов управления элементами. Поэтому я думаю, что лучшим подходом было бы добавить некоторые элементы по отдельности, используя (Begin) Invoke несколько раз. - person bitbonk; 17.03.2010

person    schedule
comment
Вы, наверное, имели в виду <Binding IsAsync="True"/>. Сам ItemsControl не имеет этого свойства. Это свойство следует использовать с осторожностью: не должно быть много сценариев, в которых необходимо использовать свойство IsAsync. Руководства .NET не рекомендуют определять свойства, которые на порядок медленнее, чем набор полей. - person bitbonk; 07.10.2010
comment
ах, я думал, что у каждого селектора есть свойство IsAsync. Когда вы загружаете окно, которое загружает много данных не асинхронно, вы получаете черное окно или оно зависает (как это было в моем случае с использованием IsAsync = True сейчас). Поэтому рекомендуется использовать IsAsync! - person Elisabeth; 07.10.2010
comment
Если вы предлагаете сделать <ItemsControl ItemsSource="{Binding IsAsync="True" .../>, это не поможет. IsAsnyc работает только тогда, когда сам источник данных недоступен сразу или требует времени. В моем случае DataSource доступен сразу, но содержит много элементов. Подробнее о проблеме читайте здесь: goo.gl/BwA1 - person bitbonk; 07.10.2010