Доступ к управлению окнами из Backgroundworker DoWork - PullRequest
2 голосов
/ 12 августа 2010

Моя проблема заключается в следующем:

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

Затем по нажатию кнопки мне нужно обработать данные, введенные пользователем на этих динамически создаваемых элементах управления. Для этой цели я использую Backgroundworker, который должен взять эти элементы управления и прочитать их данные.

Моя проблема заключается в том, что Backgroundworker не позволяет мне получить доступ к элементу управления из метода DoWork, но мне нужно сделать это таким образом, потому что я буду сообщать о ходе операций.

Вот части моего кода для пояснения концепции:

private void frmMyForm_Load(object sender, EventArgs e)
    {
       //I add multiple controls, this one is just for example
       LayoutPanel1.add(TextBox1);

       ....
    }

private void bgwBackground_DoWork(object sender, DoWorkEventArgs e)
    {

       foreach (Control controlOut in LayoutPanel1.Controls)
       {
           //do some stuff, this one is just for example
           string myString = controlOut.Name; //-> Here is the error, cant access controls from different Thread.
       }
    }

Задать текст просто, используя делегата, но как насчет получения всего родительского элемента управления для управления дочерними элементами управления (просто для получения информации, я не хочу задавать какие-либо данные, просто нужно получить имя, текст, вещи вот так).

Надеюсь, я все прояснил, спасибо всем.

Ответы [ 2 ]

11 голосов
/ 12 августа 2010

Вы можете получить доступ только к элементам управления Windows Forms из потока графического интерфейса.Если вы хотите манипулировать ими из другого потока, вам нужно будет использовать метод Control.Invoke , чтобы передать делегат для выполнения в потоке GUI.В вашей ситуации вы должны быть в состоянии сделать это:

private void bgwBackground_DoWork(object sender, DoWorkEventArgs e)
{
    foreach (Control controlOut in LayoutPanel1.Controls)
    {
        this.Invoke(new MethodInvoker(delegate {
            // Execute the following code on the GUI thread.
            string myString = controlOut.Name;
        }));
    }
}

Мне нравится определять метод расширения, который позволяет мне использовать более чистый лямбда-синтаксис:

// Extension method.
internal static void Invoke(this Control control, Action action) {
    control.Invoke(action);
}

// Code elsewhere.
this.Invoke(() => {
    string myString = controlOut.Name;
});
1 голос
/ 12 августа 2010

Как вы уже знаете, доступ к контрольным значениям из любого потока, кроме потока пользовательского интерфейса, - это большой запрет.Я бы сказал, что разумной реализацией является использование механизма синхронизации .NET, такого как WaitHandle, для приостановки фонового потока, пока поток пользовательского интерфейса обновляет потокобезопасную структуру данных по вашему выбору.

Идея состоит в том,что ваш фоновый поток уведомляет поток пользовательского интерфейса (через механизм делегирования, с которым вы уже знакомы), что ему нужна информация, а затем ожидает.Когда пользовательский интерфейс завершает заполнение совместно используемой переменной информацией, он сбрасывает WaitHandle и фоновый работник возобновляет работу.

Не выписывая и не тестируя весь код, позвольте мне дать вам несколько ресурсов:

...