对同一个Form实例使用多线程?

时间:2013-05-21 15:50:18

标签: c# multithreading

我有一个单线程C#工具,其中有一堆UI输入控件。基于这些控件和一些输入的Excel文件,正在进行一些处理。此处理需要10~15秒,在此期间程序无响应。完成工作后,输出文本将在文本框中提及。

现在我有一个完成所有工作的功能。但是,此功能取决于用户提供的UI输入。

我刚尝试使用此代码应用一些线程:

workerThread = new Thread(this.WorkerFunction);
workerThread.Start();
//workerThread.Join();
output.Text = outputStringBuilder.ToString();

我基本上在这里使用相同的Form实例,因为使用另一个Form实例将无法工作,因为新的Form实例将不包含用户指定的输入。

正如上面提到的代码,它工作。我没有在文本框中看到输出文本。它只有在我启用workerThread.Join();语句时才有效,但后来我看到经历了10~15秒的延迟,这打破了线程的整个点......

那么如何在这个设置中添加线程,而不必向workerFunction添加一大堆输入参数(因为我希望看到UI控件的输入)。?

2 个答案:

答案 0 :(得分:0)

  

但是,此功能取决于用户提供的UI输入。

嗯,这是您需要解决的第一个问题。您需要将UI交互与业务逻辑和长时间运行的流程分开。

之前调用长时间运行的函数时,您应该从UI中提取执行此处理所需的任何信息。将该信息传递给通过一个或多个参数进行处理的方法。如果有大量信息,可能值得封装在特定的数据持有者类(或类或集合等,取决于信息的范围)。

接下来,不是让这个过程用它生成​​的任何结果更新UI,而是让这个函数返回一个表示业务操作结果的值;然后,UI代码可以根据需要获取这些结果并操作UI。

现在,有许多不同的线程工具专门用于帮助您在UI程序中执行长时间运行的操作,同时在另一个线程中执行长时间运行的工作,但同时在UI上下文中执行UI相关工作。其中之一是BackgroundWorker类。 (如果您使用的是C#5.0,则可以将任务并行库与asyncawait关键字结合使用,这实际上要好得多。)

完成此操作后,您的代码将很好地适应BackroundWorker提供的功能。

首先从UI中提取数据。然后创建BGW,分配一个DoWork处理程序来完成工作并使用从UI中提取的信息。将Result设置为操作的结果。然后使用RunWorkerCompleted处理程序更新具有这些结果的UI。

var myUIInfo = new SomeClass(){Info = someControl.Text
    , Other = someOtherControl.Selected};
var worker = new BackgroundWorker();
worker.DoWork += (s,e) => e.Result = LongRunningProcess(myUIInfo);
worker.RunWorkerCompleted += (s, e) += UpdateUIWith(e.Result);
worker.RunWorkerAsync();

答案 1 :(得分:0)

如果您的任务很简单并且只需几行代码,那么您可以简单地将output.Text更新移动到WorkerFunction,而不是整个BackgroundWorker设置。请记住使用Dispatcher否则它将无法工作,具体如下:

Invoke(new MethodInvoker(
            delegate
            {
                // Update output.Text here
            }
            ));