C# WPF:仅当后台任务花费的时间超过指定的时间间隔时,才显示进度对话框
我正在模态对话框的后台线程中执行一个可能长时间运行的操作。问题在于,当操作耗时较短时,对话框几乎会立即显示和关闭,这让用户感到恼火。 我只想在操作时间超过2秒时显示对话框 该对话框是一个WPF窗口,长时间运行的操作代码位于ViewModel中。ViewModel创建一个在后台运行操作的任务 以下是一个相关的片段:C# WPF:仅当后台任务花费的时间超过指定的时间间隔时,才显示进度对话框,c#,wpf,mvvm,task,C#,Wpf,Mvvm,Task,我正在模态对话框的后台线程中执行一个可能长时间运行的操作。问题在于,当操作耗时较短时,对话框几乎会立即显示和关闭,这让用户感到恼火。 我只想在操作时间超过2秒时显示对话框 该对话框是一个WPF窗口,长时间运行的操作代码位于ViewModel中。ViewModel创建一个在后台运行操作的任务 以下是一个相关的片段: public Task StartAction() { var mainTask = Task.Factory.StartNew(InternalAction); Ma
public Task StartAction() {
var mainTask = Task.Factory.StartNew(InternalAction);
MainTask = mainTask;
mainTask.ContinueWith(_ => { IsFinished = true; });
return mainTask;
}
InternalAction
是一个潜在的长时间运行的操作
这就是我试图引入延迟的方式。我从不同的角度使用Sriram Sakthivel的建议,但代码并不完全相同:
var viewModel = ... // Creates the ViewModel
var dialogWindow = ... // Creates the Window and starts the operation by calling viewModel.StartAction();
var delayTask = Task.Delay(2000);
if (viewModel.MainTask != null) {
Task.WaitAny(delayTask, viewModel.MainTask);
}
if (viewModel.IsFinished) {
return;
}
ShowDialog(dialogWindow); // this code calls dialogWindow.ShowDialog() eventually
我没有使用wait
,因为我不想将控制权让给调用者(COM),因为调用者希望在收回控制权时结果准备就绪
我一直在尝试不同的超时,例如5000ms,但我看不到行为上的任何差异。对话框窗口仍然“闪烁”(立即显示并关闭)。我肯定我做错了什么,但我不能理解我的错误 您正在等待
MainTask
,但是MainTask
不是设置IsFinished
的任务。您可能在InternalAction
完成之后,但在IsFinished=true
继续操作完成之前,从WaitAny
返回
尝试将MainTask
设置为延续,而不是其先行项:
public Task StartAction() {
var mainTask = Task.Factory.StartNew(InternalAction);
var continuation = mainTask.ContinueWith(_ => { IsFinished = true; });
MainTask = continuation;
return mainTask;
}
请注意,continuation
在mainTask
完成之前无法开始,因此通过此更改,您将等待mainTask
和continuation
但是,请注意,如果正在从UI线程读取
IsFinished
,您还需要从UI线程进行设置。或者让它由一个volatile
字段支持。过去有一个称为“Busy Indicator”的第三方库。也许您可以启用它,使其仅在繁忙条件满足一定时间时才显示?()
基本上可以归结为ViewModel公开了一个“busy”属性(或任何可以转换为表示“busy”的布尔值的属性)。以及对延迟(如果有)上的更改作出反应的视图
我不确定XAML本身是否可以做到这一点,因为您需要显示一个窗口。这里可能需要一些代码。注册一个启动计时器的定制ChangeNotification处理程序,让计时器重新检查“tick”事件中是否仍然满足条件,怎么样
以下是一些代码,主要由内存生成:
//custom ChangeNofiticationHander
busyChangeHanlder(object sender, PropertyChangedEventArgs e){
if(e.PropertyName == "BusyBoolean"){
if(BusyBoolean)
//Start the timer
else
//Stop the timer
}
}
timerTickHandler(object sender, TimerTickEventArgs e){
if(BusyBoolean){
//create and Dispaly the Dialog here
}
}
尝试这种方法-如果操作耗时超过2秒,它将只显示对话框窗口。您还可以将所有这些都打包到另一个任务中,然后调用方可以等待整个过程,而不管对话框是否显示 这个答案实际上没有帮助,因为它与我链接的答案非常相似。
var mainTask = Task.Delay(5000); // your long running task
if(Task.WaitAny(mainTask, Task.Delay(2000)) == 1){ // if the delay enden first, show dialog
showDialog();
await mainTask;
closeDialog();
}
await mainTask; // this will just skip, if mainTask is already done