При частом обновлении контрола окна приложения, окно тормозит. Как избавится?
Есть приложение WPF состоящее из одного окна, в котором есть DataGrid. В классе окна приложения есть метод, который обновляет содержимое DataGrid. Обновления происходят часто, до нескольких раз в секунду. Так как окно приложения и его контролы работает в одном потоке, то наблюдаются тормоза. Окно плохо, откликается, плохо перетаскивается по рабочему столу и так далее ... Почему это происходит - понятно. Не понятно как от этого избавится. Что можно с этим сделать?
Спасибо.
Я делал примерно так:
BindingList (или ObservalCollection) хранит коллекцию того, что нужно показывать в DataGrid. Она один раз привязывается при запуске формы к ItemsSource.
Процедура обновления получает обновлённый список и сравнивает его с тем, который отображается в DataGrid. Там три варианта - удалилось, добавилось, обновилось. Все три части аккуратно и несложно описываются. Меняется именно ваша коллекция. Автоматически у неё срабатывают события изменения, и изменения сразу отображаются в DataGrid, так как он умеет правильно работать и с BindingList и с ObservalCollection.
честно говоря не понял. Есть коллекция
public BindingList quote_list = new BindingList();
в конструкторе окна приложения я ее связываю с DataGrid:
DataGrid.ItemsSource = quote_list;
Есть метод, который занимается обновлением данных. Специфика такова, что новую порцию данных нужно целиком записать в DataGrid вместо того, что в нем уже есть, без каких-либо проверок. Поэтому в методе обновляющем DataGrid делаю просто:
quote_list.Clear(); //очищаю колекцию
quote_list.Add(new QuoteItem(){...}) //Заполняю новыми данными
Вроде бы как вы написали. Но тормоза жесткие. Когда приложение запускаю, то в очереди куча новых данных для грида, до 1000 сообщений. И пока грид их все не вытащит из очереди окно приложения вообще не откликается. Потом частота обновлений уже конечно ниже и приложение уже отзывается, но с тормозами.
Если у вас данные обновляются частично, то лучше всё же обновлять, а не переписывать.
Если же хочется всё переписать и все данные несколько раз в секунду меняются, то можно попробовать вручную реализовать IBindingList. В таком случае вы можете реализовать добавление списка без генерации лишних событий ListChanged, и только в конце вызвать событие ListChanged с параметром Reset.
скорее всего неправильно построена архитектура приложения, в частности вам скорее всего не нужен грид совсем или в нем не должно быть столько данных и частого обновления.
А что можно было бы использовать вместо DataGrid в моем случае, как вы считаете? По сути нужна таблица в которой некоторые строки можно было бы выделять цветом, а текст жирным.
Игорь: начнем с того, что выводить 1000 строк даже, если часть из них будет выделяться бессмысленно, человек не сможет так быстро просмотреть весь список, как быстро вы его обновляете. Есть подозрение, что ваш список это чтото вроде записей лога с подсветкой определенных событий, в таком случае под обновлением видимо подразумевается добавление новых строк, в таком случае неплохо справляется listbox с кастомной раскраской. Если же это не так, то вероятно выводить нужно лишь то, что действительно важно.
Я не говорил, что в таблице 1000 строк. 1000 сообщений в очереди, которые ожидают вывода - это да. В самой таблице не больше 20 строчек. Мой список это стакан торгового привода. Попробую следуя вашему совету обновлять только изменившиеся данные. Так сразу не стал делать, потому что данных меняется много за раз и поэтому я решил обновлять целиком. Я не проводил исследования, но думаю что за раз меняется в большая часть данных в таблице.
Игорь: в таком случае решение зависит от того что вы понимаете под "меняется", если скажем есть N параметров из которых K меняют свое значение это одно, а если есть N параметров, K удаляются и M добавляются, отличных от N то это другое. В первом случае я бы пошел иначе: на форме разместил flowlayout , создал key-value список List> при получении новых данных первым делом проверял есть ли в списке элемент с параметром key, если нет создавал бы новый label и ложил его в новый KeyValuePair под индексом key , этот KeyValuePair добавлял бы в общий список и label от него добавил бы в flowlayout.controls, при обновлении достаточно было бы найти нужный label и изменить его значение. Так получится что каждая строка будет обновляться лишь тогда когда это нужно