2008-12-01 8 views
8

En un UserControl de WPF, tengo que hacer una llamada a un servicio web. Estoy haciendo esta llamada en un hilo separado, pero quiero informar al usuario que la llamada puede tomar algo de tiempo.Cómo mostrar una barra de progreso en la parte superior de un control en WPF

El WebMethod me devuelve una colección de objetos y lo enlace a un ListBox en mi UC. Hasta ahora, muy bien ... Esta parte funciona realmente bien. Sin embargo, Quiero mostrar una barra de progreso (o una animación de cualquier tipo ...) durante la llamada. Esta animación estaría en la parte superior y centrada en el control ListBox.

Probé con Adorner y funciona parcialmente. Sin embargo, tengo que dibujar todos los controles en override anulado vacío OnRender (DrawingContext drawingContext) ... Simplemente quiero agregar un control por un par de segundos ...

¿Alguien tiene una idea de cómo podría lograr esto?

Gracias!

Respuesta

9

No vaya con el adorner - lo que hago es tener dos controles de contenedor separados (generalmente cuadrículas) que ocupan la misma área de la pantalla. Uno es mi control de "progreso" y el otro es mi control de "contenido". Establecí la visibilidad del control de progreso en Contraído y la visibilidad del control de contenido en Visible de forma predeterminada.

Si lo tiene configurado de esa manera, cuando inicia la llamada asincrónica al servicio web puede hacer visible el control de progreso y el control de contenido colapsado. Cuando finalice el servicio web, haga que use Dispatcher.BeginInvoke para actualizar la interfaz de usuario, y en ese punto, vuelva a colocar el control de progreso para colapsar y el control de contenido vuelva a ser visible.

En general, hago que el control de progreso sea indeterminado. Aquí hay un ejemplo; en esto, tengo un UserControl separado llamado ProgressGrid que tiene mi barra de progreso.

<Grid x:Name="layoutRoot"> 
     <Grid x:Name="contentGrid" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Visible"> 
      <!-- snip --> 
     </Grid> 

     <controls:ProgressGrid x:Name="progressGrid" Text="Signing in, please wait..." Visibility="Collapsed"/> 
    </Grid> 

Y en el código detrás, algo tan simple como esto:

private void SignInCommand_Executed(object sender, ExecutedRoutedEventArgs e) 
    { 
     contentGrid.Visibility = Visibility.Collapsed; 
     progressGrid.Visibility = Visibility.Visible; 
    } 
+0

¡Guau! ¡Gran respuesta! Sin embargo, con su solución, ¿cómo centro el control ProgressBar en el centro de ListBox? ¿Lona? – Martin

+0

Hmm: podría hacer que el panel de progreso sea un elemento secundario de ListBox y establecer el resto de elementos dentro de la visibilidad del cuadro de lista para colapsarse, y cuando no necesite el panel de progreso, establezca que su visibilidad se colapsó. –

+0

O podría hacer que el ListBox sea hijo de un contenedor diferente, como una cuadrícula, y hacer que el panel de progreso sea un hermano del ListBox; luego, puede establecer la alineación horizontal y vertical del panel de progreso en "Centro", y estará centrado cuando se haga visible. –

1

Hay un truco que puede utilizar con un lienzo altura cero que podría funcionar. El libro WPF de Chris Anderson entra en detalles sobre esto y por qué funciona, pero es algo como esto.

  • crear un StackPanel
  • añadir una lona con la Altura = "0" y un alto índice z al panel pila
  • añadir el control de usuario al panel de pila.

Cuando quiera mostrar la barra de progreso, agréguelo al lienzo de altura cero. Le permitirá ubicarlo sobre el control del usuario. Canvas le permite ir más allá de sus fronteras. Centrar la barra de progreso solo debería requerir observar las dimensiones del control del usuario y establecer la posición de la barra de progreso en el Lienzo en consecuencia. Retire la barra de progreso del lienzo cuando haya terminado.

Aquí hay un ejemplo simple que usa un TextBox. No es perfecto, pero muestra la idea. Hacer clic en el botón muestra el cuadro de texto en la parte superior de la InkCanvas

<DockPanel LastChildFill="True"> 
    <Button DockPanel.Dock="Top" Name="showButton" Click="showProgress">show</Button> 
    <StackPanel DockPanel.Dock="Bottom"> 
     <Canvas Name="zeroHeight" Height="0"/> 
     <InkCanvas Name="inky"> 
     </InkCanvas> 
    </StackPanel> 
</DockPanel> 


private void showProgress(object sender, RoutedEventArgs e) 
{ 
    TextBox box = new TextBox(); 
    box.Text = "on top"; 
    StackPanel.SetZIndex(zeroHeight, 8); 
    zeroHeight.Children.Add(box); 
    box.Width = 30; 
    box.Height = 30; 
    Canvas.SetLeft(box, 10); 
    Canvas.SetTop(box, 10); 
    Canvas.SetZIndex(box, 10); 
} 
Cuestiones relacionadas