2011-08-04 107 views
5

我正在开发C#操作,我只想显示一个模式进度对话框,但只有在操作很长(例如超过3秒)时才会显示。我在后台线程中执行我的操作。只有在后台操作很长的情况下才显示进度

问题是,我不知道操作是长期还是短期。

一些软件如IntelliJ有一个定时器aproach。如果该操作花费的时间超过x次,则会显示一个对话框。

你认为这是一个很好的模式来实现这个?

  • 用计时器等待UI线程,并在那里显示对话框?
  • 必须我DoEvents()当我显示对话框?
+2

你为什么不简单总是显示进度。如果它的任务很短,那么进度条就会被填满并显示很短的时间。例如Office总是在底部显示加载进度条,即使在小文档中也是如此。 –

+3

操作快时看到闪烁的对话框(毫秒)很烦人。 –

回答

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. 
    } 
} 
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,我会开始使用它。它会让你的生活更轻松。

0

我会将进度对话框与后台活动分开,以将我的UI逻辑与应用程序的其余部分分开。因此,顺序将是(这是基本相同什么的IntelliJ一样):

  1. UI启动后台操作(BackgroundWorker的),并设置一个计时器X秒
  2. 当计时器到期UI显示进度对话框(如果后台任务仍在运行)
  3. 当后台任务完成计时器被取消,对话框(如果有的话)被关闭

使用定时器,而不是一个单独的线程是多个资源效率高达。

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(); 
+0

而不是Thread.Sleep,我会建议Task.Delay,以免整个线程进入睡眠状态(多个任务可能在同一个线程上运行)。 – MCattle

+1

@MCattle:是的。在编写这个答案的时候,Task.Delay并不存在于框架中,并且使用System.Threading.Timer会使事情变得复杂,以致于无法证明我试图展示的简单原则。 –

0

推荐非阻塞的解决方案,没有新的主题:

try 
{ 
    var t = DoLongProcessAsync(); 
    if (await Task.WhenAny(t, Task.Delay(1000)) != t) ShowProgress(); 
    await t; 
} 
finally 
{ 
    HideProgress(); 
} 
相关问题