Как обновить текстовые поля в главном потоке из другого потока? - PullRequest
5 голосов
/ 15 декабря 2010

Как вы обновляете текстовые поля и метки в главном потоке из нового потока с другим классом.

MainForm.cs (Основной поток)

public partial class MainForm : Form
{
    public MainForm()
    {
        Test t = new Test();

        Thread testThread = new Thread(new ThreadStart(t.HelloWorld));
        testThread.IsBackground = true;
        testThread.Start();
    }

    private void UpdateTextBox(string text)
    {
        textBox1.AppendText(text + "\r\n");
    }

}

public class Test
{
    public void HelloWorld()
    {
        MainForm.UpdateTextBox("Hello World"); 
        // How do I execute this on the main thread ???
    }
}

Я смотрел на примерыздесь, но, кажется, не могу понять это правильно.Пожалуйста, кто-нибудь может дать хорошие ссылки.

Я начал все заново, чтобы не испортить свой код.Если кто-то хотел бы привести рабочий пример с моим примером, это было бы здорово.

Кроме того, если бы мне пришлось обновлять несколько объектов, таких как текстовые поля, метки и т. Д. (Не все одновременно), что было бы наилучшим способом для этого, иметь метод для каждого текстового поля или есть способсделать это одним методом?

Ответы [ 3 ]

6 голосов
/ 15 декабря 2010

Invoke или BeginInvoke, например,

Invoke((MethodInvoker)delegate {
    MainForm.UpdateTextBox("Hello World"); 
});

@ tiptopjones Я полагаю, вы также спрашиваете, как получить ссылку на форму. Вы можете заставить свой метод HelloWorld принимать параметр объекта, использовать делегат ParameterizedThreadStart, а затем передавать ссылку на форму в качестве параметра методу Thread.Start. Но я бы посоветовал прочесть об анонимных методах, что значительно облегчает работу и сохраняет строгий контроль.

public class MainForm : Form {
    public MainForm() {
        Test t = new Test();

        Thread testThread = new Thread((ThreadStart)delegate { t.HelloWorld(this); });
        testThread.IsBackground = true;
        testThread.Start();
    }

    public void UpdateTextBox(string text) {
        Invoke((MethodInvoker)delegate {
            textBox1.AppendText(text + "\r\n");
        });
    }
}

public class Test {
    public void HelloWorld(MainForm form) {
        form.UpdateTextBox("Hello World"); 
    }
}

Когда вы освоитесь с этим, вы можете прочитать о лямбда-выражениях и сделать это следующим образом:

Thread testThread = new Thread(() => t.HelloWorld(this));
4 голосов
/ 15 декабря 2010

Вы можете вызвать BeginInvoke метод , который поставит в очередь делегата для асинхронного выполнения в потоке пользовательского интерфейса.

Если вам нужен фоновый поток для ожидания завершения функции в потоке пользовательского интерфейса, вы можете вместо этого вызвать Invoke.

Обратите внимание, что вам понадобится ссылка на экземпляр вашей формы; вам, вероятно, следует передать это конструктору Test и сохранить его в закрытом поле.


Компонент BackgroundWorker сделает все это автоматически, используя метод ReportProgress; Вы должны рассмотреть возможность его использования.

1 голос
/ 15 декабря 2010

Предпочтительным способом в WinForms является использование SynchronizationContext

public partial class MainForm : Form
{
    SynchronizationContext ctx;

    public MainForm()
    {
        ctx = SynchronizationContext.Current;

        Test t = new Test();

        Thread testThread = new Thread(new ThreadStart(t.HelloWorld));
        testThread.IsBackground = true;
        testThread.Start();
    }

    private void UpdateTextBox(string text)
    {
        ctx.Send(delegate(object state)
        {
            textBox1.AppendText(text + "\r\n");

        },null);
    }    
}

public class Test
{
    public void HelloWorld()
    {
        MainForm.UpdateTextBox("Hello World"); 
        // How do I excute this on the main thread ???
    }
}
...