Приложение Windows Forms C# - Обновление GUI из другого потока И класса?

Я искал тонну, но я не могу найти ничего, касающегося моей конкретной проблемы.

Я хочу иметь возможность обновлять мою форму MainUI из другого класса (SocketListener), и в этом у меня есть поток, который обрабатывает сеть (clientThread). Прямо сейчас я могу запустить простые выходные данные из сетевого потока, такие как запись в выходные данные отладчика и создание MessageBox.

Но то, что я действительно хочу сделать, это иметь возможность вызывать код из clientThread, который будет делать вещи в моем экземпляре MainUI. Как я могу это сделать?

Кроме того, если кому-то нужны определенные части кода, я могу опубликовать его, чтобы помочь вам лучше понять, о чем я спрашиваю.

С наилучшими пожеланиями!

3 ответа

Решение

Проверить InvokeRequired из Control класс, и если это правда, то позвоните Invoke и передать делегат (обычно анонимный метод), который делает то, что вы хотите сделать в потоке клиента.

Пример:

public void DoWork(Form form)
{
    if (form.InvokeRequired)
    {
        // We're on a thread other than the GUI thread
        form.Invoke(new MethodInvoker(() => DoWork(form)));
        return;
    }

    // Do what you need to do to the form here
    form.Text = "Foo";
}

Да, вы можете добавить конструктор в ваш класс, который принимает форму MainUI в качестве параметра. Это быстрый способ сделать это, но он вводит "обратную" зависимость от вашего класса в MainUI, где, теоретически, никакой зависимости не требуется.

В качестве альтернативы я бы предложил добавить к вашему классу публичное событие, на которое затем могла бы подписаться форма MainUI. Когда вашему классу нужно обновить MainUI (или элементы управления внутри MainUI), класс просто "вызовет" событие. Это вызовет метод MainUI, который был зарегистрирован во время подписки. Поскольку это уже метод формы MainUI, все, что вам нужно сделать, это обновить соответствующие элементы управления в форме, убедившись, что InvokeRequired свойство каждого элемента управления во внимание.

И при этом вот конструкция, которую я использовал во всем своем коде.

class NetworkEventArgs : EventArgs { /* defined class here */ }
private void NetworkEventHandler(object sender, NetworkEventArgs e)
{ 
    Invoke( ( MethodInvoker ) delegate {
        myTextBox.Text = e.Message;
    }
}

Я основал это на записи в блоге здесь. У меня такой подход меня не подводил, поэтому я не вижу причин усложнять мой код с помощью рекурсивной проверки InvokeRequired имущество.

Вы можете определить событие вашего clientThread класса

и обрабатывать его в mainform, когда clientThread нуждается в осведомленной mainform, чтобы что-то сделать (например, обновить состояние элемента управления), вы должны запустить событие

поэтому mainform получает параметр из события и вызывает функцию обновления

Другие вопросы по тегам