Show the user that a time consuming operation is taking place in the background, while restricting the user interface input.
Nice to have:
A generic solution that can be reused.
Solutions?
The first thing that popped into mind was to show a modal window with some sort of a loading animation and a status text. But the interface to work with, was already in a modal window, so I thought of creating a mask over the existing interface. Now I think this idea came up from the ASP.net field; I remembered the Ajax/Java Script implementation for this effect.
I thought about how it could be done, but then I decided to look a bit over the web, to see what's the most popular way of doing this. I found some articles related to using the Adorner class. But looking over the implementations, it seemed over-complicated, with too much code for what I needed. I felt it could be done simpler with much more xaml, and much less code.
So I did. I started noting down what kind of visual tree structure would be needed. Then I wrote a short class called LoaderLayer, that derives from content control, and which contains two dependency properties called IsLoadingVisible and LoadingText.
Then I defined a simple style for it, with a content which has over it a rectangle, an animation and a status label.
The content will be whatever we want to show is busy, the visibility of the loading layer will be controlled by IsLoadingVisible and the status text will be binded to LoadingText.
I must admit, I have a hard trouble designing something visual that's out of the order, like say... a loading animation. Given this fact, I got the loading animation from A Simple WPF Loading Animation . I thought this looks like a respectable and stylish animation, but you can easily change it if you'd like.
And.. after a few more lines of xaml and code later, this is the result:
The control template is what I find most important:
<ControlTemplate TargetType="{x:Type local:LoaderLayer}"> <Grid> <ContentPresenter Name="Content" Content="{TemplateBinding Content}" /> <Grid Visibility="{TemplateBinding IsLoadingVisible, Converter={StaticResource BoolToVisibilityConverter}}"> <Rectangle Opacity="0.7" Fill="{StaticResource LoadingLayerGradient}" /> <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Focusable="False"> <local:LoadingAnimation /> <TextBlock Text="{TemplateBinding LoadingText}" FontWeight="Bold" HorizontalAlignment="Center" Margin="0, 20, 0, 0" /> </StackPanel> </Grid> </Grid> </ControlTemplate>
It is very straight forward. The control template has a rectangle and a stack panel right over it's content. The rectangle will act as a mask over the content, and the stack panel will contain some information for the user. Like a loading animation (could also show some percentage of how much is done, if available), and a status text.
The LoaderLayer, as I call it, can be used for an entire window, or just for some inner controls.
The demo project can be found here. Enjoy!

No comments:
Post a Comment