Как вы обновляете сетку данных (или любой другой элемент управления UI) непрерывно, не замораживая UI? - PullRequest
7 голосов
/ 24 ноября 2011

В приложении WinForms у меня есть сетка данных, связанная с источником данных.Когда данные поступают через фоновый поток, набор данных необходимо обновить, что, в свою очередь, автоматически обновляет сетку данных.Теперь обновления могут быть в порядке, скажем, 7000 обновлений в 20 секунд.Проблема в том, что пользовательский интерфейс зависает, когда такое обновление происходит, потому что оно должно происходить в основном потокеЕсть ли известное решение этой проблемы?

Как вообще можно создавать высокопроизводительные корпоративные приложения в WinForms, где пользовательский интерфейс постоянно обновляется без зависания приложения?


ДобавлениеСценарий, чтобы объяснить это:

Рассмотрим этот сценарий.У вас есть древовидное представление, которое вы используете для представления некоторых иерархических данных.Теперь обновление данных на дереве асинхронно.Сервер может публиковать одно или 1000 обновлений одновременно.Обновление может быть модификацией существующего элемента или добавлением новых узлов.Следует отметить, что обновление не может быть отложено.Узлы где-то представляют сущность реального времени. Задержка обновления даст пользователю представление о том, что само событие было отложено. Так что это невозможно сделать.Если бы это было возможно (с точки зрения бизнес-логики), я бы сделал это очень давно.

Здесь есть ключевой момент: все данные не должны быть видны одновременно.

Чтобы люди больше этого не предлагали:

Добавление фонового рабочего потока НЕ ​​ПОМОЖЕТ, потому что поток должен переключиться на основной поток, чтобы выполнить обновление.Рабочий поток не будет иметь никакого значения.

Ответы [ 14 ]

0 голосов
/ 22 января 2012

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

В то же время вы должны использовать виртуализированные элементы управления (особенно сетку данных). Использование виртуальной сетки в основном означает, что видимые ячейки отображаются на лету. Следовательно, вам нужно только обновить данные, которые отображаются в данный момент. Когда каждая ячейка станет видимой, она получит доступ к модели данных, чтобы получить соответствующее значение в это время. См. эту ссылку в качестве отправной точки для реализации виртуальной сетки.

Комбинируя эти два подхода, вы сможете свести к минимуму количество обновлений в сетке.

0 голосов
/ 20 января 2012

Используйте backgroundWorker, он будет запускать вставленный код в отдельном потоке, чтобы приложение не зависало.

 public void backgroundWorkerPinger_DoWork(object sender, DoWorkEventArgs e)
        {

            Ping ping = new Ping();

                try
                {
                    PingReply pingreply = ping.Send("46.4.106.10", 500);
                    string active = pingreply.Status.ToString();
                    if (active == "Success")
                    {
                        //Pokud je spojení aktivni pak se nastavi barva labelu na zelenou a vypise se aktivni
                        ActiveOrNotLabel.ForeColor = Color.Green;
                        ActiveOrNotLabel.Text = "Aktivní";
                       // MessageBox.Show("vyjimka2");
                        if (connection_enabled == false)
                        {
                            admini.Enabled = true;
                            connection_enabled = true;
                        }
                    }
                    if (active != "Success") {
                        ActiveOrNotLabel.ForeColor = Color.Red;
                        ActiveOrNotLabel.Text = "Neaktivní";
                        admini.Enabled = false;
                        connection_enabled = false;

                     }
                }
                catch
                {
                    //Jinak na cervenou a neaktivni

                    //MessageBox.Show("vyjimka");
                    ActiveOrNotLabel.ForeColor = Color.Red;
                    ActiveOrNotLabel.Text = "Neaktivní";
                    admini.Enabled = false;
                    connection_enabled = false;

                }
            }
0 голосов
/ 20 января 2012

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

Я предлагаю вам продолжать использовать фонового работника для выполнения работы (как вы и говорили) и использовать метод ReportProgress для отправки% выполненного возврата на индикатор выполнения.Вы также можете обновить ярлык на странице с файлом, над которым вы работаете.Ярлык обновится автоматически и не замораживает ваш пользовательский интерфейс.Для этого создайте переменную экземпляра в классе, который вызывает ваш фоновый работник.В вашем пользовательском интерфейсе создайте экземпляр этого класса, а в методе ProgressChanged фонового работника установите для своей метки пользовательского интерфейса переменную экземпляра класса.Он будет обновляться каждый раз, когда вы вызываете backgroundworker.ReportProgress ()

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

0 голосов
/ 19 января 2012
Application.DoEvents();

Используйте этот метод внутри таймера.

private void timer1_Tick(object sender, EventArgs e)
{
     Application.DoEvents();
}

Вы должны запустить таймер там, где ваш пользовательский интерфейс зависает, или вы можете запустить его в form_Load и установить небольшое число на интервал вашего таймера, чтобы он часто срабатывал. Например, установите его на десять.

timer1.Start();
timer1.Interval = 10;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...