Animate Margin values between states in WPF - wpf

I'm trying to familiarize myself with WPF for an upcoming project. I'm having problem animating margins between states. Using Blend I've obtained the following sample XAML. If I trigger the state "Large" from codebehind, the rectangle suddenly expands after 1 second, instead of "easing" into the expansion, which is the desired effect.
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Large">
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="rectangle">
<EasingThicknessKeyFrame KeyTime="0" Value="64,135,47,191"/>
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="rectangle" Fill="#FFF4F4F5" Margin="428,135,47,191" Stroke="Black"/>
</Grid>
Thanks in advance!

I think it is because you only have one keyframe set to 0 in your animation.
try this :
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<!--Take one second to transition to the Large state.-->
<VisualTransition To="Large" GeneratedDuration="0:0:1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<!--Change the Margin to "64,135,47,191" when the states gets to "Large"-->
<VisualState x:Name="Large">
<Storyboard>
<ThicknessAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="Margin" To="64,135,47,191" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="rectangle" Margin="428,135,47,191" Fill="#FFF4F4F5" Stroke="Black"/>
</Grid>
edit: I was not very pleased with my first shot, so here is a better way of doing this.

Related

Wpf Visual transitions not working as intended

I am trying to create a custom button using a template.
I have written this template:
<Style TargetType="Button" x:Key="Delete Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="MouseOver"
GeneratedDuration="0:0:1"/>
<VisualTransition To="Pressed"
GeneratedDuration="0:0:1"/>
<VisualTransition From="Presse To="MouseOver"
GeneratedDuration="0:0:1"/>
<VisualTransition To="Normal"
GeneratedDuration="0:0:1"/>
<VisualTransition To="Disabled"
GeneratedDuration="0:0:0.1"/>
<VisualTransition From="Disabled"
GeneratedDuration="0:0:0.1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="VisPres"
Storyboard.TargetProperty="Stroke.Color"
To="PaleVioletRed"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="VisPres"
Storyboard.TargetProperty="Fill.Color"
To="DarkRed">
</ColorAnimation>
<ColorAnimation Storyboard.TargetName="VisPres"
Storyboard.TargetProperty="Stroke.Color"
To="Red"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ColorAnimation Storyboard.TargetName="VisPres"
Storyboard.TargetProperty="Fill.Color"
To="Gray"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="VisPres" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Fill="Red"
Stroke="Black" StrokeThickness="4">
</Ellipse>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="4,4,4,4"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The template looks fine, but all the animation transitions take 1 seond, even though I stated they should take different times in the visualtransition.
can anyone help me please?
thank you very much!
Edit: here is another template on which even increasing times won't work
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="MouseOver"
GeneratedDuration="0:0:0.2"/>
<VisualTransition To="Pressed"
GeneratedDuration="0:0:0.01"/>
<VisualTransition From="Pressed" To="MouseOver"
GeneratedDuration="0:0:0.01"/>
<VisualTransition To="Normal"
GeneratedDuration="0:0:2"/>
<VisualTransition To="Disabled"
GeneratedDuration="0:0:0"/>
<VisualTransition From="Disabled" To="Normal"
GeneratedDuration="0:0:2"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="LightCol"
Storyboard.TargetProperty="Color"
To="#BCFF8E"/>
<ColorAnimation Storyboard.TargetName="ShadCol"
Storyboard.TargetProperty="Color"
To="#A1CC84"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="LightCol"
Storyboard.TargetProperty="Color"
To="#72E324"/>
<ColorAnimation Storyboard.TargetName="ShadCol"
Storyboard.TargetProperty="Color"
To="#6CBF32"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ColorAnimation Storyboard.TargetName="LightCol"
Storyboard.TargetProperty="Color"
To="Gray"/>
<ColorAnimation Storyboard.TargetName="ShadCol"
Storyboard.TargetProperty="Color"
To="Gray"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="Focused">
<Storyboard>
<ThicknessAnimation Storyboard.TargetName="Bord"
Storyboard.TargetProperty="BorderThickness"
To="2"
Duration="0:0:0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="Bord" BorderBrush="Blue" BorderThickness="0">
<Rectangle Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop x:Name="LightCol" Color="#D7FFBC" Offset="0.499"/>
<GradientStop x:Name="ShadCol" Color="#D5E5CA" Offset="0.501"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Border>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="4,4,4,4"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Change text when VisualState is set to "PointerOver",

