locked
BusyIndicator for Blend/SketchFlow Silverlight web app prototype? RRS feed

Answers

  • You can still get what you want, you just have to edit the template to suit your needs.  Since the base functionality is there.

    Here is what I did to make a simple spinning busy indicator:

    1. Follow the directions in that first page to get a basic busy indicator working so you can display it
    2. Right click the busy indicator, select edit template, edit a copy
    3. Inside the template, find the progress bar, and delete it
    4. If you want to remove the gray box, move the Content presenter up to a higher grid, and delete the border objects
    5. In that grid, I made an ellpise that surrounded the text
    6. I set the stroke to a gradient so the top was black, and the bottom faded to white and 0 alpha, thickness of 15
    7. To make it spin, select the states panel, and go to the visible state
    8. Expand the timeline in the objects and timeline panel
    9. Select the ellipse, and add a keyframe at both 0 and 1 sec
    10. Select the 1 sec mark, and go rotate the ellipse 360 degrees (aided by the shift key to get exactly 360)
    11. Expand the nodes under ellipse and select angle, right click the gray bar in the timeline and select repeat count, and set it to infinity using the button

    That is a little dense, so here is a quick screen recording of those steps:
    http://chuckhays.net/bitemplate/

    And my xaml after those steps:
    <UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit" xmlns:System="clr-namespace:System;assembly=mscorlib"
    x:Class="SilverlightPrototype16Screens.Screen_1"
    Width="640" Height="480">

    <UserControl.Resources>
    <Style x:Key="BusyIndicatorStyle1" TargetType="controlsToolkit:BusyIndicator">
    <Setter Property="BusyContent" Value="Please wait..."/>
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="OverlayStyle">
    <Setter.Value>
    <Style TargetType="Rectangle">
    <Setter Property="Fill" Value="White"/>
    <Setter Property="Opacity" Value="0.5"/>
    </Style>
    </Setter.Value>
    </Setter>
    <Setter Property="ProgressBarStyle">
    <Setter.Value>
    <Style TargetType="ProgressBar">
    <Setter Property="IsIndeterminate" Value="True"/>
    <Setter Property="Height" Value="15"/>
    <Setter Property="Margin" Value="8,0,8,8"/>
    </Style>
    </Setter.Value>
    </Setter>
    <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="Template">
    <Setter.Value>
    <ControlTemplate TargetType="controlsToolkit:BusyIndicator">
    <Grid>
    <VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="VisibilityStates">
    <VisualState x:Name="Hidden">
    <Storyboard>
    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="busycontent" Storyboard.TargetProperty="(UIElement.Visibility)">
    <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.TargetName="overlay" Storyboard.TargetProperty="(UIElement.Visibility)">
    <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.TargetName="busycontent" Storyboard.TargetProperty="(UIElement.Visibility)">
    <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.TargetName="overlay" Storyboard.TargetProperty="(UIElement.Visibility)">
    <DiscreteObjectKeyFrame KeyTime="00:00:00">
    <DiscreteObjectKeyFrame.Value>
    <Visibility>Visible</Visibility>
    </DiscreteObjectKeyFrame.Value>
    </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" RepeatBehavior="Forever">
    <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    <EasingDoubleKeyFrame KeyTime="00:00:01" Value="360"/>
    </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    </VisualState>
    </VisualStateGroup>
    <VisualStateGroup x:Name="BusyStatusStates">
    <VisualState x:Name="Idle">
    <Storyboard>
    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="content" Storyboard.TargetProperty="(Control.IsEnabled)">
    <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.TargetName="content" Storyboard.TargetProperty="(Control.IsEnabled)">
    <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" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
    <Rectangle x:Name="overlay" Style="{TemplateBinding OverlayStyle}"/>
    <ContentPresenter x:Name="busycontent">
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    <Ellipse x:Name="ellipse" Margin="-13,-46,-15,-44" StrokeThickness="15" RenderTransformOrigin="0.5,0.5">
    <Ellipse.RenderTransform>
    <TransformGroup>
    <ScaleTransform/>
    <SkewTransform/>
    <RotateTransform/>
    <TranslateTransform/>
    </TransformGroup>
    </Ellipse.RenderTransform>
    <Ellipse.Stroke>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="Black" Offset="0"/>
    <GradientStop Color="Transparent" Offset="0.94"/>
    </LinearGradientBrush>
    </Ellipse.Stroke>
    </Ellipse>
    <ContentPresenter Margin="8,8,12,8" Content="{TemplateBinding BusyContent}" ContentTemplate="{TemplateBinding BusyContentTemplate}"/>
    </Grid>
    </ContentPresenter>
    </Grid>
    </ControlTemplate>
    </Setter.Value>
    </Setter>
    </Style>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">
    <Button Height="57" HorizontalAlignment="Left" Margin="52,47,0,0" VerticalAlignment="Top" Width="127" Content="Button" Click="DoBusy"/>
    <controlsToolkit:BusyIndicator x:Name="BusyWindow" Style="{StaticResource BusyIndicatorStyle1}"/>
    </Grid>
    </UserControl>

    • Proposed as answer by Chuck HaysModerator Tuesday, February 23, 2010 3:17 PM
    • Marked as answer by GClaes Thursday, February 25, 2010 8:13 AM
    Tuesday, February 23, 2010 3:16 PM
    Moderator

