【问题标题】:How to update textboxes in main thread from another thread?如何从另一个线程更新主线程中的文本框?
【发布时间】:2010-12-15 01:53:44
【问题描述】:

如何从运行不同类的新线程更新主线程中的文本框和标签。

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 ???
    }
}

我已经查看了此处的示例,但似乎无法正确理解。请有人提供一些好的链接。

我重新开始了,所以我不会弄乱我的代码。如果有人想用我的例子提出一个可行的例子,那就太好了。

另外,如果我必须更新多个对象,如文本框和标签等(不是同时更新),最好的方法是什么,每个文本框都有一个方法,或者有没有办法做到这一点一种方法?

【问题讨论】:

  • 欢迎来到 SO。您可以编辑您的问题以添加更多信息,并且您可以将 cmets 留在您提出的问题的答案上(以及在您达到 50 次代表之后的任何内容)。

标签: c# multithreading user-interface


【解决方案1】:

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"); 
    }
}

当您对此感到满意时,您可以阅读 lambda 表达式并这样做:

Thread testThread = new Thread(() => t.HelloWorld(this));

【讨论】:

  • 嘿,最好编辑您的问题以添加更多信息,而不是提供其他答案。
【解决方案2】:

您可以调用BeginInvoke method,它将一个委托排队,以便在 UI 线程上异步执行。

如果您需要后台线程等到 UI 线程上的函数完成,您可以改为调用 Invoke

请注意,您需要对表单实例的引用;您可能应该将其传递给 Test 构造函数并将其存储在私有字段中。


BackgroundWorker component 将使用ReportProgress 方法自动完成所有这些工作;你应该考虑使用它。

【讨论】:

  • 感谢您的回答,但我是 c# 新手,需要一个示例来解决问题,以便我了解它是如何工作的。
  • @tiptop:那么您可能应该使用 BackgroundWorker。 MSDN has examples.
  • 任何 WinForms 开发人员都应该了解如何以线程安全的方式更新 UI,这两种方法都是可以理解的有效选项
  • ...还值得警告的是,用于切换到 UI 线程的SynchronizationContext.BeginInvoke()Delegate.BeginInvoke() 不同,Invoke() on each Type 也是如此。如果您正在使用多线程 WinForms,那么这种歧义可能会让您感到困惑
【解决方案3】:

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 ???
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-13
    相关资源
    最近更新 更多