Добавление большого количества элементов в WPF Datagrid потребляет много процессорного времени.

Я создаю приложение, которое имеет некоторые простые функции сниффера и которое показывает сброшенные пользователем пакеты. Пакеты считываются из файла дампа, который обновляется в режиме реального времени с текущим трафиком, а затем захваченные пакеты добавляются в Datagrid (каждый пакет — новая строка). Я использую привязку данных для получения пакетов из считывателя дампа, который реализует интерфейс ICollectionChanged, поэтому Datagrid информируется о каждом новом пакете. Datagrid использует виртуализацию и отложенную прокрутку. Почти все работает нормально, за исключением большого потребления процессора. Эта загрузка ЦП вызвана тем, что я читаю все новые пакеты (тысячи в секунду), форматирую их для отображения и для каждого пакета возникает событие CollectionChanged, которое обновляет Datagrid. Требование к программному обеспечению состоит в том, что пользователю не обязательно видеть все новые пакеты в режиме реального времени - их появляются десятки тысяч в секунду, так что никто их все не заметит. Пользователь может просматривать только некоторые пакеты, и когда он хочет, он может прокручивать полосу вниз / вверх до соответствующей позиции, чтобы увидеть нужные ему пакеты, и только в этом случае пакеты должны быть прочитаны из файла.

Проблема в том, что я хочу, чтобы Datagrid обновлялся каждую секунду, чтобы показать, что новые пакеты прибыли, предпочтительно путем масштабирования полосы прокрутки до фактического количества пакетов, но без необходимости их непрерывного чтения, форматирования и вызова CollectionChanged, потому что это требует процессорного времени, и, кроме того, пользователь не увидит новые пакеты, если он не прокручивает полосу. Мне сообщают количество прибывающих пакетов, поэтому я знаю количество всех пакетов.

Я попытался добавить поддельные пакеты (тем самым избегая чтения и форматирования каждого нового пакета) только для того, чтобы заставить Datagrid масштабироваться до фактического количества пакетов. Это почти сработало, потому что загрузка ЦП падает, а пакеты читаются только при прокрутке полосы. Но через мгновение, когда в Datagrid добавлялись новые пакеты, строки в текущем представлении начинали произвольно дублироваться, т.е. в первый момент пакет в представлении отображался 1-й, 2-й, 3-й, 4-й, 5-й, 6-й и так далее, но через некоторое время они отображались 1-м, 2-м, 3-м и снова 1-м, 2-м, 3-м.

Я также попытался обновить привязку - это сработало, но потребляло больше ресурсов, чем при первом подходе, поэтому я отказался от него. Я также попытался обновить список коллекции Datagrid - тот же эффект, что и при обновлении привязки.

Следующее, что когда я хотел добавить список пакетов за один вызов CollectionChanged

NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list));

Я получил сообщение об ошибке, что действия диапазона не поддерживаются, вызванные PresentationFramework.dll!System.Windows.Data.ListCollectionView.ValidateCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

Поэтому мне пришлось вызывать CollectionChanged для каждого пакета в списке пакетов, что также увеличивало нагрузку на ЦП.

Подводя итог, я хотел бы сообщить Datagrid, что есть новые пакеты/строки, поэтому полоса прокрутки Datagrid будет масштабироваться до общего количества пакетов, но пакеты будут считываться из файла только тогда, когда пользователь прокручивает полосу .

Я был бы очень благодарен за каждое предложение, как решить мою проблему.

Я только что понял, что есть одна важная вещь, которую нужно упомянуть, и извините, я забыл сказать об этом в начале. Моя ObservableCollection поддерживает какую-то виртуализацию данных, когда в памяти я держу лишь несколько необходимых пакетов. Когда приходят новые пакеты, я просто сообщаю своей коллекции о количестве новых пакетов, и мне не нужно вызывать метод Add для сбора, потому что я на самом деле не добавляю в нее никаких пакетов, поэтому никакие пакеты фактически не считываются< /сильный>. Коллекция содержит информацию об общем количестве пакетов в данный момент, и только небольшое их количество действительно хранится в памяти, чтобы сетка могла их отображать. Пакеты считываются на лету только при необходимости, а когда они не отображаются, они освобождаются. Но чтобы сообщить grid о новых пакетах, я должен (я не знаю, как это сделать по-другому, лучше) вызвать CollectionChanged и в аргументе этого вызова мне нужно подавать каждый новый пакет. И этот вызов CollectionChanged заставляет пакеты действительно читаться, что потребляет процессор. Я хочу перемасштабировать сетку, чтобы размер полосы прокрутки информировал о поступлении новых пакетов, но без необходимости чтения пакетов и вызова CollectionChanged по одному для каждого нового пакета (что может происходить тысячу раз в секунду). Я хочу, чтобы пакеты читались только при изменении положения полосы прокрутки, поэтому дорогостоящие операции обработки каждого пакета будут выполняться только для нескольких видимых в данный момент пакетов, а не для каждого пакета.


person wpf_beginner    schedule 28.11.2012    source источник


Ответы (1)


Если вы DataGrid привязаны к ObservableCollection. И каждый T содержит информацию о данном пакете, хитрость будет заключаться в том, чтобы сделать экземпляр класса «T» очень быстрым.

Прямо сейчас это звучит так, как будто вы создаете каждый T и вычисляете всю информацию, необходимую для отображения, когда добавляете их в коллекцию.

Он должен принимать в своем конструкторе только достаточно информации, чтобы он мог получить информацию о пакете позже, когда пользователь прокручивает сетку, чтобы просмотреть его строку.

person eoldre    schedule 28.11.2012
comment
Спасибо за ответ. Моя базовая коллекция получает данные только при прокрутке полосы прокрутки. Но проблема в том, что я хочу, чтобы размер полосы прокрутки отражал количество пакетов, поэтому я должен (может быть, и не должен, но я не знаю, как это сделать по-другому) читать и добавлять каждый новый пакет в Datagrid — а затем все вычисления случаться. Я хотел бы избежать этого. Я попытался добавить пустые пакеты в сетку (без каких-либо вычислений), единственной целью которой было зарезервировать место. Я сделал это, потому что фактическое чтение и отображение пакетов происходило после полосы прокрутки пользователем. Это почти сработало, но пакеты начали случайным образом перемещаться по сетке. - person wpf_beginner; 29.11.2012