Introduction
This is a simple but effective Busyindicator style. The difference is in the new look instead of the boring standard looking progressbars.
How to do it
The progressbar consists of 8 pieces (paths) which appear and disappear, arranged in a circle.
- First, we need to build the paths. That is very easy with the help of Expression Blend 4.
- Create a new project and add two circles, the second smaller than the first, but both centered each other. Then add four rectangles on top of them like this:
- Now use the context menu from Blend to subtract the smaller ellipse from the bigger one, and then the rectangles from the result.
- Now you need to release the compound path:
And here is the result:
Then group all the paths in a grid and in a ViewBox
. This will help the figures preserve their shape and be automatically resized.
- The last thing to do is to add the appropriate timeline and animation preferences for each path.
Here is the XAML:
<Style TargetType="toolkit:BusyIndicator">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Background" Value="{StaticResource Brush5}"/>
<Setter Property="BusyContent" Value="Please wait..."/>
<Setter Property="FontFamily"
Value="{StaticResource FontFamily1}"/>
<Setter Property="FontSize" Value="{StaticResource FontSize1}"/>
<Setter Property="Foreground" Value="{StaticResource Brush2}"/>
<Setter Property="DisplayAfter" Value="00:00:00.1"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="OverlayStyle">
<Setter.Value>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="White"/>
<Setter Property="Opacity" Value="0.6"/>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ProgressBarStyle">
<Setter.Value>
<Style TargetType="ProgressBar">
<Setter Property="Background"
Value="{StaticResource Brush1}"/>
<Setter Property="Foreground"
Value="{StaticResource Brush2}"/>
<Setter Property="IsIndeterminate"
Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Grid>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualState x:Name="Determinate"/>
<vsm:VisualState x:Name="Indeterminate">
<Storyboard BeginTime="0:0:0.15"
Duration="0:0:2.4"
RepeatBehavior="Forever" >
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="p1"
Storyboard.TargetProperty=
"Opacity">
<LinearDoubleKeyFrame
KeyTime="0:0:0.15"
Value="0"/>
<LinearDoubleKeyFrame
KeyTime="0:0:0.26"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.35"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.46"
Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="p2"
Storyboard.TargetProperty=
"Opacity">
<LinearDoubleKeyFrame
KeyTime="0:0:0.30"
Value="0"/>
<LinearDoubleKeyFrame
KeyTime="0:0:0.41"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.50"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.61"
Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="p3"
Storyboard.TargetProperty=
"Opacity">
<LinearDoubleKeyFrame
KeyTime="0:0:0.45"
Value="0"/>
<LinearDoubleKeyFrame
KeyTime="0:0:0.56"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.65"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.76"
Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="p4"
Storyboard.TargetProperty=
"Opacity">
<LinearDoubleKeyFrame
KeyTime="0:0:0.60"
Value="0"/>
<LinearDoubleKeyFrame
KeyTime="0:0:0.71"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.80"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.91"
Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="p5"
Storyboard.TargetProperty=
"Opacity">
<LinearDoubleKeyFrame
KeyTime="0:0:0.75"
Value="0"/>
<LinearDoubleKeyFrame
KeyTime="0:0:0.86"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.95"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:2.06"
Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="p6"
Storyboard.TargetProperty=
"Opacity">
<LinearDoubleKeyFrame
KeyTime="0:0:0.90"
Value="0"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.01"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:2.10"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:2.21"
Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="p7"
Storyboard.TargetProperty=
"Opacity">
<LinearDoubleKeyFrame
KeyTime="0:0:1.05"
Value="0"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.16"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:2.25"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:2.36"
Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="p8"
Storyboard.TargetProperty=
"Opacity">
<LinearDoubleKeyFrame
KeyTime="0:0:1.20"
Value="0"/>
<LinearDoubleKeyFrame
KeyTime="0:0:1.31"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:2.40"
Value="1"/>
<LinearDoubleKeyFrame
KeyTime="0:0:2.40"
Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Viewbox>
<Grid Height="35" Width="35">
<Path x:Name="p5" Opacity="0"
Data="M5.3666506,0.5000003
L5.7133517,0.72223777
C6.6946535,1.3184171
7.7845569,1.7536836
8.9464264,1.9914073
L8.9809875,1.998026
L8.9809875,8.876935
L8.8369169,8.8604708
C5.7175508,8.4639959
2.862067,7.2222071
0.50738931,5.3719926
L0.5,5.3660407 z"
Margin="6.496,0,0,0.124"
Stretch="Fill"
Stroke="#FF7E7E7E"
UseLayoutRounding="False"
HorizontalAlignment="Left"
Height="9.377"
VerticalAlignment="Bottom"
Width="9.481"
StrokeThickness="0"
Fill="{TemplateBinding Background}"/>
<Path x:Name="p4" Opacity="0"
Data="M4.1121063,0.5000006
L8.9784365,5.3657207
L8.9678411,5.3742528
C6.6131639,7.2244673
3.7576799,8.4662561
0.63831252,8.862731
L0.50000048,8.8785391
L0.50000048,1.999184
L0.52880186,1.9936675
C1.6906725,1.7559438
2.7805767,1.3206773
3.761878,0.72449797 z"
Margin="0,0,6.497,0.124"
Stretch="Fill"
Stroke="#FF7E7E7E"
UseLayoutRounding="False"
HorizontalAlignment="Right"
Height="9.379"
VerticalAlignment="Bottom"
Width="9.478"
StrokeThickness="0"
Fill="{TemplateBinding Background}"/>
<Path x:Name="p3" Opacity="0"
Data="M1.9976557,0.5 L8.8776493,
0.5 L8.8615131,
0.64116967 C8.4649878,
3.7601461 7.2230439,
6.615272 5.3725972,8.969655
L5.366652,8.9770346
L0.5,4.110992 L0.7222597,
3.7643437 C1.3185138,
2.7831655 1.7538347,1.6933979
1.9915864,0.53167284 z"
Margin="0,0,0.124,6.499"
Stretch="Fill"
Stroke="#FF7E7E7E"
UseLayoutRounding="False"
HorizontalAlignment="Right"
Height="9.477"
VerticalAlignment="Bottom"
Width="9.378" StrokeThickness="0"
Fill="{TemplateBinding Background}"/>
<Path x:Name="p6" Opacity="0"
Data="M0.5,0.5 L7.3799934,
0.5 L7.3860626,
0.53167284 C7.623816,
1.6933979 8.0591364,
2.7831655 8.6553907,
3.7643437 L8.8799105,
4.1145191 L4.0135803,
8.9802399 L4.0050535,
8.969655 C2.1546073,
6.615272 0.91266096,
3.7601461 0.51613933,
0.64116967 z"
Margin="0.12,0,0,6.496"
Stretch="Fill" Stroke="#FF7E7E7E"
UseLayoutRounding="False"
HorizontalAlignment="Left" Height="9.48"
VerticalAlignment="Bottom"
Width="9.38" StrokeThickness="0"
Fill="{TemplateBinding Background}"/>
<Path x:Name="p2" Opacity="0"
Data="M5.3666501,0.50000006
L5.3726025,0.50738847
C7.2230492,2.8617713
8.4649935,5.7168975
8.8615189,8.8358727
L8.877655,8.9770498
L1.9976631,8.9770498
L1.991592,8.9453697
C1.7538403,7.7836447
1.3185194,6.6938791
0.72226524,5.7126989
L0.5,5.3660417 z"
Margin="0,6.499,0.124,0"
Stretch="Fill" Stroke="#FF7E7E7E"
UseLayoutRounding="False"
HorizontalAlignment="Right"
Height="9.477"
VerticalAlignment="Top"
Width="9.378" StrokeThickness="0"
Fill="{TemplateBinding Background}"/>
<Path x:Name="p7" Opacity="0"
Data="M4.013588,0.50000024
L8.8799181,5.3657212
L8.6553917,5.7159047
C8.0591364,6.6970849
7.6238165,7.7868505
7.3860636,8.948576
L7.379993,8.9802561 L0.5,
8.9802561 L0.51614022,
8.8390789 C0.91266179,
5.7201033 2.154608,
2.8649771 4.0050545,
0.51059425 z"
Margin="0.12,6.496,0,0"
Stretch="Fill" Stroke="#FF7E7E7E"
UseLayoutRounding="False"
HorizontalAlignment="Left"
Height="9.48"
VerticalAlignment="Top"
Width="9.38" StrokeThickness="0"
Fill="{TemplateBinding Background}"/>
<Path x:Name="p1" Opacity="0"
Data="M0.50000048,
0.5 L0.63831252,0.5158087
C3.7576799,0.91228062
6.6131639,2.1540713 8.9678411,
4.0042858 L8.9784269,
4.0128117 L4.1120973,8.8785334
L3.761878,8.6540403 C2.7805767,
8.0578604 1.6906725,
7.6225948 0.52880186,7.3848715
L0.50000048,7.379354 z"
Margin="0,0.125,6.497,0"
Stretch="Fill"
Stroke="#FF7E7E7E"
UseLayoutRounding="False"
HorizontalAlignment="Right"
Height="9.379"
VerticalAlignment="Top"
Width="9.478"
StrokeThickness="0"
Fill="{TemplateBinding Background}"/>
<Path x:Name="p8" Opacity="0"
Data="M8.9809799,0.5
L8.9809799,7.3789091
L8.9464188,7.3855295
C7.7845492,7.6232529
6.6946459,8.0585184
5.7133441,8.6546984
L5.366652,8.8769302
L0.50000006,4.0108881
L0.50738156,4.0049438
C2.8620591,2.1547294
5.7175431,0.91293871 8.8369093,
0.5164668 z"
Margin="6.496,0.124,0,0"
Stretch="Fill"
Stroke="#FF7E7E7E"
UseLayoutRounding="False"
HorizontalAlignment="Left"
Height="9.377"
VerticalAlignment="Top"
Width="9.481" StrokeThickness="0"
Fill="{TemplateBinding Background}"/>
</Grid>
</Viewbox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:BusyIndicator">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisibilityStates">
<VisualState x:Name="Hidden">
<Storyboard>
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:00"
Duration="00:00:00.001"
Storyboard.TargetProperty=
"(UIElement.Visibility)"
Storyboard.TargetName="busycontent">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:00"
Duration="00:00:00.001"
Storyboard.TargetProperty=
"(UIElement.Visibility)"
Storyboard.TargetName="overlay">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Visible">
<Storyboard>
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:00"
Duration="00:00:00.001"
Storyboard.TargetProperty=
"(UIElement.Visibility)"
Storyboard.TargetName="busycontent">
<DiscreteObjectKeyFrame
KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:00"
Duration="00:00:00.001"
Storyboard.TargetProperty=
"(UIElement.Visibility)"
Storyboard.TargetName="overlay">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="BusyStatusStates">
<VisualState x:Name="Idle">
<Storyboard>
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:00"
Duration="00:00:00.001"
Storyboard.TargetProperty=
"(Control.IsEnabled)"
Storyboard.TargetName="content">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>True</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Busy">
<Storyboard>
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:00"
Duration="00:00:00.001"
Storyboard.TargetProperty=
"(Control.IsEnabled)"
Storyboard.TargetName="content">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>False
</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl x:Name="content"
Content="{TemplateBinding Content}"
HorizontalAlignment=
"{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment=
"{TemplateBinding VerticalContentAlignment}"
ContentTemplate=
"{TemplateBinding ContentTemplate}"/>
<Rectangle x:Name="overlay"
Style="{TemplateBinding OverlayStyle}"
d:IsHidden="True"/>
<ContentPresenter x:Name="busycontent">
<Border Background="{TemplateBinding Background}"
CornerRadius="4"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Border.Effect>
<DropShadowEffect Opacity="0.6"
BlurRadius="6" ShadowDepth="0" />
</Border.Effect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentControl
Content="{TemplateBinding BusyContent}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{TemplateBinding Foreground}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
ContentTemplate=
"{TemplateBinding BusyContentTemplate}"
Grid.Row="0" Margin="5 5 5 2"/>
<ProgressBar
Style="{TemplateBinding ProgressBarStyle}"
Height="45"
Width="45" Grid.Row="2"
IsIndeterminate="True"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="5 2 5 5"/>
</Grid>
</Border>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can not paste this code exactly and expect it to work. There are some custom resources like brushes and other defined parameters outside, but you can edit it easily and make it work for you.
How it works
If you have tested the control online, you might have noticed that the pieces of the graphics appear and disappear this way: one by one, the eight graphics appear in clockwise direction until all of them appear, then begin disappearing in the same direction one by on until they all disappear. The animation continues forever in the same order.
All these motions are defined in the VSM part of the ProgressBar style in indeterminate state. There is no code-behind or any other sources, only XAML.
You can download all the source as well as other control styles from here.