2012-01-03 16 views
8

Tengo una aplicación wpf que realiza acciones muy pesadas en las que el usuario necesita esperar mientras la aplicación "piensa".Superposición de efecto "ocupado"

Lo que quiero hacer es, mientras que el hilo principal de la aplicación está pensando, otro hilo desactivará toda la ventana y le dará un tipo de color grisáceo y una barra de progreso circular aparecerá en el centro de la pantalla.

Es una gran pregunta y realmente no necesito todo el código para hacer esto solo la Idea general.

Gracias por toda su ayuda ..

Respuesta

2

descarga de la acción pesada para un nuevo hilo y hacer las cosas de la interfaz de usuario (desactivar, en gris y la barra de progreso) en el hilo principal. Ver BackgroundWorker and Dispatcher.

Es posible utilizar un nuevo hilo para la interfaz de usuario, pero no se está utilizando la ventana existente. Un control de interfaz de usuario (Dispatcher) puede ser usado/llamado en línea por el hilo al que pertenece. Sin embargo, podría crear un nuevo hilo y usar una nueva Ventana con un nuevo Dispatcher para hacer las cosas de la interfaz de usuario. Debería colocar la nueva ventana sobre el original. No es tan fácil como mi primera sugerencia. Podría ser una opción si no sabe cuándo se ejecuta la acción intensa. Ver here, here y here.

+0

Muchas gracias, esto fue extremadamente útil. –

3

Uso Dispatcher.BeginInvoke para cambiar el Enable-Propiedad de los componentes de interfaz de usuario y mostrar/ocultar el progressbar fuera del subproceso de trabajo

para el trabajador-hilo se puede utilizar el BackgroundWorker-Class

+0

Muchas gracias, ¡esto fue extremadamente útil! –

2

Tome un vistazo a este muestra:

public void DoHeavyWork() 
    { 
     mainDispatcher = Dispatcher.CurrentDispatcher; 
     DisableWindow(); 
     workDelegate.BeginInvoke(EnableWindowCallBack, null); 
    } 

    private void EnableWindowCallBack(IAsyncResult asyncResult) 
    { 
     workDelegate.EndInvoke(asyncResult); 
     mainDispatcher.InvokeIfRequired(() => { EnableWindow(); }); 
    } 

Cuando se llama a DoHeavyWork que supongo que estamos en el hilo que tiene acceso a la interfaz de usuario, que debe ser el habitual. DisableWindow muestra la animación o lo que se debe mostrar mientras se trabaja. Luego invocará a su delegado predefinido, workDelegate, que se ejecutará en un nuevo hilo, y cuando lo haya hecho, la devolución de llamada debería restaurar la vista.

Tenga en cuenta que la llamada a EnableWindow tiene que hacerse en la secuencia que tiene acceso a la interfaz de usuario.

+0

¡Muchas gracias, esto fue extremadamente útil! –

+0

Me alegra ser de ayuda. Puede mostrar su agradecimiento al votar y aceptar una de las respuestas como la respuesta correcta. –

12

Además de las sugerencias anteriores (Trabajador de fondo, Despachador): sí, estas son las técnicas correctas para obtener lo que desea, pero permítame hablar sobre el efecto de IU que solicitó en su pregunta. Si está utilizando el patrón MVVM, puede crear una IU "Estoy ocupado" y enlazar a una propiedad IsBusy en el modelo de vista para mostrar y ocultar la IU. Por ejemplo:

public class MyViewModel : INotifyPropertyChanged 
{ 
    // Bind to this property any UI you want to 
    // show/hide during long running updates 
    public bool IsBusy 
    { 
     get { return _isBusy; } 
     set 
     { 
      _isBusy = true; 
      OnPropertyChanged("IsBusy"); 
     } 
    } 

    private void OnPropertyChanged(string prop) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(prop)); 
     } 
    } 

    // Note: This is intended to be called on a background thread 
    private void DoLongRunningOperationOnABackgroundThread() 
    { 
     try 
     { 
      IsBusy = true; 

      // do your work 
     } 
     finally 
     { 
      IsBusy = false; 
     } 
    } 
} 

Luego, en el uso de interfaz de usuario de este xaml (o similar)

<UserControl:MyControl x:Class="MyApp.MyControl" 
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <UserControl.Resources> 
     <BooleanToVisibilityConverter x:Key="boolToVis"/> 
    </UserControl.Resources> 
    <Grid> 
     <!-- your UI code goes here --> 

     <!-- Below this, at higher Z-Order place a control to gray out the screen when IsBusy = true --> 
     <Border Background="#55000000" BorderThickness="0" Visibility="{Binding IsBusy, Converter={StaticResource boolToVis}}"> 
      <TextBlock Text="I AM BUSY!" Font-Size="32" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White"/> 
     </Border> 
    <Grid> 
</UserControl>  

El efecto neto será cuando se utiliza un trabajador o subprocesos de fondo para llamar a la función DoLongRunningOperation en su modelo de vista, el borde definido en Xaml se mostrará/ocultará cuando la operación comience/se detenga. No necesitará que el despachador invoque aquí, ya que WPF maneja la clasificación de subprocesos por usted.

Hay implementaciones de controles ocupados con animaciones de whirlygig, etc ... en la red también para darle vida a la interfaz de usuario.

Saludos cordiales,

+0

Gracias, he encontrado algunas implementaciones de animaciones geniales en línea gracias mucho –

+0

Sin problemas :) Simplemente tenga en cuenta que puede utilizar WPF Grid para colocar un control directamente sobre otro control (más alto en el índice Z). Esto es muy útil para el efecto de apagón que está buscando. –