Существуют различные способы решения этой проблемы.
Первое, что нужно определить - это «в реальном времени». Если ваши данные изменяются каждую 1 миллисекунду, даже если вы смогли обновить интерфейс так быстро, никто не сможет его увидеть. В качестве ориентира мы можем обнаруживать изменения только на частоте около 60 Гц (поэтому видеоигры ориентированы на эту частоту кадров). На практике вы, вероятно, хотите, чтобы пользовательский интерфейс обновлялся в диапазоне 10–50 Гц.
Решение с таймером
Простое решение, которое может или не может быть целесообразным, заключается в настройке таймера. в потоке пользовательского интерфейса, который запускается с соответствующей скоростью и обновляет элементы управления в обработчике событий таймера.
Решение Invoke () / BeginInvoke ()
Еще один вариант - по-прежнему использовать BeginInvoke ( ), но:
Реализовать logi c для обновления всех элементов управления в одной функции и только BeginInvoke () этой, так что вы ставите в очередь только один рабочий элемент в пользовательском интерфейсе нить. Если бы вы делали BeginInvoke () для каждого элемента управления, вы бы вызвали переключение контекста для каждого элемента управления.
Пропустить вызов BeginInvoke (), если минимальное время не истекло с момента последнее обновление Например, если данные изменились через 3 миллисекунды, вы можете пропустить все обновления, пока они не произойдут через 50 миллисекунд (что даст максимальную частоту обновления 20 Гц).
Осложнения
Это будет хорошо работать, если у вас есть простые элементы управления, однако вы можете столкнуться с проблемами, если у вас есть сложные, такие как графики, множество элементов управления для обновления. В этом случае их перерисовка может занять много времени, поэтому вы не сможете обновить пользовательский интерфейс с нужной скоростью. Если вы слишком часто используете BeginInvoke () и поток пользовательского интерфейса не может поддерживать работу, приложение по существу зависнет, потому что у него нет времени для обработки пользовательского ввода.
Могут быть другие условия, которые приводят к поток должен быть более загруженным, чем обычно (изменение размера окна или другой обработки, которая занимает максимум пару секунд, и вы не удосужились запустить в отдельном потоке).
Итак, в моих программах я обычно устанавливаю флаг непосредственно перед вызовом BeginInvoke (), и я очищаю его в вызываемой функции. В следующий раз, когда мне нужно вызвать BeginInvoke (), я сначала проверяю флаг. Если он все еще установлен, это означает, что поток пользовательского интерфейса был занят и все еще не смог обновить пользовательский интерфейс. В этом случае я пропускаю BeginInvoke ().
Наконец, если у вас много чего происходит (мне пришлось обновить много графиков и представлений), вам также может потребоваться гарантия logi c минимальное время с , когда код обновления в потоке пользовательского интерфейса завершает выполнение и , когда вы ставите в очередь новое обновление из фонового потока . Это гарантирует, что в потоке пользовательского интерфейса остается некоторое время для обработки пользовательского ввода, в то время как поток очень занят обновлением пользовательского интерфейса в остальное время.
Заключительные примечания
Если значение не имеет изменилось, вы хотите избежать перерисовки относительного контроля, потому что это бессмысленно. Я ожидаю, что большинство элементов управления WinForms, таких как метка, уже не будут перерисовываться, если вы установите для их текста то же значение, которое у них уже есть, но если у вас есть пользовательские элементы управления, сторонние элементы управления или такие вещи, как очистка ListView и повторное его заполнение, вы хочу убедиться, что код не вызывает перерисовку, когда он не нужен.