1

我有一个方法,其中有一个 for 循环。在 for 循环中,我想更新主窗体上的一些标签文本,但更改仅在循环结束后完成。

我试图在另一个线程上这样做:

Thread firstthread = new Thread(new ThreadStart(myMethod));
firstthread.Start();

当我这样做时,我InvalidOperationException因为试图访问另一个线程或类似的东西上的控件而得到一个。

在循环进行时,我应该如何从循环中更新主窗体上的标签(或其他控件)?

4

3 回答 3

4

您应该使用BackgroundWorker. 将长时间运行的循环放在DoWork事件处理程序中;它将在后台线程中运行并且不会阻塞 UI 线程。您可以设置ReportProgress为 true,然后将事件处理程序附加到它以允许您定期更新标签(或其他任何内容)。ProgressReported 事件在 UI 线程中运行。您还可以将处理程序添加到也在 UI 线程中运行的 Completed 事件。

您可以查看 BackgroundWorker 的MSDN 页面以获取详细信息和代码示例。

于 2012-10-08T13:47:44.463 回答
1

您应该检查 Form(对于 Windows.Forms)或窗口的 Dispatcher 对象(对于 WPF)上的 Invoke 和 BeginInvoke 方法。

例如:

this.BeginInvoke(new Action(() => this.Text = "ciao"));

更改表单的标题栏。

BeginInvoke 是异步的 - 它不会等待更改发生 - 而 Invoke 是同步的并且阻塞直到更改完成。除非您有特别的需要,否则我建议使用 BeginInvoke 来减少意外死锁的机会。

这将允许您从并发线程更新 UI - 并且可以使用您正在使用的任何线程机制(TPL 任务、普通线程等)。

于 2012-10-08T13:44:50.240 回答
1

正如 Servy 所说,你可以在这个简单的例子中使用类似的东西:

public partial class Form1 : Form
{
    BackgroundWorker bgw;
    public Form1()
    {
        InitializeComponent();
        bgw = new BackgroundWorker();
        bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
        bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
        bgw.WorkerReportsProgress = true;
    }

    void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        string text = (string)e.UserState;
        SetValue(text);//or do whatever you want with the received data
    }
    void SetValue(string text)
    {
        this.label1.Text = text;
    }

    void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < 10000; i++)
        {
            string text = "Value is " + i.ToString();
            bgw.ReportProgress(1, text);
            Thread.Sleep(1000);
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        bgw.RunWorkerAsync();
    }

}

于 2012-10-08T14:19:58.300 回答