我正在开发一个C#操作,我想显示一个模态进度对话框,但只有当一个操作很长时(例如,超过3秒)。我在后台线程中执行我的操作。
问题在于我事先并不知道该操作是长还是短。
某些软件IntelliJ有一个计时器方法。如果操作时间超过x时间,则显示一个对话框。
您认为这是一个很好的模式来实现这个目标吗?
DoEvents()
吗?答案 0 :(得分:4)
我将在这里做出第一选择并进行一些修改:
首先在不同的线程中运行可能的长时间运行操作 然后运行一个不同的线程,通过一个带有超时的等待句柄检查第一个状态,等待它完成。如果超时触发,则显示进度条。
类似的东西:
private ManualResetEvent _finishLoadingNotifier = new ManualResetEvent(false);
private const int ShowProgressTimeOut = 1000 * 3;//3 seconds
private void YourLongOperation()
{
....
_finishLoadingNotifier.Set();//after finish your work
}
private void StartProgressIfNeededThread()
{
int result = WaitHandle.WaitAny(new WaitHandle[] { _finishLoadingNotifier }, ShowProgressTimeOut);
if (result > 1)
{
//show the progress bar.
}
}
答案 1 :(得分:4)
这就是我要做的事情:
1)使用BackgroundWorker。
2)在调用方法RunWorkerAsync之前,将当前时间存储在变量中。
3)在DoWork事件中,您需要调用ReportProgress。在ProgressChanged事件中,检查时间是否已超过三秒。如果是,请显示对话框。
以下是BackgroundWorker的MSDN示例:http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
注意:一般来说,我同意Ramhound的评论。只需始终显示进度。但是如果您不使用BackgroundWorker,我会开始使用它。它会让你的生活更轻松。
答案 2 :(得分:2)
假设您使用DoPossiblyLongOperation()
,ShowProgressDialog()
和HideProgressDialog()
方法,您可以使用TPL为您做繁重的工作:
var longOperation = new Task(DoPossiblyLongOperation).ContinueWith(() => myProgressDialog.Invoke(new Action(HideProgressDialog)));
if (Task.WaitAny(longOperation, new Task(() => Thread.Sleep(3000))) == 1)
ShowProgressDialog();
答案 3 :(得分:0)
我会将进度对话框与后台活动分开,将我的UI逻辑与应用程序的其余部分分开。所以序列就是(这与IntelliJ所做的基本相同):
使用计时器而不是单独的线程可以提高资源效率。
答案 4 :(得分:0)
推荐的非阻塞解决方案,没有新的线程:
try
{
var t = DoLongProcessAsync();
if (await Task.WhenAny(t, Task.Delay(1000)) != t) ShowProgress();
await t;
}
finally
{
HideProgress();
}
答案 5 :(得分:0)
我从 Jalal Said 的回答中得到了这个想法。我需要超时或取消进度显示。我没有将附加参数(取消令牌句柄)传递给 WaitAny
,而是将设计更改为依赖于 Task.Delay()
private const int ShowProgressTimeOut = 750;//750 ms seconds
public static void Report(CancellationTokenSource cts)
{
Task.Run(async () =>
{
await Task.Delay(ShowProgressTimeOut);
if (!cts.IsCancellationRequested)
{
// Report progress
}
});
}
像这样使用它;
private async Task YourLongOperation()
{
CancellationTokenSource cts = new CancellationTokenSource();
try
{
// Long running task on background thread
await Task.Run(() => {
Report(cts);
// Do work
cts.Cancel();
});
}
catch (Exception ex) { }
finally {cts.Cancel();}
}