C# 有没有办法让WPF中的后台工作人员慢下来?
在一些游戏中,有一个启动屏幕,可以从服务器下载内容。在你等待的时候,它可能会给你一些提示。我正在做类似的事情,只是加载速度非常快,但我希望它再等几秒钟 当用户第一次加载我的应用程序时,它有一个带有进度条的屏幕。目前,它检查服务器是否在线。如果是,它会说“已连接!”,但是,它会立即淡出我的控制。我想让它再等5秒钟,这样读者就可以阅读了。然后淡出控制C# 有没有办法让WPF中的后台工作人员慢下来?,c#,wpf,C#,Wpf,在一些游戏中,有一个启动屏幕,可以从服务器下载内容。在你等待的时候,它可能会给你一些提示。我正在做类似的事情,只是加载速度非常快,但我希望它再等几秒钟 当用户第一次加载我的应用程序时,它有一个带有进度条的屏幕。目前,它检查服务器是否在线。如果是,它会说“已连接!”,但是,它会立即淡出我的控制。我想让它再等5秒钟,这样读者就可以阅读了。然后淡出控制 private void frmMain_Loaded(object sender, RoutedEventArgs e) {
private void frmMain_Loaded(object sender, RoutedEventArgs e)
{
// Start background worker
m_bgWorker = new System.ComponentModel.BackgroundWorker();
m_bgWorker.ProgressChanged += M_bgWorker_ProgressChanged;
m_bgWorker.WorkerReportsProgress = true;
m_bgWorker.RunWorkerAsync();
m_bgWorker.ReportProgress(100);
}
private void M_bgWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progConnect.Value = 0;
if (SystemBO.IsOnline())
{
lblConnection.Content = "Connected!";
}
progConnect.Value = e.ProgressPercentage;
// TODO: Wait 5 seconds here...
// Fade out controls
lblTitle.BeginAnimation(Label.OpacityProperty, doubleAnimation);
progConnect.BeginAnimation(Label.OpacityProperty, doubleAnimation);
lblConnection.BeginAnimation(Label.OpacityProperty, doubleAnimation);
}
注:
- 我尝试了
,但没有什么不同。我明白为什么。想法是一样的:我希望后台工作人员在完成之前先睡5秒钟System.Sleep()
private void M_bgWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
m_index++;
System.Threading.Thread.Sleep(40);
m_bgWorker.ReportProgress(m_index);
}
System.Threading.Thread.Sleep(3000); // wait 3 seconds to read
}
private void M_bgWorker_DoWork(对象发送方,System.ComponentModel.DoWorkEventArgs e)
{
对于(int i=0;i<100;i++)
{
m_index++;
系统.线程.线程.睡眠(40);
m_bgWorker.报告进度(m_索引);
}
System.Threading.Thread.Sleep(3000);//等待3秒读取
}
成功了。进度条的动画制作相当流畅 您不应该在处理程序中进行淡出。该处理程序实际上应该只用于更新进度信息,如文本和百分比栏 淡出逻辑应移到单独的事件处理程序。在这里,您可以让线程在开始淡出控件之前休眠/等待一段时间。(在
Thread.Sleep()
上使用async
/wait
的优点是在等待时不阻塞UI线程,因此UI在等待时间流逝时仍保持响应。)
它还确保代码在最后被调用,而不是每次工作人员报告任何类型的进度时都被调用。它也更干净,因为它允许您通过检查RunWorkedCompletedEventArgs
来处理不同的终止状态:
- 如果设置了
,则工作线程中会发生异常e.Error
- 如果
为true,则通过调用工作线程上的e.Cancelled
来取消工作线程。(仅当CancelAsync()
设置为WorkerSupportsCancellation
时才可能,并且仅当处理程序中的代码实际检查取消标志时才有用)true
- 否则一切都会好起来的
旁注:
我假设您的代码不是完整的示例,因为您没有为
DoWork
事件分配实际的处理程序。所以现在它什么也做不了。从主线程调用ReportProgress()
也是错误的。该方法设计为从DoWork
事件处理方法中调用,以便让异步线程报告状态更新回UI,因为这些事件是在主线程上处理的。而不是加载的frmMain\u中的最后一行:
m_bgWorker.ReportProgress(100);
我将使用Sleep()设置一个for循环,以模拟一些额外的处理:
for (int i=0; i<=100; i+=10)
{
if (SystemBO.IsOnline())
i = 100;
Sleep(1000);
m_bgWorker.ReportProgress(i);
}
用于(int i=0;i注意到BackgroundWorker有一些附加事件,所以我尝试了这些事件。效果更好,是的!相关说明是,如果您使用.NET 4.5或更高版本,您可能希望使用任务完成整个任务。运行而不是BackgroundWorker
。这似乎是一种更现代、更直接的方法这避免了所有不同事件处理程序的麻烦:我相信我尝试过Task,但由于它在单独的线程上运行,它无法访问控件,因为主线程控制了它。这有点麻烦,然后我遇到了BackgroundWorker。@Bob这就是Dispatcher的用途。Dispatcher.Invoke将运行func在UI线程上单击查看我发布的链接的第5点。要报告任务的进度,可以使用委托函数实例化进度
对象,调用报告()时会调用委托函数
方法。与后台工作程序相比,报告的对象可以按任何类型,而不仅仅是整数和字符串。使用Thread.Sleep
几乎总是一个坏主意。等待任务。延迟(TimeSpan.FromSeconds(1.0))
会更好。@Enigmatity:我试过了,但得到了这个错误:System.InvalidOperationException:“这个操作已经调用了OperationCompleted,以后的调用是非法的。”@Bob-听起来像是在重用一个任务。延迟。你能显示代码吗?@Bob-无论如何睡眠都不是答案。Sug对故意延迟的任务进行异步操作只是一种狂热的反应。异步并不是解决所有问题的答案。对于这个特定的用例,睡眠效果很好,因为在显示进度对话框时没有其他事情要做。如果有用户操作要做(不寻常),如果更改睡眠持续时间,用户界面在1秒或更短时间后仍会响应。