Question

In a WPF UserControl, I have to make to call to a WebService. I am making this call on a separate thread but I want to inform the user that the call may take some time.

The WebMethod returns me a collection of objects and I bind it to a ListBox in my UC. So far, so good... This part works really well. However, I want to display a progress bar (or an animation of any kind...) during the call. This animation would be on top and centered in the ListBox control.

I tried Adorner and it partially works. However, I have to draw all controls in protected override void OnRender(DrawingContext drawingContext)... I simply want to add a control for a couple of seconds...

Anybody has an idea of how I could achieve this?

Thanks!

Was it helpful?

Solution

Don't go with the adorner - what I do is have two separate container controls (usually grids) that occupy the same area of the screen. One is my "progress" control, and the other is my "content" control. I set the visibility of the progress control to Collapsed and the visibility of the content control to Visible by default.

If you have it set up that way, when you start the asynchronous call to the webservice you can make the progress control visible and the content control collapsed. When the webservice finishes, have it use Dispatcher.BeginInvoke to update the UI, and at that point, switch the progress control back to collapsed and the content control back to visible.

I generally make the progress control indeterminate. Here is an example; in this, I have a separate UserControl called ProgressGrid that has my progress bar.

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

And in the code behind, just something simple like this:

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

OTHER TIPS

There is a trick you can use with a zero height Canvas that might work. Chris Anderson's WPF book goes into detail on this and why it works, but it goes something like this.

  • create a StackPanel
  • add a Canvas with Height="0" and a high z-index to the stack panel
  • add your user control to the stack panel.

When you want to show the progress bar add it to the zero height canvas. It will allow you to position it over the user control. Canvas allows you to go beyond its borders. Centering the progress bar should just require looking at the dimensions of the user control and setting the position of the progress bar on the Canvas accordingly. Remove the progress bar from the canvas when you are done.

Here is a simple example that uses a TextBox. It's not perfect but it shows the idea. Clicking the button shows the TextBox on top of the 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);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top