Поиск…


Доступ к элементам управления формы из других потоков

Если вы хотите изменить атрибут элемента управления, такого как текстовое поле или ярлык из другого потока, кроме потока GUI, создавшего элемент управления, вам придется его вызывать, иначе вы можете получить сообщение об ошибке:

«Неверная операция поперечного потока: Control 'control_name' обращается из потока, отличного от потока, в котором он был создан."

Используя этот примерный код в форме system.windows.forms, вы получите исключение с этим сообщением:

private void button4_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(updatetextbox);
    thread.Start();
}

private void updatetextbox()
{
    textBox1.Text = "updated"; // Throws exception
}

Вместо этого, если вы хотите изменить текст текстового поля из потока, который не владеет им, используйте Control.Invoke или Control.BeginInvoke. Вы также можете использовать Control.InvokeRequired для проверки необходимости использования элемента управления.

private void updatetextbox()
{
    if (textBox1.InvokeRequired)
        textBox1.BeginInvoke((Action)(() => textBox1.Text = "updated"));
    else
        textBox1.Text = "updated";
}

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

public static class Extensions
{
    public static void BeginInvokeIfRequired(this ISynchronizeInvoke obj, Action action)
    {
        if (obj.InvokeRequired)
            obj.BeginInvoke(action, new object[0]);
        else
            action();
    }
}

И обновление текстового поля из любого потока становится немного проще:

private void updatetextbox()
{
    textBox1.BeginInvokeIfRequired(() => textBox1.Text = "updated");
}

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

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



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow