2011-08-04 8 views
5

Estoy desarrollando una operación de C# y me gustaría mostrar un diálogo de progreso modal, pero solo cuando una operación será larga (por ejemplo, más de 3 segundos). Ejecuto mis operaciones en un hilo de fondo.Mostrar progreso solo si la operación de fondo es larga

El problema es que no sé de antemano si la operación será larga o corta.

Algún software como IntelliJ tiene un enfoque de temporizador. Si la operación lleva más de x tiempo, entonces muestra un cuadro de diálogo.

¿Cuál cree que es un buen patrón para implementar esto?

  • ¿Espera el hilo de la interfaz de usuario con un temporizador y muestra el cuadro de diálogo allí?
  • ¿Debo DoEvents() cuando muestro el cuadro de diálogo?
+2

¿Por qué simplemente no siempre muestra el progreso? Si es una tarea corta, la barra de progreso se llena y muestra solo un corto período de tiempo. Office, por ejemplo, siempre muestra la barra de progreso de carga en la parte inferior, incluso en un documento pequeño. –

+3

Es molesto ver un cuadro parpadeante (milisegundos) cuando la operación es rápida. –

Respuesta

4

voy a ir con la primera opción aquí con algunas modificaciones:

En primer lugar ejecutar la posible operación de larga data en el subproceso diferente.
Luego ejecute un hilo diferente para verificar el primer estado mediante un identificador de espera con tiempo de espera para esperar a que termine. si se dispara el tiempo de espera, aparece la barra de progreso.

Algo así como:

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

Esto es lo que haría:

1) Use un BackgroundWorker.

2) Antes de llamar al método RunWorkerAsync, almacene la hora actual en una variable.

3) En el evento DoWork, deberá llamar a ReportProgress. En el evento ProgressChanged, verifique si el tiempo ha transcurrido más de tres segundos. Si es así, muestre el diálogo.

Aquí está un ejemplo de MSDN para el BackgroundWorker: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

Nota: En general, estoy de acuerdo con el comentario de Ramhound. Solo siempre muestre el progreso. Pero si no estás usando BackgroundWorker, comenzaría a usarlo. Te hará la vida más fácil.

0

Mantendría el diálogo de progreso separado de la actividad de fondo, para separar mi lógica de UI del resto de la aplicación. Así que la secuencia sería (Esto es esencialmente lo mismo que lo hace IntelliJ):

  1. interfaz de usuario inicia la operación de fondo (en un BackgroundWorker) y establecer un temporizador para X segundos
  2. Cuando el temporizador expira muestra la interfaz de usuario el diálogo de progreso (si la tarea en segundo plano todavía se está ejecutando)
  3. Cuando la tarea de fondo completa el temporizador se cancela y el diálogo (si los hay) se cierra

el uso de un temporizador en lugar de un hilo separado es más recursos -eficiente.

2

Asumiendo que tienen un DoPossiblyLongOperation(), ShowProgressDialog() y HideProgressDialog() métodos, se puede utilizar el TPL para hacer el trabajo pesado para usted:

var longOperation = new Task(DoPossiblyLongOperation).ContinueWith(() => myProgressDialog.Invoke(new Action(HideProgressDialog))); 

if (Task.WaitAny(longOperation, new Task(() => Thread.Sleep(3000))) == 1) 
    ShowProgressDialog(); 
+0

En lugar de Thread.Sleep, sugeriría Task.Delay, para no poner todo el hilo en suspensión (es posible que varias tareas se ejecuten en el mismo hilo). – MCattle

+1

@MCattle: cierto. En el momento de escribir esta respuesta, Task.Delay no existía en el marco, y usar System.Threading.Timer complicaría demasiado las cosas para demostrar el principio simple que estaba tratando de mostrar. –

0

recomendado sin bloqueo solución y no hay nuevos temas:

try 
{ 
    var t = DoLongProcessAsync(); 
    if (await Task.WhenAny(t, Task.Delay(1000)) != t) ShowProgress(); 
    await t; 
} 
finally 
{ 
    HideProgress(); 
} 
Cuestiones relacionadas