I am working on ControlTemplate for a Button.
This is my current code which changes button's color.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1.Styles">
<ControlTemplate x:Key="ButtonBrushAnimation" TargetType="Button">
<Grid >
<TextBlock x:Name="textBlock" Width="80" Height="30" Text="AAA" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<!--Take one half second to transition to the PointerOver state.-->
<VisualTransition To="PointerOver" GeneratedDuration="0:0:0.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonBrush"
Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.Background>
<SolidColorBrush x:Name="ButtonBrush" Color="Green"/>
</Grid.Background>
</Grid>
</ControlTemplate>
</ResourceDictionary>
I want to change text property of textBlock control on PointerOver event.
How can I do it?
Thank you!
Add StringAnimationUsingKeyFrames to your Storyboard like this:
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonBrush" Storyboard.TargetProperty="Color" To="Red" />
<StringAnimationUsingKeyFrames Storyboard.TargetName="textBlock" Storyboard.TargetProperty="Text">
<DiscreteStringKeyFrame Value="BBB" KeyTime="0:0:0" />
</StringAnimationUsingKeyFrames>
</Storyboard>
You can set a KeyTime property value depending on when exactly you need to change the text.

Binding event handlers to the templated hyperlink

I created a templated hyperlinkbutton in wpf (windows 8 metro app):
<ControlTemplate TargetType="HyperlinkButton">
<HyperlinkButton>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="PointerOver" GeneratedDuration="0:0:0.1"/>
</VisualStateGroup.Transitions>
</VisualStateGroup>
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="HyperlinkForegroundBrush" Storyboard.TargetProperty="Color" To="#FF011751"/>
</Storyboard>
</VisualState>
</VisualStateManager.VisualStateGroups>
<ContentPresenter Content={TemplateBinding Content}>
<ContentPresenter.Foreground>
<SolidColorBrush x:Name="HyperlinkForegroundBrush" Color="3FFB20404"/>
</ContentPresenter.Foreground>
</ContentPresenter>
</HyperlinkButton>
and this is the hyperlinkbutton::
<HyerlinkButton Style={StaticResource MainPageLinkStyle} x:Name="MoreDetailsHyperlinkButton" Content="More..." Click="MoreDetailsHyperlinkButton_Click"/>
The style MainPageLinkStyle refers to the above style mentioned.
Problem: The click of the hyperlinkbutton doesn't gets executed.
Please help.
Thanks in advance.
EDIT:
Instead of hyperlinkbutton's click event, when I use PointerPressed event, the mouse right click triggers this event,but not the mouse left click....Seems strange to me.
I found the solution. Here's the modified markup:
<ControlTemplate TargetType="HyperlinkButton">
<**Border**>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="PointerOver" GeneratedDuration="0:0:0.1"/>
</VisualStateGroup.Transitions>
</VisualStateGroup>
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="HyperlinkForegroundBrush" Storyboard.TargetProperty="Color" To="#FF011751"/>
</Storyboard>
</VisualState>
</VisualStateManager.VisualStateGroups>
<ContentPresenter Content={TemplateBinding Content}>
<ContentPresenter.Foreground>
<SolidColorBrush x:Name="HyperlinkForegroundBrush" Color="3FFB20404"/>
</ContentPresenter.Foreground>
</ContentPresenter>
</**Border**>
As highlighted in the markup, I need to use Border class instead of Hyperlink. I am not able to understand why, but this seems to be a possible solution working for me.

How can I target multiple UIElements with VisualStateManager?

If I do something like this to change the opacity of an Ellipse:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1">
<VisualTransition.GeneratedEasingFunction>
<CircleEase EasingMode="EaseIn"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Lit"/>
<VisualState x:Name="Unlit">
<Storyboard>
<DoubleAnimation Duration="0" To="0.225"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="ellipse" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="ellipse" Width="100" Height="100" Fill="Azure"/>
VisualStateManager.GoToState(this, "Unlit", true);
It works just fine.
But let's say I have a handful of Ellipses and want to apply the same StoryBoard to them, how do I do that?
<Ellipse x:Name="ellipse1" Width="100" Height="100" Fill="Azure"/>
<Ellipse x:Name="ellipse2" Width="100" Height="100" Fill="Azure"/>
<Ellipse x:Name="ellipse3" Width="100" Height="100" Fill="Azure"/>
One way would be to define multiple DoubleAnimations to the same StoryBoard:
<Storyboard>
<DoubleAnimation Duration="0" To="0.225"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="ellipse1"
d:IsOptimized="True"/>
<DoubleAnimation Duration="0" To="0.225"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="ellipse2"
d:IsOptimized="True"/>
</Storyboard>
But this is somewhat cumbersome when I have a dynamic number of ellipses.
Is there any more elegant way?
I'm not sure about elegant, but one way could be to animate an intermediate property, and bind the real target properties to that:
<Grid x:Name="animationTarget" Visibility="Collapsed" />
<Ellipse x:Name="ellipse1" Width="100" Height="100" Fill="Azure"
Opacity={Binding Opacity, ElementName=animationTarget}/>
<Ellipse x:Name="ellipse2" Width="100" Height="100" Fill="Azure"
Opacity={Binding Opacity, ElementName=animationTarget}/>
and
<Storyboard>
<DoubleAnimation Duration="0" To="0.225"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="animationTarget" />
</Storyboard>
(If using an invisible extra element as an intermediate binding target doesn't seem nice it could instead be on some attached property on whatever container your ellipses are in)

How to turn off animations in WPF Toolkit charts

Is there a way to turn off the animations in Xaml directly? The animations are really sluggish as my chart has many points.
i have downloaded the latest source code at http://wpf.codeplex.com/SourceControl/list/changesets
my idea is, to remove the animation by changing the style for the different chart series (chart points, DataPointStyle)
example for charting:PieDataPoint
try to remove the animation for the shown data and take your own style with a given key (x:key="myStyle" -> DataPointStyle="{StaticResource myStyle}")
and remove Opacity="0" at <Grid x:Name="Root" Opacity="0">
remove this visual state group from your style
<VisualStateGroup x:Name="RevealStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.5" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Shown">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
</Storyboard>
</VisualState>
<VisualState x:Name="Hidden">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="0" Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
EDIT
This is the changed style.
<!-- charting:PieDataPoint -->
<Style TargetType="charting:PieDataPoint">
<Setter Property="Background" Value="Orange" />
<Setter Property="BorderBrush" Value="White" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="RatioStringFormat" Value="{}{0:p2}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="charting:PieDataPoint">
<Grid x:Name="Root" Opacity="0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.1" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="MouseOverHighlight" Storyboard.TargetProperty="Opacity" To="0.6" Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.1" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Unselected" />
<VisualState x:Name="Selected">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SelectionHighlight" Storyboard.TargetProperty="Opacity" To="0.6" Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Path x:Name="Slice" Data="{TemplateBinding Geometry}" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeMiterLimit="1">
<ToolTipService.ToolTip>
<StackPanel>
<ContentControl Content="{TemplateBinding FormattedDependentValue}" />
<ContentControl Content="{TemplateBinding FormattedRatio}" />
</StackPanel>
</ToolTipService.ToolTip>
</Path>
<Path x:Name="SelectionHighlight" Data="{TemplateBinding GeometrySelection}" Fill="Red" StrokeMiterLimit="1" IsHitTestVisible="False" Opacity="0" />
<Path x:Name="MouseOverHighlight" Data="{TemplateBinding GeometryHighlight}" Fill="White" StrokeMiterLimit="1" IsHitTestVisible="False" Opacity="0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
After my first attempt to remove the animation, I wanted to give up, because it has not worked.
But then I looked upon me with the reflector to the source code and have found a way that it still works.
Setting the DataPointStyle unfortunately is not enough, I think it's a bug.
<chartingToolkit:Chart Margin="8">
<chartingToolkit:Chart.Series>
<chartingToolkit:BarSeries x:Name="barSeries"
Title="Experience"
DataPointStyle="{StaticResource myBarStyle}">
</chartingToolkit:BarSeries>
</chartingToolkit:Chart.Series>
</chartingToolkit:Chart>
In the constructor of the control where the chart is included simply execute the following.
this.barSeries.RefreshStyles();
hope this helps

Resources