Search code examples
wpfsilverlightstoryboardexpression-blend

Reusing a storyboard


I am teaching myself how to use Blend some MS lessons. One project I am going through is a calculator, where the calculator keys are defined using the xaml below, each with it's own storyboard to animate the press and release of the key.

The images for each key were created in Photoshop or something similar, and the end result is the nice looking calculator below.

Questions:

  1. is it possible to define the StoryBoard(s) once and reuse that for each 'key'? How?
  2. is it possible to turn each key into a button? How?

Cheers,
Berryl

sample calculator key

            <Canvas x:Name="plus" Height="75" HorizontalAlignment="Right" Margin="0,362,485,0" VerticalAlignment="Top" Width="111" Clip="M60.612606,3.8724005 C57.263493,4.7858224 6.0270014,29.143972 5.1136127,30.361849 C4.2002244,31.579754 4.895596,32.797173 5.8089843,34.31953 C6.722373,35.841862 43.258041,68.419128 45.389259,69.94146 C47.520477,71.463791 47.520477,71.159058 50.260643,70.245667 C53.000813,69.332275 104.15021,40.713028 104.45465,39.495182 C104.75909,38.277306 104.75952,37.059433 103.54169,35.841587 C102.32386,34.623711 64.291183,3.7548122 62.439445,3.7270708 C60.571468,3.6990852 60.612606,3.8724005 60.612606,3.8724005 z">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseLeftButtonDown">
                    <im:ControlStoryboardAction Storyboard="{StaticResource PlusPress}"/>
                </i:EventTrigger>
                <i:EventTrigger EventName="MouseLeftButtonUp">
                    <im:ControlStoryboardAction Storyboard="{StaticResource PlusRelease}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
            <Image x:Name="image14" Height="75" Width="111" Source="images/plus.png" Stretch="Fill" RenderTransformOrigin="0.5,0.5">
                <Image.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Image.RenderTransform>
            </Image>
        </Canvas>

sample story boards

        <Storyboard x:Name="PlusPress">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image14" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
            <EasingDoubleKeyFrame KeyTime="00:00:00.2000000" Value="7">
                <EasingDoubleKeyFrame.EasingFunction>
                    <CircleEase EasingMode="EaseInOut"/>
                </EasingDoubleKeyFrame.EasingFunction>
            </EasingDoubleKeyFrame>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    <Storyboard x:Name="PlusRelease">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image14" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
            <EasingDoubleKeyFrame KeyTime="00:00:00.2000000" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>

enter image description here


