2013-07-11 7 views
1

В приложении Visual C#/.Net мне нужно прочитать SerialPort, и поэтому я назначил ему DataReceivedEventHandler.Альтернатива использованию Control.Invoke

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

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

Какое из следующего следует делать?

  • Вариант А: Палка с Invoke в любом случае, и выполнять каждое из действий по каждому из различных элементов управления с использованием Invoke для каждого из них.

  • Вариант B: Положите 50ms повторяющегося таймера, где каждый 50мс, я проверяю, если булево DataReceived == истинного, и если да, обновить пользовательский интерфейс управление соответствующим образом. (с DataReceived установлено значение true каждый раз, когда я читаю данные в Serial Port DataReceivedEventHandler, а в противном случае - false.)

  • Опция C: Любая другая опция?

UPDATE:

Успех со следующим (на основе Ответ @ tcarvin и комментарии @Hans Passant в).

private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
{ 
    if (this.InvokeRequired()) 
    { 
     this.BeginInvoke(new EventHandler<SerialDataReceivedEventArgs>(DataReceivedHandler), new object[] { sender, e }); 
     return; 
    } 

    tbSerialStatus.Text = "Received text";  
} 
+1

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

ответ

3

Я думаю, вы уже думали об этом. Предполагая, что вы кодируете в форме, что-то вроде этого должно работать. Это от бедра, вы, возможно, потребуется настроить его немного:

private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
{ 

    if (this.InvokeRequired) 
    { 
     this.Invoke(new EventHandler<SerialDataReceivedEventArgs>(DataReceivedHandler), sender, e); 
     return; 
    } 

    // everything here runs on the UI thread, do what you like, 
    // and update as many UI controls as you like. 

} 

Как вы можете видеть, вы не должны обернуть каждый контроль доступа в отдельном Control.Invoke.

+0

А так, чтобы каждый элемент управления не требовался отдельно! Но почему это «Control.Invoke», разве это не должно быть «this.Invoke»? Кроме того, почему вы назначили 'DataReceivedHandler' в качестве делегата - мы уже находимся в этом обработчике, поэтому не следует ли пытаться перейти к методу в потоке пользовательского интерфейса? Я знаю, что вы просто написали это как черновик, но я пытаюсь убедиться. – boardbite

+0

Это неприятный ответ. Не используйте Control.BeginInvoke, как это. Это свойство, а не метод, оно всегда будет * true *. И * никогда * не используйте Control.Invoke(), это основной источник тупика. Особенно в обработчике событий DataReceived вызов метода SerialPort.Close() в потоке пользовательского интерфейса при выходе программы имеет очень высокий коэффициент взаимоблокировки. Всегда используйте BeginInvoke(). –

+0

Проблема решена - спасибо вам обоим! (См. ОБНОВЛЕНИЕ с рабочим кодом моего Вопроса.) – boardbite

0

Решено. Этот подход работает:

private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
{ 
    if (this.InvokeRequired()) 
    { 
     this.BeginInvoke(new EventHandler<SerialDataReceivedEventArgs>(DataReceivedHandler), new object[] { sender, e }); 
     return; 
    } 

    tbSerialStatus.Text = "Received text";  
} 
Смежные вопросы