2008-12-01 11 views
8

In einem WPF-Benutzersteuerelement muss ich einen Aufruf an einen WebService vornehmen. Ich mache diesen Anruf auf einem separaten Thread, aber ich möchte den Benutzer informieren, dass der Anruf einige Zeit dauern kann.So zeigen Sie eine Fortschrittsleiste über einem Steuerelement in WPF

Die WebMethod gibt mir eine Sammlung von Objekten zurück und ich binde es an eine ListBox in meinem UC. So weit, so gut ... Dieser Teil funktioniert wirklich gut. Jedoch, Ich möchte einen Fortschrittsbalken (oder eine Animation aller Art ...) während des Anrufs anzeigen. Diese Animation wäre oben und zentriert im ListBox-Steuerelement.

Ich versuchte Adorner und es funktioniert teilweise. Allerdings muss ich alle Steuerelemente im geschützten Override zeichnen void OnRender (DrawingContext drawingContext) ... Ich möchte einfach ein Steuerelement für ein paar Sekunden hinzufügen ...

Jeder hat eine Idee, wie ich das erreichen könnte?

Danke!

Antwort

9

Nicht mit dem Adorner gehen - was ich tue, habe zwei separate Container-Steuerelemente (normalerweise Raster), die den gleichen Bereich des Bildschirms belegen. Einer ist meine "Fortschritt" -Kontrolle und der andere ist meine "Inhalts" -Kontrolle. Ich habe die Sichtbarkeit des Fortschrittssteuerelements auf "Eingeschaltet" und die Sichtbarkeit des Inhaltssteuerelements standardmäßig auf "Sichtbar" festgelegt.

Wenn Sie dies so eingerichtet haben, können Sie beim Starten des asynchronen Aufrufs zum Webservice die Fortschrittskontrolle sichtbar machen und das Inhaltssteuerelement reduzieren. Wenn der Webservice fertig ist, verwenden Sie Dispatcher.BeginInvoke, um die Benutzeroberfläche zu aktualisieren, und schalten Sie dann die Fortschrittskontrolle wieder auf "Collapsed" und die Inhaltskontrolle auf "sichtbar" zurück.

Ich mache im Allgemeinen die Fortschrittskontrolle unbestimmt. Hier ist ein Beispiel; In diesem habe ich eine separate UserControl namens ProgressGrid, die meine Fortschrittsanzeige hat.

<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> 

Und in der Code-behind, nur einfach so etwas wie diese:

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

Wow! Gute Antwort! Wie zentriere ich das ProgressBar-Steuerelement in der Mitte der ListBox mit Ihrer Lösung? Segeltuch? – Martin

+0

Hmm - Sie können das Fortschrittsfeld als untergeordnetes Element der ListBox definieren und alle anderen Elemente innerhalb der Sichtbarkeitsliste des Listenfelds auf reduziert setzen. Wenn Sie das Fortschrittsfeld nicht benötigen, legen Sie die Sichtbarkeit auf minimiert fest. –

+0

Oder Sie könnten die ListBox ein Child eines anderen Containers, wie ein Raster, und die Fortschrittsanzeige ein Geschwister der ListBox sein - dann können Sie einfach die horizontale und vertikale Ausrichtung der Fortschrittsanzeige auf "Center" setzen, und es wird zentriert, wenn es sichtbar gemacht wird. –

1

Es gibt einen Trick, den Sie mit einer Nullhöhe Leinwand verwenden kann, die funktionieren könnten. Chris Andersons WPF-Buch geht hierauf ins Detail und warum es funktioniert, aber es geht so.

  • erstellen Stackpanel
  • eine Leinwand mit Height = "0" und einem hohen Z-Index auf den Plattenstapel hinzufügen
  • auf den Stack Panel Benutzersteuerelement hinzufügen.

Wenn Sie den Fortschrittsbalken anzeigen möchten, fügen Sie ihn dem Nullhöhe-Canvas hinzu. Es ermöglicht Ihnen, es über das Benutzersteuerelement zu positionieren. Mit Canvas können Sie über seine Grenzen hinausgehen. Das Zentrieren der Fortschrittsleiste sollte nur die Dimensionen des Benutzersteuerelements anzeigen und die Position des Fortschrittsbalkens in dem Canvas entsprechend festlegen. Entfernen Sie den Fortschrittsbalken aus der Leinwand, wenn Sie fertig sind.

Hier ist ein einfaches Beispiel, das eine TextBox verwendet. Es ist nicht perfekt, aber es zeigt die Idee. Klicken Sie auf die Schaltfläche zeigt die TextBox auf der 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); 
}