Суть метода Invoke довольно проста - он принимает делегат и выполняет его в том потоке, в котором был создан элемент управления, у которого вызывается Invoke.
Как вы могли заметить, если обращаться к контролам в WinForms не из того потока, в котором они были созданы, будет выброшено исключение.
Соответственно, метод Invoke полезен в случаях, когда необходимо работать с контролом из других потоков.
Метод BeginInvoke делает то же самое, но асинхронно.
Небольшой пример использования Invoke:
private void ButtonInvoke_Click(object sender, EventArgs e)
{
var myThread = new Thread(ThreadFunction);
myThread.Start(); //метод выполняется в другом потоке
}
private void ThreadFunction()
{
Thread.Sleep(1000);
Action action = () => listBox1.Items.Add("value");
// Свойство InvokeRequired указывает, нeжно ли обращаться к контролу с помощью Invoke
if (InvokeRequired)
Invoke(action);
else
action();
}
Стоит также отметить, что async/await, добавленные в C# 5, позволяют обойтись без Invoke:
private async void ButtonAsync_Click(object sender, EventArgs e)
{
listBox1.Items.Add("first");
await Task.Run(async () =>
{
await Task.Delay(1000);
});
// этот код будет продолжен в UI потоке,
// и здесь нет необходимости использовать Invoke
listBox1.Items.Add("second");
}Т.е. грубо говоря, если мне нужно изменить datagridview в другом потоке, я в своём первоначальном коде изменяю контрол с помощью Invoke и делегата. Action action = () => dataGridView1.DataSource = dsOpenPos.Tables[0]; if (InvokeRequired) Invoke(action); else action();
В оконных приложениях Windows существует так называемый поток пользовательского интерфейса (UI thread), по сути — основной поток приложения, создаваемый самым первым.
Он выполняет обработку оконных сообщений (Windows messages), вызывая в цикле функции GetMessage или PeekMessage. Если вы хотите что-то сделать с пользовательским интерфейсом, например, изменить строку в поле ввода, вы посылаете ему оконное сообщение.
Комментариев нет:
Отправить комментарий