All replies

  • The SLToolkit team released one:

    http://www.c-sharpcorner.com/UploadFile/dpatra/BusyIndicatorControlInSilverlight311222009134928PM/BusyIndicatorControlInSilverlight3.aspx has some info.

    This is the SLToolkit page:
    http://www.codeplex.com/Silverlight
    • Proposed as answer by Chuck HaysModerator Monday, February 22, 2010 2:57 PM
    • Unproposed as answer by GClaes Tuesday, February 23, 2010 8:05 AM
    Monday, February 22, 2010 2:57 PM
    Moderator
  • Hi Chuck,  I just had a closer look at the SLToolkit and I can't find any circular progress indicator at all.  It does have a plain "Please wait" with busy progress bar (windows type busy indicator) but that's not really what I was after.  I am more looking for a typical web app busy indicator not a progress bar.
    Tuesday, February 23, 2010 8:11 AM
  • You can still get what you want, you just have to edit the template to suit your needs.  Since the base functionality is there.

    Here is what I did to make a simple spinning busy indicator:

    1. Follow the directions in that first page to get a basic busy indicator working so you can display it
    2. Right click the busy indicator, select edit template, edit a copy
    3. Inside the template, find the progress bar, and delete it
    4. If you want to remove the gray box, move the Content presenter up to a higher grid, and delete the border objects
    5. In that grid, I made an ellpise that surrounded the text
    6. I set the stroke to a gradient so the top was black, and the bottom faded to white and 0 alpha, thickness of 15
    7. To make it spin, select the states panel, and go to the visible state
    8. Expand the timeline in the objects and timeline panel
    9. Select the ellipse, and add a keyframe at both 0 and 1 sec
    10. Select the 1 sec mark, and go rotate the ellipse 360 degrees (aided by the shift key to get exactly 360)
    11. Expand the nodes under ellipse and select angle, right click the gray bar in the timeline and select repeat count, and set it to infinity using the button

    That is a little dense, so here is a quick screen recording of those steps:
    http://chuckhays.net/bitemplate/

    And my xaml after those steps:
    <UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit" xmlns:System="clr-namespace:System;assembly=mscorlib"
    x:Class="SilverlightPrototype16Screens.Screen_1"
    Width="640" Height="480">

    <UserControl.Resources>
    <Style x:Key="BusyIndicatorStyle1" TargetType="controlsToolkit:BusyIndicator">
    <Setter Property="BusyContent" Value="Please wait..."/>
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="OverlayStyle">
    <Setter.Value>
    <Style TargetType="Rectangle">
    <Setter Property="Fill" Value="White"/>
    <Setter Property="Opacity" Value="0.5"/>
    </Style>
    </Setter.Value>
    </Setter>
    <Setter Property="ProgressBarStyle">
    <Setter.Value>
    <Style TargetType="ProgressBar">
    <Setter Property="IsIndeterminate" Value="True"/>
    <Setter Property="Height" Value="15"/>
    <Setter Property="Margin" Value="8,0,8,8"/>
    </Style>
    </Setter.Value>
    </Setter>
    <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="Template">
    <Setter.Value>
    <ControlTemplate TargetType="controlsToolkit:BusyIndicator">
    <Grid>
    <VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="VisibilityStates">
    <VisualState x:Name="Hidden">
    <Storyboard>
    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="busycontent" Storyboard.TargetProperty="(UIElement.Visibility)">
    <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.TargetName="overlay" Storyboard.TargetProperty="(UIElement.Visibility)">
    <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.TargetName="busycontent" Storyboard.TargetProperty="(UIElement.Visibility)">
    <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.TargetName="overlay" Storyboard.TargetProperty="(UIElement.Visibility)">
    <DiscreteObjectKeyFrame KeyTime="00:00:00">
    <DiscreteObjectKeyFrame.Value>
    <Visibility>Visible</Visibility>
    </DiscreteObjectKeyFrame.Value>
    </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" RepeatBehavior="Forever">
    <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    <EasingDoubleKeyFrame KeyTime="00:00:01" Value="360"/>
    </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    </VisualState>
    </VisualStateGroup>
    <VisualStateGroup x:Name="BusyStatusStates">
    <VisualState x:Name="Idle">
    <Storyboard>
    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="content" Storyboard.TargetProperty="(Control.IsEnabled)">
    <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.TargetName="content" Storyboard.TargetProperty="(Control.IsEnabled)">
    <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" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
    <Rectangle x:Name="overlay" Style="{TemplateBinding OverlayStyle}"/>
    <ContentPresenter x:Name="busycontent">
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    <Ellipse x:Name="ellipse" Margin="-13,-46,-15,-44" StrokeThickness="15" RenderTransformOrigin="0.5,0.5">
    <Ellipse.RenderTransform>
    <TransformGroup>
    <ScaleTransform/>
    <SkewTransform/>
    <RotateTransform/>
    <TranslateTransform/>
    </TransformGroup>
    </Ellipse.RenderTransform>
    <Ellipse.Stroke>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="Black" Offset="0"/>
    <GradientStop Color="Transparent" Offset="0.94"/>
    </LinearGradientBrush>
    </Ellipse.Stroke>
    </Ellipse>
    <ContentPresenter Margin="8,8,12,8" Content="{TemplateBinding BusyContent}" ContentTemplate="{TemplateBinding BusyContentTemplate}"/>
    </Grid>
    </ContentPresenter>
    </Grid>
    </ControlTemplate>
    </Setter.Value>
    </Setter>
    </Style>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">
    <Button Height="57" HorizontalAlignment="Left" Margin="52,47,0,0" VerticalAlignment="Top" Width="127" Content="Button" Click="DoBusy"/>
    <controlsToolkit:BusyIndicator x:Name="BusyWindow" Style="{StaticResource BusyIndicatorStyle1}"/>
    </Grid>
    </UserControl>

    • Proposed as answer by Chuck HaysModerator Tuesday, February 23, 2010 3:17 PM
    • Marked as answer by GClaes Thursday, February 25, 2010 8:13 AM
    Tuesday, February 23, 2010 3:16 PM
    Moderator
  • Hi Chuck, I really appreciate your help and in most cases you really solve the problem (not too happy with this work-around though).

    I am still testing and reviewing Blend/SketchFlow and I have to say that I am not too happy with Expression Blend/SketchFlow for several reasons:
    • As mentioned somewhere else, Expression Blend crashes at least 5 times a day
    • The naming, re-naming is just horrible and causes a lot of issues which require me to rename the objects myself in the XAML and C# code ... and quite frankly, I really don't want to
    • From a UxD point of view the tool is just too complex and has too many things missing with; a circular Busy Indicator (which is almost a new standard now, like the one when you submit a question on this forum, why is that so hard), GlobalState, Conditional Navigation and DataGrid row selection without putting a stupid box around the cell just being a few examples.
    Having said that I would really like to thank you (and others) for helping me with all the questions I am asking on this forum ... but why do I need to ask so many questions I wonder?

    In my view the Blend and SketchFlow product and forum needs to be split up, it is a completely different target audience, SketchFlow needs to be simplified, UxD are not programmers and they don't really want to be either, allow easy swapping between Sketchy and Mockup look and feel ... anyway, just my 2cent
    Thursday, February 25, 2010 8:13 AM