Solution

  • The next step is to learn how to template a button. After that, you can use transition effect between "Pressed" and "Normal" states.

    Edit 1

    Example :

    You must adapt these styles with your use (image instead of text etc..). In Blend after past this snippet, right click on one button, Edit Template > Edit Current...

    Or in Resources pannel : Right click on CalcButtonStyle Edit You can change default properties (background color, margin etc.) in this mode. Il you want change the template : on object and Timeline pannel, right click on "<> Style" Edit Template > Edit Current... You can see the different states (Normal, Pressed etc.) in the States pannel.

               <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
                    <StackPanel.Resources>
                        <!-- The main calc button style -->
                        <Style TargetType="Button"  x:Key="CalcButtonStyle">
                            <Setter Property="FontFamily" Value="Arial Black" />
                            <Setter Property="Background" Value="Black" />
                                <Setter Property="BorderBrush">
                                    <Setter.Value>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="#FF838383" Offset="0"/>
                                            <GradientStop Color="#FF393939" Offset="0.375"/>
                                            <GradientStop Color="#FF293037" Offset="0.375"/>
                                            <GradientStop Color="Black" Offset="1"/>
                                        </LinearGradientBrush>
                                    </Setter.Value>
                                </Setter>
                            <Setter Property="Foreground" Value="#FFFFFFFF"/>
                            <Setter Property="Padding" Value="3"/>
                            <Setter Property="BorderThickness" Value="1"/>
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="Button">
                                        <Grid>
                                            <VisualStateManager.VisualStateGroups>
                                                <VisualStateGroup x:Name="CommonStates">
                                                    <VisualStateGroup.Transitions>
                                                        <VisualTransition GeneratedDuration="0:0:0.255"/>
                                                    </VisualStateGroup.Transitions>
                                                    <VisualState x:Name="Normal" />
                                                    <VisualState x:Name="MouseOver"/>
                                                    <VisualState x:Name="Pressed">
                                                        <Storyboard>
                                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="BackgroundPressed" d:IsOptimized="True"/>
                                                            <DoubleAnimation Duration="0" To="0.8" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="contentPresenter" d:IsOptimized="True"/>
                                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="contentPresenter" d:IsOptimized="True">
                                                                <DoubleAnimation.EasingFunction>
                                                                    <BackEase EasingMode="EaseInOut"/>
                                                                </DoubleAnimation.EasingFunction>
                                                            </DoubleAnimation>
                                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="contentPresenter" d:IsOptimized="True">
                                                                <DoubleAnimation.EasingFunction>
                                                                    <BackEase EasingMode="EaseInOut"/>
                                                                </DoubleAnimation.EasingFunction>
                                                            </DoubleAnimation>
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="Disabled">
                                                    <Storyboard>
                                                        <DoubleAnimation Duration="0" Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" To=".55"/>
                                                    </Storyboard>
                                                </VisualState>
                                            </VisualStateGroup>
                                            <VisualStateGroup x:Name="FocusStates">
                                                <VisualState x:Name="Focused"/>
                                                <VisualState x:Name="Unfocused" />
                                            </VisualStateGroup>
                                        </VisualStateManager.VisualStateGroups>
                                        <Border x:Name="Background" IsHitTestVisible="False" BorderThickness="1" CornerRadius="3" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"/>
                                        <Border x:Name="BackgroundPressed" IsHitTestVisible="False" BorderThickness="1" CornerRadius="3" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Opacity="0" RenderTransformOrigin="0.5,0.5" >
                                            <Border.RenderTransform>
                                                <CompositeTransform ScaleY="-1"/>
                                            </Border.RenderTransform>
                                        </Border>
                                        <ContentPresenter
                                              x:Name="contentPresenter"
                                              Content="{TemplateBinding Content}"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              Margin="{TemplateBinding Padding}" RenderTransformOrigin="0.5,0.5">
                                            <ContentPresenter.RenderTransform>
                                                <CompositeTransform/>
                                            </ContentPresenter.RenderTransform>
                                        </ContentPresenter>
                                        <Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
                                    </Grid>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                    <!-- Define CalcButtonStyle as default style for all buttons -->
                    <Style TargetType="Button" BasedOn="{StaticResource CalcButtonStyle}" />
                    <!-- Override style for Gray buttons -->
                    <Style x:Key="CalcGrayButtonStyle" TargetType="Button" BasedOn="{StaticResource CalcButtonStyle}">
                        <Setter Property="Background" Value="Gray" />
                        <Setter Property="BorderBrush">
                            <Setter.Value>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FF999999" Offset="0"/>
                                    <GradientStop Color="#FF4B4B4B" Offset="0.375"/>
                                    <GradientStop Color="#FF41464B" Offset="0.375"/>
                                    <GradientStop Color="#FF373737" Offset="1"/>
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </StackPanel.Resources>
                <Button Content="7" Width="22" Height="22"  Margin="2"/>
                <Button Content="8" Width="22" Height="22" Margin="2" />
                <Button Content="9" Width="22" Height="22" Margin="2" />
                <Button Content="-" Width="22" Height="22" Margin="2" Style="{StaticResource CalcGrayButtonStyle}" />
            </StackPanel>
    

    Edit 2

    In your case, the template might look like this:

    Warning: I deleted the visual states "MouseOver, Disabled, Focused etc." I just kept the pressed state.

    <UserControl.Resources>
            <Style TargetType="Button">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Grid>
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup x:Name="CommonStates">
                                        <VisualStateGroup.Transitions>
                                            <VisualTransition GeneratedDuration="0:0:0.255"/>
                                        </VisualStateGroup.Transitions>
                                        <VisualState x:Name="Normal"/>
                                        <VisualState x:Name="MouseOver"/>
                                        <VisualState x:Name="Pressed">
                                            <Storyboard>
                                                <DoubleAnimation Duration="0" To="7" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="contentPresenter" d:IsOptimized="True">
                                                    <DoubleAnimation.EasingFunction>
                                                        <BackEase EasingMode="EaseInOut"/>
                                                    </DoubleAnimation.EasingFunction>
                                                </DoubleAnimation>
                                                <DoubleAnimation Duration="0" To="7" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="contentPresenter" d:IsOptimized="True">
                                                    <DoubleAnimation.EasingFunction>
                                                        <BackEase EasingMode="EaseInOut"/>
                                                    </DoubleAnimation.EasingFunction>
                                                </DoubleAnimation>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Disabled"/>
                                    </VisualStateGroup>
                                    <VisualStateGroup x:Name="FocusStates">
                                        <VisualState x:Name="Focused"/>
                                        <VisualState x:Name="Unfocused"/>
                                    </VisualStateGroup>
                                </VisualStateManager.VisualStateGroups>
                                <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RenderTransformOrigin="0.5,0.5">
                                    <ContentPresenter.RenderTransform>
                                        <CompositeTransform/>
                                    </ContentPresenter.RenderTransform>
                                </ContentPresenter>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </UserControl.Resources>
    
        <Grid x:Name="LayoutRoot" Background="White">
            <Canvas x:Name="plus" Height="75" HorizontalAlignment="Right" Margin="0,362,485,0" VerticalAlignment="Top" Width="111" Clip="M60.612606,3.8724005 C57.263493,4.7858224 6.0270014,29.143972 5.1136127,30.361849 C4.2002244,31.579754 4.895596,32.797173 5.8089843,34.31953 C6.722373,35.841862 43.258041,68.419128 45.389259,69.94146 C47.520477,71.463791 47.520477,71.159058 50.260643,70.245667 C53.000813,69.332275 104.15021,40.713028 104.45465,39.495182 C104.75909,38.277306 104.75952,37.059433 103.54169,35.841587 C102.32386,34.623711 64.291183,3.7548122 62.439445,3.7270708 C60.571468,3.6990852 60.612606,3.8724005 60.612606,3.8724005 z">
                <Button>
                    <Image x:Name="image14" Height="75" Width="111" Source="icon-twitter-footer.png" Stretch="Fill" RenderTransformOrigin="0.5,0.5">
                        <Image.RenderTransform>
                            <TransformGroup>
                                <ScaleTransform/>
                                <SkewTransform/>
                                <RotateTransform/>
                                <TranslateTransform/>
                            </TransformGroup>
                        </Image.RenderTransform>
                    </Image>
                </Button>
            </Canvas>
        </Grid>