Страницы

Поиск по вопросам

пятница, 7 декабря 2018 г.

Можете объяснить суть invoke

Есть основной поток, в котором я создаю все Controls в winforms. И есть второй поток, который вызывается через срабатывание события. В результате этого события мне нужно изменить значение DataSource у DataGridView. В результате возникает ошибка, что доступ к контролу пытается получить не основной поток, в котором был создан контрол. Решением является использование методов Invoke\BeginInvoke. Но саму суть я не понимаю этих методов и как их реализовать в коде. В создаваемом втором потоке используется функция доступа к dgv
private void RefreshTables() { try { if(con.State == ConnectionState.Closed) { con.Open(); } sql = "select rowid, * from OpenPos"; adapOpenPos = new SQLiteDataAdapter(sql, con); dsOpenPos = new DataSet(); adapOpenPos.Fill(dsOpenPos); dataGridView1.DataSource = dsOpenPos.Tables[0]; dataGridView1.Columns[0].Visible = false; dataGridView1.Columns[15].Visible = false; dataGridView1.Update(); con.Close();
if (con.State == ConnectionState.Closed) { con.Open(); } sql = "select rowid, * from ClosePos"; adapClosePos = new SQLiteDataAdapter(sql, con); dsClosePos = new DataSet(); adapClosePos.Fill(dsClosePos); dataGridView2.DataSource = dsClosePos.Tables[0]; dataGridView2.Columns[0].Visible = false; dataGridView2.Columns[14].Visible = false; dataGridView2.Update(); con.Close(); } catch (Exception e) { MessageBox.Show(e.Message); } }


Ответ

Суть метода 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"); }

Комментариев нет:

Отправить комментарий