首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从多个工作线程(.NET)更新UI

从多个工作线程(.NET)更新UI
EN

Stack Overflow用户
提问于 2010-01-19 21:35:00
回答 6查看 12.2K关注 0票数 6

我有一个我正在做的宠物项目,它有多个工作线程。将所有输出输出到控制台变得越来越难,所以我想开发一个UI,它每个线程都有一个输出区域。我想知道线程向UI发送更新的最佳方式。我有两个想法:

1)当新数据可用时,让每个线程设置一个"DataUpdated“标志,并让UI定期检查新数据。

2)使用UI更新回调(.)创建每个线程方法,以便在新数据可用时调用。

我目前倾向于(2)有两个原因:我不喜欢“检查”每个线程的想法,因为这是我的第一个多线程应用程序,(2)看起来比它可能更简单。我想知道:

  • 在简单性和效率方面,哪一种选择更可取?
  • 您有什么技巧来实现(2)或类似的东西(即更多的事件驱动)?
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-01-19 21:38:21

通过创建BackgroundWorker组件并在其DoWork处理程序中完成工作,您可以轻松地实现(2):

代码语言:javascript
复制
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += /* your background work here */;
bw.ProgressChanged += /* your UI update method here */;
bw.RunWorkerAsync();

每个BackgroundWorker都可以通过调用ReportProgress向UI线程报告进度:虽然这主要是为报告有界进程的进度而设计的,但这不是强制性的--如果您的UI更新需要这样的话,您也可以传递您自己的自定义数据。您可以从您的ReportProgress处理程序中调用DoWork。

BackgroundWorker的好处是它为您处理了许多混乱的交叉线程细节。它也符合事件驱动的更新模型,您(正确地)更倾向于显式回调。

票数 12
EN

Stack Overflow用户

发布于 2010-01-19 22:31:05

在大多数情况下,最简单的方法是使用itowlson的答案中所建议的BackgroundWorker组件,如果可能的话,我强烈建议使用这种方法。如果出于某种原因,您不能使用BackgroundWorker组件来实现您的目的,比如您正在使用.Net 1.1开发(yikes!)或者使用紧凑的框架,那么您可能需要使用另一种方法:

使用Winform控件时,您必须避免修改除最初创建控件的线程之外的任何线程上的控件。BackgroundWorker组件为您处理这个问题,但是如果您不使用它,那么您可以而且应该使用在System.Windows.Forms.Control类中找到的InvokeRequired属性和Invoke方法。下面是一个使用此属性和方法的示例:

代码语言:javascript
复制
public partial class MultithreadingForm : Form
{
    public MultithreadingForm()
    {
        InitializeComponent();
    }

    // a simple button event handler that starts a worker thread
    private void btnDoWork_Click(object sender, EventArgs e)
    {
        Thread t = new Thread(WorkerMethod);
        t.Start();
    }

    private void ReportProgress(string message)
    {
        // check whether or not the current thread is the main UI thread
        // if not, InvokeRequired will be true
        if (this.InvokeRequired)
        {
            // create a delegate pointing back to this same function
            // the Invoke method will cause the delegate to be invoked on the main UI thread
            this.Invoke(new Action<string>(ReportProgress), message);
        }
        else
        {
            // txtOutput is a UI control, therefore it must be updated by the main UI thread
            if (string.IsNullOrEmpty(this.txtOutput.Text))
                this.txtOutput.Text = message;
            else
                this.txtOutput.Text += "\r\n" + message;
        }
    }

    // a generic method that does work and reports progress
    private void WorkerMethod()
    {
        // step 1
        // ...
        ReportProgress("Step 1 completed");

        // step 2
        // ...
        ReportProgress("Step 2 completed");

        // step 3
        // ...
        ReportProgress("Step 3 completed");
    }
}
票数 2
EN

Stack Overflow用户

发布于 2010-01-19 21:37:28

我也投第二票,但用的是BackgroundWorkers而不是System.Threading.Threads。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2097284

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档