C# 后台工作程序不使用WPF

C# 后台工作程序不使用WPF,c#,wpf,backgroundworker,C#,Wpf,Backgroundworker,在我的WPF程序中,它需要大量的处理时间和长时间的冻结 所以我决定使用后台工作程序并在后台处理它 但它不起作用。通过调试,程序在Render3D()处停止。它不会抛出异常。这就像你把return放进去一样 换句话说,它在到达Render3D()后不会执行任何操作,只会返回 (我不说它会返回,因为我不确定,但行为与返回相同) 这一部分 private void DefineCamera() { PerspectiveCamera camera = new Persp

在我的WPF程序中,它需要大量的处理时间和长时间的冻结

所以我决定使用后台工作程序并在后台处理它

但它不起作用。通过调试,程序在
Render3D()
处停止。它不会抛出异常。这就像你把
return
放进去一样

换句话说,它在到达
Render3D()
后不会执行任何操作,只会返回

(我不说它会返回,因为我不确定,但行为与返回相同)

这一部分

    private void DefineCamera()
    {
        PerspectiveCamera camera = new PerspectiveCamera
        {
            FieldOfView = 60
        };

        PositionCamera(camera);
        Viewport.Camera = camera; // Must be run in Main thread.
    }

在WPF的世界中,不同于您习惯使用的Windows窗体,您应该考虑<强>调度程序< /强>。为此,必须导入

System.Windows.Threading

    private void ThreadTask()
    {
        Thread.Sleep(TimeSpan.FromSeconds(5));

        this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                    (ThreadStart)delegate()
                    {
                        //Do some heavy task here...
                    });
    }
快速更新

要从按钮单击或任何函数运行线程,请添加以下代码行:

    Thread thread = new Thread(new ThreadStart(ThreadTask));
    thread.Start();

这行代码相当于
BackgroundWorker.RunWorkerAsync()

我强烈建议使用async/await。此功能是在.NET4.5中引入的,用于将工作转移到主WPF GUI线程之外,以使应用程序快速响应

基本上,规则是使用Task.Runasync/await的组合将任何不与GUI交互的计算推送到后台线程上。与Dispatcher.Invoke一起,您实际上不需要其他任何东西

例如,可能从数据库获取数据的慢速数据调用可以推送到后台线程上,因此应用程序在等待SQL执行时会冻结


我用它使我编写的应用程序快速、响应迅速。

首先,您很难找到错误

。。。程序在Render3D()处停止。它不会抛出异常。就好像你把它放回去一样

实际发生的情况是,您的方法引发了一个异常,而Backgroundworker捕获了该异常。它被转移到已完成的事件中,但您必须在那里采取行动

private void worker_Completed(object sender, RunWorkerCompletedEventArgs e) 
{
  // check error, check cancel, then use result
  if (e.Error != null)
  {
     // handle the error
  }
  else if (e.Cancelled)
  {
     // handle cancellation
  }
  else      
  {         
      // use the result(s) on the UI thread
  }    
  // general cleanup
}
未能查看
e.Error
e.Result
与程序中存在空的
catch{}
块相同

在错误处理就绪后,我们就可以

哦,是的,它显示了错误。System.InvalidOperationException调用线程无法访问此对象,因为其他线程拥有它

这表明Render3D()仍在某处与GUI交互


基本建议是将所有计算(以及I/O、数据库)工作与UI工作分开。您可以在一个线程中运行CPU绑定和I/O绑定的cod,但是GUI是单线程的,您只能从主线程与之交互

您没有已完成的事件。添加它并处理传入的
e.Error
。或者只是在DoWork中添加一个try/catch。您现在忽略了可能会告诉您出错原因的异常。“在我添加RunWorkerCompleted后”确定,现在让它报告
e.Error
。确定,Render3D()不适合在线程上运行。练习结束。我们无法对看不到的代码进行注释/分析。视口将无法安全使用。也许你可以拆分GUI/非GUI代码,我不知道。+1谢谢。我将尝试拆分非GUI部分。绘图模型只需要几毫秒。所以这可能会解决问题@HenkHoltermanCan有人能解释为什么投票失败吗?我以前用过,没有任何问题!这毫无意义。即使忽略Sleep(),也会将“繁重的任务”发送回主Gui线程。一无所获。只是一个令人困惑的绕道。它会起作用,但不会解决你的冰冻问题。@Henkholtman我和调度员一起生活了将近两年,没有任何问题。我曾将其用于数据库应用程序开发(这需要繁重的任务)。@user3104111:正如亨克所说,你完全忽视了OP问题的根源。这与是否使用BackgroundWorker无关。如果我们要讨论最佳实践,那么使用Tasks和async将优于您的建议,更不用说您正在创建单个线程,而不是使用标准线程池,我可以继续……这些都不能解决OP面临的问题。@HenkHolterman我建议使用async/await进行重构。这将解决OP遇到的问题。不,它将遇到相同的异常。这里没有魔杖。
    Thread thread = new Thread(new ThreadStart(ThreadTask));
    thread.Start();
private void worker_Completed(object sender, RunWorkerCompletedEventArgs e) 
{
  // check error, check cancel, then use result
  if (e.Error != null)
  {
     // handle the error
  }
  else if (e.Cancelled)
  {
     // handle cancellation
  }
  else      
  {         
      // use the result(s) on the UI thread
  }    
  // general cleanup
}