后台工作器不工作WPF
本文关键字:工作 WPF 后台 | 更新日期: 2023-09-27 17:53:57
在我的WPF程序中需要大量的处理时间和长时间的冻结。
所以我决定使用后台worker并在后台处理。
,但它不起作用。通过调试,程序停在Render3D()
。它不会抛出异常。就像你放了return
。
换句话说,到达Render3D()
后不做任何事情,只返回。
(我没有说它会返回,因为我不确定,但行为是相同的返回)
private readonly BackgroundWorker backgroundWorker = new BackgroundWorker();
private AssetDeclaration _assetDeclaration = new AssetDeclaration();
public MainWindow()
{
backgroundWorker.DoWork += backgroundWorker1_DoWork;
backgroundWorker.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 1000; i++)
{
if (!((BackgroundWorker)sender).CancellationPending)
{
Render3D(); // will return at this point. (why?) or waiting for something to start?
((BackgroundWorker)sender).ReportProgress(i);
}
else
{
e.Cancel = true;
break;
}
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done!");//will show message box instant.
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressBar1.Value = e.ProgressPercentage;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//...Some work here before starting Hard job!
//...From now i want to start heavy process in background.
//...with report to progress bar at same time.
backgroundWorker.RunWorkerAsync(100);
}
Render3D()在没有后台处理的情况下工作良好,但会冻结一段时间。
Render3D()是MainWindow
的Partial
类,因为有很多方法,所以我决定把它们分开。
我如何在backgroundWorker1_DoWork
之外使用ReportProgress
。例如在Render3D()。
最后一件事:我想知道如何向用户显示完成了多少进程。
解决!:
问题是因为我在Render3D()
里面设置了Viewport3D
我把它从Render3D中分离出来,问题得到了修复。感谢Henk Holterman给出的正确答案。
似乎有些任务不能在另一个线程中完成。在错误报告中,我发现无效的任务正在设置Viewport3D属性。
这个任务必须在主线程中完成。
下面的是无效的代码,导致后台worker停止工作。
DefineCamera();
Viewport.Children.Add(model); // Must be run in Main thread.
和这部分
private void DefineCamera()
{
PerspectiveCamera camera = new PerspectiveCamera
{
FieldOfView = 60
};
PositionCamera(camera);
Viewport.Camera = camera; // Must be run in Main thread.
}
首先,您很难找到错误。
…程序在Render3D()处停止。它不会抛出异常。就像你输入return。
实际发生的情况是,你的方法抛出了一个异常,并被后台工作线程捕获。它被转移到Completed事件,但你必须在那里对它采取行动。
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{}
块相同。
有了错误处理,我们就有了
哦,是的,它显示错误。系统。调用线程不能访问这个对象,因为它被另一个线程拥有
这表明你的Render3D()仍然与GUI交互。
基本建议是将所有计算(和I/O,数据库)工作与UI工作分开。你可以在一个线程中运行CPU绑定和I/O绑定的代码,但是GUI是单线程的,你只能在主线程中与它交互。
在WPF的世界中,与您习惯的Windows窗体不同,您应该考虑Dispatcher。为此,您必须导入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。该特性是在。net 4.5中引入的,用于将工作从主WPF GUI线程中转移出来,使应用程序快速响应。
从本质上讲,规则是使用Task的组合将任何不与GUI交互的计算推到后台线程上。运行和async/await。与Dispatcher一起使用。调用,您实际上不需要其他任何东西。例如,一个可能从数据库中获取数据的缓慢的数据调用可以被推到后台线程中,因此应用程序在等待SQL执行时确实会冻结。
我已经用它来让我写的应用程序快速,响应和时髦。