Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将对象从backgroundworker传递到主线程_C#_.net_Multithreading_Backgroundworker - Fatal编程技术网

C# 将对象从backgroundworker传递到主线程

C# 将对象从backgroundworker传递到主线程,c#,.net,multithreading,backgroundworker,C#,.net,Multithreading,Backgroundworker,我有一个WPF应用程序,它执行外部程序来处理媒体文件,为了在处理媒体文件时GUI不会冻结,我通过backgroundworker在单独的线程上执行该过程 private void BackgroundWorkerExecProcess(Process process) { BackgroundWorker worker = new BackgroundWorker(); worker.WorkerReportsProgress = fals

我有一个WPF应用程序,它执行外部程序来处理媒体文件,为了在处理媒体文件时GUI不会冻结,我通过backgroundworker在单独的线程上执行该过程

        private void BackgroundWorkerExecProcess(Process process)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.WorkerReportsProgress = false;
        worker.DoWork += DoWork;
        worker.RunWorkerCompleted += WorkerCompleted;
        worker.RunWorkerAsync(process);
    }
    void DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        Process process = e.Argument as Process;
        process.Start();
        string stderr = process.StandardError.ReadToEnd();
        //I want to display stderr on main thread
        process.WaitForExit();
    }
    void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        //some code to update gui telling user that process has finished
    }
因此,如果有打印到stderr的内容,我可以在调试器中看到它,但是如果我尝试使用字符串stderr执行任何操作,例如,如果我有一个名为“\u tbLog”的文本框,并且


我从编译器那里得到一个关于它们在不同线程上的错误。是否有方法将对象从工作线程传递到主线程?

在DoWork中,将e.Result设置为对象。在WorkerCompleted中,您可以将该对象取回。。。它将再次成为e.object类型的结果。把它扔到原来的物体上。完成的工件应在正确的螺纹上

这是我的一个:

private void workerUpdateBuildHistory_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    UpdateStatusModel model = (UpdateStatusModel)e.Argument;
    BuildService buildService = new BuildService(model.TFSUrl);
    e.Result = buildService.UpdateBuildHistoryList(model);
}

private void workerUpdateBuildHistory_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    BuildHistoryListModel model = (BuildHistoryListModel)e.Result;
    if (model != null)
    {
        listViewPastBuilds.Items.Clear();
        foreach (var item in model.Builds)
        {
            listViewPastBuilds.Items.Add(item);
        }
    }
}

首先,您需要将任何结果对象(在本例中为字符串列表)放入DoWorkEventArgs.result属性中,然后通过RunWorkerCompletedArgs.result属性检索该对象

然后,连接后台工作程序的事件处理程序RunWorkedCompleted事件,并让它传回RunWorkerCompletedEventArgs.Result属性中需要的任何对象

例如:

void DoWork(object sender, DoWorkEventArgs arg)
{
   List<string> results = new List<string>();
   results.Add("one");
   results.Add("two");
   results.Add("three");
   arg.Results = results;
}

void WorkComplete(object sender, runWorkerCompelteEventArgs arg)
{
   //Get our result back as a list of strings
   List<string> results = (List<string>)arg.Result;
   PrintResults(results);
}
void DoWork(对象发送方,DoWorkEventArgs参数)
{
列表结果=新列表();
结果。添加(“一”);
结果。添加(“两”);
结果。添加(“三”);
arg.Results=结果;
}
void WorkComplete(对象发送方,runworkercompleteeventargs参数)
{
//将结果作为字符串列表返回
列表结果=(列表)arg.Result;
打印结果(结果);
}
注意:我还没有测试过这段代码,但我相信它应该可以编译。

您也可以使用调度器,因为@Zembi提到:

  this.Dispatcher.Invoke( new Action( () => {
    _tbLog.Text+=stderr; 
  } ) );
您还可以使用来确保在正确的线程上运行

-编辑-


这里介绍了进行ui更新的不同方法,包括使用TPL,使用WorkerCompleted事件处理程序对ui进行更改,它在正确的线程上运行。您所要做的就是将字符串传递给事件处理程序。这就是DowereVentargs设计的结果。您将在事件处理程序中从e.Result中检索它。因此:

   void DoWork(object sender, DoWorkEventArgs e)
   {
      //...
      e.Result = stderr;
   }

   void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
   {
      if (e.Error != null) DisplayError(e.Error);
      else _tbLog.Text += (string)e.Result;
   }

谢谢这很有效。刚刚添加了e.Result=stderr;然后在workercompleted中,我能够使用_tbLog.Text+=e.Result作为字符串;请注意,读取e.Result将显示DoWork中未处理的任何异常。完成的事件应该遵循一种模式,请看,我已经按照CrazyDart的解决方案让它工作了,但是如果我使用TPL,并且让进程在正确的线程(主线程)上运行,这不也会阻止GUI重新绘制,锁定应用程序吗?如果在GUI线程上运行整个进程,是的。然而,tpl的一个关键好处是,它很容易在使用continuations(ContinueWith(..)方法)的线程和调度器之间传递工作。您将在线程池上启动一个新任务,完成后,您将在更新ui的ui线程上安排一个新任务。
   void DoWork(object sender, DoWorkEventArgs e)
   {
      //...
      e.Result = stderr;
   }

   void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
   {
      if (e.Error != null) DisplayError(e.Error);
      else _tbLog.Text += (string)e.Result;
   }