Изменить элементы управления из MainThread (нужно подтверждение теории от профессионалов) - PullRequest
1 голос
/ 04 октября 2010

У меня есть winform с формой под названием MainForm.У меня есть статический класс под названием ObjMgr.В ObjMg у меня есть несколько других статических классов, значений, но сейчас это не важно.

В классе ObjMgr у меня также есть метод static void Pulse (), который я заполняю своими другими статическими классами в ObjMgr,Этот импульсный метод приходится запускать очень часто, например, 0,033 с.

В MainForm я поместил кнопку запуска, которая при событии щелчка начинает пульсировать мой ObjMgr в другом потоке.

Pulser = new System.Threading.Thread(new System.Threading.ThreadStart(ObjMgr.StartPulsing));
Pulser.IsBackground = true;
Pulser.Start();

Мой метод ObjMgr.StartPulsing источник:

        while(true)
        {
            ObjMgr.Pulse();
            System.Threading.Thread.Sleep(30);
        }

Мой метод Pulser источник:

        //here I update all my data in ObjMgr
        // Its need to be fast, I have some while, and switch statements here.
        // complicated code here :D The main thing is, its populating my classes with data.

Теперь у меня запущен пульсатор, и я постоянно обновляю данные своего статического класса.Это очень приятно.Следующим шагом я хотел бы показать некоторые данные в моей форме (UI) из обновленных классов ObjMgr.В моей форме около 20 ярлыков, 2 значения ProgressBar, которые я хочу часто обновлять, например, Pulsator.(0,033сек)

Было бы очевидно обновить мои метки, начиная с самого метода Pulsator, но я боюсь, что это замедлит мой Pulsator, и я не хочу этого .Итак, Мне нужно несколько советов, как это сделать .Я думал, и я установил таймер, что я установил интервал в 30, а затем при тиковом событии я прочитал свои данные из ObjMgr и показал изменение меток.Это работает хорошо, но немного глючит, потому что некоторые проблемы с синхронизацией. Если вы понимаете мою проблему, не могли бы вы дать мне какой-нибудь отзыв или советы, как сделать это лучше?

ЕСЛИ я бы попытался обновить свои метки из самого метода Pulse ()Это замедлит мой метод Pulse ()?Если нет, то как я могу обновить 20 ярлыков в MainForm из другого потока?

Ответы [ 2 ]

3 голосов
/ 04 октября 2010

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

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

У этого подхода есть несколько преимуществ.

  • Пользовательский интерфейс и рабочие потоки остаются слабосвязанными, в отличие от подхода Control.Invoke или Control.BeginInvoke, который тесно связывает их.
  • Поток пользовательского интерфейса не будет препятствовать выполнению рабочего потока.
  • Рабочий поток не может доминировать во время, которое поток пользовательского интерфейса тратит на обновление.
  • Интервалы, с которыми пользовательский интерфейс и рабочие потоки выполняют операции, могут оставаться независимыми.
  • Рабочий поток не может переполнить насос сообщений потока пользовательского интерфейса.

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

1 голос
/ 04 октября 2010

Если бы я попытался обновить свои метки из самого метода Pulse (), это замедлило бы мой метод Pulse ()?

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

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

Таким образом, лучший способ - использовать Control.BeginInvoke (), вы отправляете обновление, но не ждете его завершения.Лучше сделайте копии данных (строк), которые вы хотите использовать, потому что теперь ваше обновление будет параллельно с вашим Pulse.

// pseudo code
void Pulse()
{
    // your DTO, a simple string[] or a special object
    var data = new string[] { x1.text, x2.Text } ;
    MainForm.BeginInvoke(Updater, new object[] { data }); 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...