Использование С# MethodInvoker.Invoke() для приложения с графическим интерфейсом... это хорошо?
Используя С# 2.0 и делегат MethodInvoker, у меня есть приложение GUI, получающее какое-либо событие из ни потока GUI, ни из рабочего потока.
Я использую следующий шаблон для обработки события в форме:
private void SomeEventHandler(object sender, EventArgs e)
{
MethodInvoker method = delegate
{
uiSomeTextBox.Text = "some text";
};
if (InvokeRequired)
BeginInvoke(method);
else
method.Invoke();
}
Используя этот шаблон, я не дублирую фактический код пользовательского интерфейса, но то, о чем я не уверен, - это хороший метод.
В частности, линия
method.Invoke()
использует ли он другой поток для вызова или несколько переводит его на прямой вызов метода в потоке GUI?
Ответы
Ответ 1
Вызов method.Invoke()
выполняет делегирование в текущем исполняемом потоке. Использование BeginInvoke(method)
гарантирует, что делегат вызывается в потоке графического интерфейса.
Это правильный способ избежать дублирования кода, когда один и тот же метод можно вызвать как из потока GUI, так и из других потоков.
Ответ 2
Лично мне нравится этот метод:
private void ExecuteSecure(Action a)
{
if (InvokeRequired)
BeginInvoke(a);
else
a();
}
И тогда вы можете написать однострочные строки следующим образом:
ExecuteSecure(() => this.Enabled = true);
Ответ 3
Имейте в виду, что Control.InvokeRequired возвращает false, если вы находитесь в фоновом потоке. AND Control.IsHandleCreated - false. Я бы защитил код с помощью Debug.Assert, который проверяет создание неуправляемого дескриптора.
Ответ 4
Для WinForms вызов Control.Invoke(Delegate)
отправляет сообщение на насос сообщения UID. Затем поток обрабатывает сообщение и вызывает делегата. После того, как он был обработан, Invoke
останавливает блокировку, а вызывающий поток возобновляет запуск вашего кода.
Ответ 5
Он вызывает вызов в том же потоке. Вы можете проверить, выполнив код. Нет ничего плохого в этом подходе.