我正在开发一个C#操作,我想显示一个模态进度对话框,但只有当一个操作很长时(例如,超过3秒)。我在后台线程中执行我的操作。
问题是我事先并不知道该操作是长还是短。
像IntelliJ这样的软件有一个计时器方法。如果操作时间超过x时间,则显示一个对话框。
你认为这是一个很好的模式来实现这个?
DoEvents()
吗?我将在这里进行第一选择并进行一些修改:
首先在不同的线程中运行可能的长时间运行操作。 然后运行一个不同的线程,通过一个带有超时的等待句柄检查第一个状态,等待它完成。如果超时触发器显示进度条。
就像是:
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)使用BackgroundWorker。
2)在调用方法RunWorkerAsync之前,将当前时间存储在变量中。
3)在DoWork事件中,您需要调用ReportProgress。在ProgressChanged事件中,检查时间是否已超过三秒。如果是,请显示对话框。
以下是BackgroundWorker的MSDN示例:http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
注意:一般来说,我同意Ramhound的评论。只需始终显示进度。但是如果您不使用BackgroundWorker,我会开始使用它。它会让你的生活更轻松。
假设你有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();
我会将进度对话框与后台活动分开,将我的UI逻辑与应用程序的其余部分分开。所以序列就是(这与IntelliJ的作用基本相同):
使用计时器而不是单独的线程更具资源效率。
推荐的非阻塞解决方案,没有新的线程:
try
{
var t = DoLongProcessAsync();
if (await Task.WhenAny(t, Task.Delay(1000)) != t) ShowProgress();
await t;
}
finally
{
HideProgress();
}