Easiest Way to Animate Control from Hidden to Full Size? - wpf

I've got a "toolbar" type control that is basically a set of buttons for "groups" of other buttons. The buttons and groups are arranged horizontally along the top of my window.
What I'd like is to have, when the user clicks one of the buttons for one of the groups, the list (probably an ItemsPanel) of other buttons for that group expands from being 0 width to being however wide it needs to be to hold the list of buttons.
So you'd start off with something like this:
_______
|G|G|G|
-------
where G is a group button. And if you click on the middle group button, you'll end up with this:
_______________
|G|G|B|B|B|B|G|
---------------
where the original group buttons are still there and the new buttons for the selected group have "grown" into place.
What's the best way to make this happen? Should I use a ListBox as the outer container and trigger an animation when IsSelected changes on one of the ListBoxItems? If so, how do I write an animation that goes from 0 width (or hidden) to "full width" (whatever that may be)?
Thanks!

I'd use fluid layout, not that this is the best way or anything, but its one way. Basically allows you to animate between say Auto width and 0 width.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
x:Class="Example.MainWindow"
Title="MainWindow"
Height="350"
Width="525">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Group1" ei:ExtendedVisualStateManager.UseFluidLayout="True">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="G1Hidden">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="button">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Double>0</System:Double>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="button1">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Double>0</System:Double>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="G1Shown"/>
</VisualStateGroup>
<VisualStateGroup x:Name="Group2" ei:ExtendedVisualStateManager.UseFluidLayout="True">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="G2Hidden">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="button2">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Double>0</System:Double>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="button3">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Double>0</System:Double>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="G2Shown"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<VisualStateManager.CustomVisualStateManager>
<ei:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<i:Interaction.Behaviors>
<ei:DataStateBehavior Binding="{Binding IsChecked, ElementName=toggleButton}" Value="True" TrueState="G1Shown" FalseState="G1Hidden"/>
<ei:DataStateBehavior Binding="{Binding IsChecked, ElementName=toggleButton1}" Value="True" TrueState="G2Shown" FalseState="G2Hidden"/>
</i:Interaction.Behaviors>
<StackPanel Orientation="Horizontal">
<ToggleButton x:Name="toggleButton" Content="Group1" />
<Button x:Name="button" Content="Group1B1" />
<Button x:Name="button1" Content="Group1B2" />
<ToggleButton x:Name="toggleButton1" Content="Group2" />
<Button x:Name="button2" Content="Group2B1" />
<Button x:Name="button3" Content="Group2B2" />
</StackPanel>
</Grid>

Related

How can I add the validation style to all my custom controls and still be DRY?

I'm currently building some custom controls in Silverlight. I want these controls to respond to validation errors. What I'm trying to do is to get that red border around my control, just like the default Silverlight controls.
What I understand is that I need to add this to my template:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="Valid"/>
<VisualState x:Name="InvalidUnfocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="InvalidFocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<sys:Boolean>True</sys:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ValidationErrorElement" BorderThickness="1" CornerRadius="1" BorderBrush="#FFDB000C" Visibility="Collapsed">
<ToolTipService.ToolTip>
<ToolTip x:Name="validationTooltip" Template="{StaticResource ValidationToolTipTemplate}" Placement="Right"
PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"
DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<ToolTip.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<sys:Boolean>true</sys:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ToolTip.Triggers>
</ToolTip>
</ToolTipService.ToolTip>
<Grid Width="12" Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Background="Transparent">
<Path Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C"/>
<Path Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff"/>
</Grid>
</Border>
and
<ControlTemplate x:Key="ValidationToolTipTemplate">
<Grid x:Name="Root" Margin="5,0" RenderTransformOrigin="0,0" Opacity="0">
<Grid.RenderTransform>
<TranslateTransform x:Name="xform" X="-25"/>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OpenStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
<VisualTransition To="Open" GeneratedDuration="0:0:0.2">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="xform" Storyboard.TargetProperty="X" To="0" Duration="0:0:0.2">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude=".3" EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.2"/>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Closed">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="0" Duration="0"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Open">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="xform" Storyboard.TargetProperty="X" To="0" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Margin="4,4,-4,-4" Background="#052A2E31" CornerRadius="5"/>
<Border Margin="3,3,-3,-3" Background="#152A2E31" CornerRadius="4"/>
<Border Margin="2,2,-2,-2" Background="#252A2E31" CornerRadius="3"/>
<Border Margin="1,1,-1,-1" Background="#352A2E31" CornerRadius="2"/>
<Border Background="#FFDC000C" CornerRadius="2"/>
<Border CornerRadius="2">
<TextBlock
UseLayoutRounding="false"
Foreground="White" Margin="8,4,8,4" MaxWidth="250" TextWrapping="Wrap" Text="{Binding (Validation.Errors)[0].ErrorContent}"/>
</Border>
</Grid>
</ControlTemplate>
And I need to add this for every control that I create (with the exception of the ValidationToolTipTemplate-ControlTemplate).
How can I add the validation style to all my controls and still be DRY?
If that is not possible, does this mean that when the style of the validation template changes, I have to copy and paste the templates of all the controls in the known universe in a file called 'generic.xaml' and change it accordingly?
I've worked with Microsoft APIs long enough to know that (2) is probably the way to go, but I want to make sure first.
With the way that Silveright/WPF work there are some gotchas in these sorts of situations. You DO end up repeating XAML as ControlTemplates are all or nothing. You either end up replacing the Style's template or not. You can't pick and choose what to override like you do with a class.
I will try to answer your specific questions then try to provide a couple of broad approaches that should help to eliminate redundancy in XAML files.
How can you add the validation style to all controls?
First, take that border and make it a StaticResoruce by giving in a Key attribute. Then put it in a shared resource dictionary. When you need the style again you can use it in your templates like this:
<ContentControl x:Name="ValidationErrorElement" Content={StaticResource MyBorderResource}" />
You can't do much more than that for encapsulating the template. As far as the Validation VisualStates, those are as compact as possible already. What you can do however, is combine multiple templates into one larger template. I like to do this with ToggleButtons, Buttons and RadioButtons that look like buttons. See point #2 below.
General Rules of Thumb
Encapsulate commonly used XAML fragments into templated Controls and Control templates. For instance, let's say you have a border within a border that you're using in a few different places. That could be described as a ControlTemplate resource and loaded into a ContentControl.
If you have several styles or control templates that are largely the same (Button,ToggleButton,RadioButton come to mind), then you can apply the style to a common ancestor ButtonBase, in this case. Your new button ControlTemplate would contain all the VisualStates and graphic elements needed by Button,ToggleButton and RadioButton and be applied to the type ButtonBase. As noted above, this approach works well for very similar looking controls but would be a poor choice for controls that aren't that similar.

