C# WPF:仅当后台任务花费的时间超过指定的时间间隔时,才显示进度对话框

C# WPF:仅当后台任务花费的时间超过指定的时间间隔时,才显示进度对话框,c#,wpf,mvvm,task,C#,Wpf,Mvvm,Task,我正在模态对话框的后台线程中执行一个可能长时间运行的操作。问题在于,当操作耗时较短时,对话框几乎会立即显示和关闭,这让用户感到恼火。 我只想在操作时间超过2秒时显示对话框 该对话框是一个WPF窗口,长时间运行的操作代码位于ViewModel中。ViewModel创建一个在后台运行操作的任务 以下是一个相关的片段: public Task StartAction() { var mainTask = Task.Factory.StartNew(InternalAction); Ma

我正在模态对话框的后台线程中执行一个可能长时间运行的操作。问题在于,当操作耗时较短时,对话框几乎会立即显示和关闭,这让用户感到恼火。 我只想在操作时间超过2秒时显示对话框

该对话框是一个WPF窗口,长时间运行的操作代码位于ViewModel中。ViewModel创建一个在后台运行操作的任务

以下是一个相关的片段:

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