Wpf DataVirtualization - PullRequest
       1

Wpf DataVirtualization

2 голосов
/ 18 августа 2011

Я пытаюсь загрузить довольно большой список элементов в WPF DataGrid.Проблема в том, что это мучительно медленно.Прямо сейчас у меня есть около 20 000 элементов в моем списке, и это занимает вечность (ну ... в моей последней версии это занимает около 10 секунд, но этого недостаточно).Я работаю над этим последние пару дней, но я не могу найти решение, которое действительно работает.

1) Конечно, виртуализация пользовательского интерфейса включена (это больше не проблема)

2) Я также попробовал какое-то решение, описанное Bea Stollnitz здесь и другими.Эти решения хороши, но они не работают для меня, так как моя коллекция должна обновляться, фильтроваться и сортироваться во время выполнения без перезагрузки коллекции.Решения, которые я нашел, работают только с реализациями IList ... Мне нужна коллекция Observable, чтобы обновлять свои элементы.

Это ситуация: у меня есть коллекция Observable объектов данных моего домена (она обновляется через WCF асинхронно).У меня есть ViewModel для элементов списка, обертывающих объекты домена.Когда я открываю представление, у меня появляется второй список, который будет заполнен экземпляром ViewModel для каждого объекта домена.Это реальная проблема.Поскольку «целевая» коллекция привязана к моей DataGrid, я должен отправить создание ViewModels в поток пользовательского интерфейса (в противном случае .Net не очень рад изменению коллекции из другого потока).Поэтому я загрязняю очередь Dispatcher 20 000 вызовов создания модели представления.Создание ViewModel довольно дешево, но у меня все еще есть 20 000 вызовов в очереди диспетчера, и в то же время DataGrid требует ЦП в том же потоке, чтобы заполнить себя.

Моя идея (не совсем законченная): поскольку у меня уже есть виртуализация пользовательского интерфейса, я хотел бы создавать ViewModels НЕ когда я открываю свое представление, а на лету, тогда они мне нужны.Когда пользователь может сначала увидеть первые 20 записей, мне нужно создать только 20 ViewModels, а не 20 000.И вот моя проблема: я понятия не имею, как.Вот куда вы приходите:)

Мне бы хотелось, чтобы что-то вроде этого (не работало так ... просто чтобы показать, что я имею в виду):

<DataGrid ItemsSource={Binding MyDomainOjectCollection}>
    <DataGrid.RowStyle>
        <Style>
            <Setter Property="DataContext" 
                    Value="{Binding DataContext, 
                            Converter={StaticResource  MyViewModelFactoryConverter}}">
            </Setter>
        </Style>
    </DataGrid.RowStyle>
</DataGrid>

Это не обязательнобыть конвертером, это также может быть что-то еще или быть сделано в коде позади.Мне все равноВсе, что мне нужно: привязать напрямую к коллекции DomainObject, создать соответствующие ViewModel на лету и использовать только что созданную ViewModel вместо исходного объекта, чтобы заполнить одну строку.Есть идеи?

Ответы [ 2 ]

1 голос
/ 18 августа 2011

Проблема в том, что заполнение вашей ObservableCollection и обновление пользовательского интерфейса для каждого элемента является проблемой.

Вы должны использовать BindingList . Вы можете отключить события на нем, когда добавляете ряд элементов, например:

BindingList.RaiseListChangedEvents = false;

, который остановит интерфейс пользователя от получения каких-либо событий. Затем, после массового добавления, вы можете включить его с помощью:

BindingList.RaiseListChangedEvents = true;
BindingList.ResetBindings();
0 голосов
/ 18 августа 2011

Когда я открываю представление, у меня появляется второй список, который будет заполнен экземпляром ViewModel для каждого объекта домена.

Хорошо, это должна быть ваша отфильтрованная коллекция ObservableCollection.

Поскольку «целевая» коллекция привязана к моей DataGrid, я должен отправить создание ViewModels в поток пользовательского интерфейса

НЕТ, ВЫ НЕ ДЕЛАЕТЕ.ViewModel - это элемент не из пользовательского интерфейса, его можно создавать в любом потоке. Это добавление этих элементов к ObservableCollection, которое необходимо выполнить в потоке пользовательского интерфейса.Таким образом, вы можете создавать все обертки виртуальных машин где угодно, я предлагаю вам делать это партиями, а затем заполнять пакет в ObservableCollection одной операцией.Теперь я знаю, что ObservableCollection настроен на добавление только одного элемента за раз, но это легко исправить, добавив в него метод расширения, как показано в этом предыдущем SO-ответе .Обратите внимание, что вам нужно только вызвать метод расширения в потоке пользовательского интерфейса, как только вы сможете добавлять элементы по одному.

Лично я бы боролся как сумасшедший, чтобы не получать все данные все время,Я полагаю, вы уже проанализировали это требование и не можете его избежать.Но вам действительно нужно выполнять фильтрацию и сортировку на клиенте?Не может ли это быть достигнуто путем отправки данных на сервер, который затем отвечает соответствующими данными?

В любом случае, если вы должны получить все данные, то я предлагаю вам делать это в пакетном режиме (хотя 20 тыс. Предметов - это не так уж много, это все же разумно).Это можно сделать довольно легко, и с помощью уведомлений о свойствах в вашей модели представления вы можете поддерживать свою отфильтрованную коллекцию в актуальном состоянии с тем, что было добавлено в вашу исходную коллекцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...