Change the background image of a Button when pressed using VisualStateManager

I have this button :
<Button x:Name="PrevAdIcon" Tag="-1" Visibility="Collapsed" Width="80" Height="80" Click="PrevAd">
<Button.Background>
<ImageBrush AlignmentY="Top" Stretch="None" ImageSource="/Images/prev.png"></ImageBrush>
</Button.Background>
</Button>
How can I change the background to /Images/prev-selected.png when a user pressed the button ? It'll give him a feedback, since it's a WP7 app
what I have so far (not working) :
<vsm:VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="Background" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ImageBrush ImageSource="/Images/prev-selected.png" Stretch="Fill"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
As far as I know, you can't change the value of the Source property on the Image element by using the VisualStateManager. However, you can just add two Image elements to the ControlTemplate: one for the Normal state and one for the Pressed state, and toggle the Visibility in the Pressed state.
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Img">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="PressedImg">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
See Peter Torr's post on "Why can't I change the Background of my Button on a Click event?" for an example and explanation of how to do this.
To add more information to Derek's answer, you should look at Gambit's answer here for full XAML that works

How to discrete animate GridLength from "Auto" to "*"?

I need to animate this property using a Storyboard.
Is writing your own animation is a best choice?
No, it is quite possible using the standard XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" x:Name="col0"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Storyboard x:Key="sbCol0ToAuto">
<ObjectAnimationUsingKeyFrames
BeginTime="0" Duration="0"
Storyboard.TargetName="col0" Storyboard.TargetProperty="Width">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<GridLength>*</GridLength>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
...
</Grid>
And even easier back to Auto:
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static GridLength.Auto}">

How can i take control of an element inside a template from outer template

