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