Am facing hard time finding solution for this problem. I've a control template in which i've a content presenter and a Custom visual state manager with visual state Selected and UnSelected under SelectionStates group. Inside the content presenter's content template i've an ellipse whose Fill property i want to animate according to the visual state. This is not directly possible since the ellipse is residing inside the content presenter's content template. Is ther any indirect workaround possible to do the same. Below is my template
<Style TargetType="local:TabNavigationItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TabNavigationItem">
<Grid>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="SelectionStates">
<vsm:VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TabStripEllipse"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="#FF3B5A82"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="UnSelected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TabStripEllipse"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="Transparent"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<ContentPresenter>
<ContentPresenter.ContentTemplate>
<DataTemplate x:Key="tabNavigationItemTemplate">
<Border Padding="1">
<Ellipse x:Name="TabStripEllipse"
Fill="Transparent"
Stroke="#FF3B5A82" Cursor="Hand"
Height="8" Width="8"/>
</Border>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Your thoughts and suggestions are appreciated..
you may also want to put my xaml file as below.. but the properties related to target type of outer template should be accessible by inner data template.
<Style TargetType="local:TabNavigationItem">
<Setter Property="ItemContentTemplate" Value="{StaticResource contentTemplate}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TabNavigationItem">
<Grid>
<Border>
<ContentPresenter>
<ContentPresenter.ContentTemplate>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="SelectionStates">
<vsm:VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TabItemPresenter"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="#FF3B5A82"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="UnSelected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TabItemPresenter"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="Transparent"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Border Padding="1">
<Ellipse x:Name="TabStripEllipse"
Fill="Transparent"
Stroke="#FF3B5A82" Cursor="Hand"
Height="8" Width="8"/>
</Border>
</ContentPresenter.ContentTemplate>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Perhaps you have a reason why you are using a ContentPresenter in this way. The normal use of a content presenter would be act as a place holder for content being bound to a property of the control. You wouldn't normally use ContentPresenter and then provide your own DataTemplate to it. Here is my version of your Xaml without the apparrently unnecessary content presenter:-
<Style TargetType="local:TabNavigationItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TabNavigationItem">
<Grid>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="SelectionStates">
<vsm:VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TabStripEllipse"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="#FF3B5A82"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="UnSelected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TabStripEllipse"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="Transparent"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Border Padding="1">
<Ellipse x:Name="TabStripEllipse"
Fill="Transparent"
Stroke="#FF3B5A82" Cursor="Hand"
Height="8" Width="8"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now your VSM should be able to find the Ellipse.

The Silverlight 3 Toolkit styles prevent the displaying of SL 3.0 data validation errors

If I apply a style from the SL 3.0 Toolkit to my application the built in SL 3.0 data validation errors are not displayed on the application edit forms. If I removed the code that applies the toolkit style to the application the SL 3.0 data validation errors appear as per normal SL 3.0 behaviour?
Has anyone else come across this problem?????
Any help is always appreciated.
Cheers
Adam
After a bit of research I managed to find the solution to the problem.
A big shout out to Jesse Liberty for this post
Basically the toolkit style control templates do not contain the necessary visual state groups for the SL 3.0 validation to work.
To fix this I copied the required visual state groups and required template markup from the standard control templates to the toolkit control templates.
ie below are the visual state group for the checkbox control.
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="Valid"/>
<VisualState x:Name="InvalidUnfocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="InvalidFocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>True</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
Below is the style for the ValidationErrorElement for a checkbox.
<Border x:Name="ValidationErrorElement" Margin="1" Visibility="Collapsed" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1" ToolTipService.PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<ToolTipService.ToolTip>
<ToolTip x:Name="validationTooltip" Template="{StaticResource ValidationToolTipTemplate}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<ToolTip.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>true</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToolTip.Triggers>
</ToolTip>
</ToolTipService.ToolTip>
<Grid Height="10" HorizontalAlignment="Right" Margin="0,-4,-4,0" VerticalAlignment="Top" Width="10" Background="Transparent">
<Path Fill="#FFDC000C" Margin="0,3,0,0" Data="M 1,0 L5,0 A 2,2 90 0 1 7,2 L7,6 z"/>
<Path Fill="#ffffff" Margin="0,3,0,0" Data="M 0,0 L2,0 L 7,5 L7,7"/>
</Grid>
</Border>
You also need to place the control template for Validation tool tip in either a control or application reasource. ie
<ControlTemplate x:Key="ValidationToolTipTemplate">
<Grid x:Name="Root" Margin="5,0" Opacity="0" RenderTransformOrigin="0,0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="OpenStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
<VisualTransition GeneratedDuration="0:0:0.2" To="Open">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="xform" Storyboard.TargetProperty="X">
<SplineDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="0:0:0.2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Closed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="0" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Open">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="xform" Storyboard.TargetProperty="X">
<SplineDoubleKeyFrame KeyTime="0" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RenderTransform>
<TranslateTransform x:Name="xform" X="-25"/>
</Grid.RenderTransform>
<Border Margin="4,4,-4,-4" Background="#052A2E31" CornerRadius="5"/>
<Border Margin="3,3,-3,-3" Background="#152A2E31" CornerRadius="4"/>
<Border Margin="2,2,-2,-2" Background="#252A2E31" CornerRadius="3"/>
<Border Margin="1,1,-1,-1" Background="#352A2E31" CornerRadius="2"/>
<Border Background="#FFDC000C" CornerRadius="2"/>
<Border CornerRadius="2">
<TextBlock Margin="8,4,8,4" MaxWidth="250" UseLayoutRounding="false" Foreground="White" Text="{Binding (Validation.Errors)[0].ErrorContent}" TextWrapping="Wrap"/>
</Border>
</Grid>
</ControlTemplate>
I hope this helps someone out there.
Cheers
Adam

Resources