I have had several problems with the GoToStateAction in different scenarios, and I'm beginning to believe that either the feature is buggy, or that my understanding of it is off.
In this case, I have a datatemplate with an ellipse that is representing a connector. The connector has an IsConnected property... I am using VisualStates and the GoToStateAction with a DataTrigger to switch between the 2 states 'Connected' and 'NotConnected'. However, in this case the state is never set.
I know the model is set up correctly, as trying other binding scenarios with IsConnected works fine. What am I doing wrong?
<DataTemplate x:Key="ConnectorTemplate">
<Grid x:Name="grid">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ConnectionStates">
<VisualState x:Name="Connected">
<Storyboard>
<ColorAnimation Duration="0" To="#FFEAFFDD" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="ellipse" d:IsOptimized="True"/>
<ColorAnimation Duration="0" To="#FF56992B" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="ellipse" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="NotConnected"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<VisualStateManager.CustomVisualStateManager>
<ei:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<Ellipse x:Name="ellipse"
Height="8"
Width="8">
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding IsConnected}" Value="true">
<ei:GoToStateAction StateName="Connected"/>
</ei:DataTrigger>
<ei:DataTrigger Binding="{Binding IsConnected}" Value="false">
<ei:GoToStateAction StateName="NotConnected"/>
</ei:DataTrigger>
</i:Interaction.Triggers>
<Ellipse.Fill>
<RadialGradientBrush Center="0.275,0.262"
GradientOrigin="0.275,0.262"
RadiusX="0.566"
RadiusY="0.566">
<GradientStop Color="#FF333333"
Offset="1" />
<GradientStop Color="#FFC4C4C4" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
</DataTemplate>
I think you should set TargetName in GoToStateAction, because by default,if my memory serves me right, Target is associated with GoToStateAction object, in your case - ellipse
GoToStateAction is not triggered when the item is loaded, it only comes in play when the related property is changed (PropertyChanged event is fired).
Related
I want to create a common Button style with redefined template and animations for transition between mouse in, out, up, down and disabled and enabled states. That's not a problem, but I want to make another button style, which is basically the same except for the background color.
I have colors defined for the Normal, Hover and Disabled states in style resources as well as Storyboards:
<Style.Resources>
<Color x:Key="DisabledBackground">#4c4c4c</Color>
<Color x:Key="NormalBackground">#538ce1</Color>
<Color x:Key="HoverBackground">#6ea8ff</Color>
<Storyboard x:Key="MouseOverAnimation">
<ColorAnimation Storyboard.TargetName="BackgroundBrush"
Storyboard.TargetProperty="Color"
To="{StaticResource HoverBackground}"
Duration="0:0:0.3" />
<DoubleAnimation Storyboard.TargetName="Underlay"
Storyboard.TargetProperty="Opacity"
To="0.7"
Duration="0:0:0.3" />
</Storyboard>
<!-- and few others... -->
</Style>
Then I have customized template and finally the ControlTemplate.Triggers section:
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{DynamicResource MouseOverAnimation}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{DynamicResource MouseOutAnimation}"/>
</Trigger.ExitActions>
</Trigger>
<!-- and few others... -->
Now what I want is to create new style and just change the color of DisabledBackground and NormalBackground like this:
<Style x:Key="Start"
TargetType="{x:Type Button}"
BasedOn="{StaticResource {x:Type Button}}">
<Style.Resources>
<Color x:Key="DisabledBackground">#4c4c4c</Color>
<Color x:Key="NormalBackground">#960a0a</Color>
<Color x:Key="HoverBackground">#de1111</Color>
</Style.Resources>
</Style>
And let the control template untouched. You have probably noticed that I used DynamicResource in my common button style to refer storyboards in style resources which ends with exception because storyboards can't have binding or dynamic resources. This is my last "solution" which does not work but I couldn't came up with anything else.
I do not want to copy and paste my whole button style just to change two colors. How can I modify my style, to be able to "dynamically" change the colors used in storyboard animations or at least inherit the style and set the colors there?
Complete XAML
<Style TargetType="{x:Type Button}">
<Style.Resources>
<Color x:Key="DisabledBackground">#4c4c4c</Color>
<Color x:Key="NormalBackground">#538ce1</Color>
<Color x:Key="HoverBackground">#6ea8ff</Color>
<Storyboard x:Key="MouseOverAnimation">
<ColorAnimation Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color" To="{StaticResource HoverBackground}" Duration="0:0:0.3" />
<DoubleAnimation Storyboard.TargetName="Underlay" Storyboard.TargetProperty="Opacity" To="0.7" Duration="0:0:0.3" />
</Storyboard>
<Storyboard x:Key="MouseOutAnimation" FillBehavior="Stop">
<ColorAnimation Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color" To="{StaticResource NormalBackground}" Duration="0:0:0.3" />
<DoubleAnimation Storyboard.TargetName="Underlay" Storyboard.TargetProperty="Opacity" To="0.2" Duration="0:0:0.3" />
</Storyboard>
<Storyboard x:Key="MouseDownAnimation">
<DoubleAnimation Storyboard.TargetName="OverlayGradient" Storyboard.TargetProperty="Opacity" To="0.45" Duration="0:0:0.1" />
</Storyboard>
<Storyboard x:Key="MouseUpAnimation" Storyboard.TargetProperty="Background" FillBehavior="Stop">
<DoubleAnimation Storyboard.TargetName="OverlayGradient" Storyboard.TargetProperty="Opacity" To="0.5" Duration="0:0:0.1" />
</Storyboard>
<Storyboard x:Key="DisabledAnimation">
<ColorAnimation Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color" To="{StaticResource DisabledBackground}" Duration="0:0:0.3" />
<ColorAnimation Storyboard.TargetName="UnderlayFillBrush" Storyboard.TargetProperty="Color" To="{StaticResource DisabledBackground}" Duration="0:0:0.3" />
</Storyboard>
<Storyboard x:Key="EnabledAnimation">
<ColorAnimation Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color" To="{StaticResource NormalBackground}" Duration="0:0:0.3" />
<ColorAnimation Storyboard.TargetName="UnderlayFillBrush" Storyboard.TargetProperty="Color" To="{StaticResource NormalBackground}" Duration="0:0:0.3" />
</Storyboard>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<!-- Button underlay glow
-->
<Rectangle x:Name="Underlay" Opacity="0.2">
<Rectangle.Fill>
<SolidColorBrush x:Name="UnderlayFillBrush" Color="{DynamicResource NormalBackground}"/>
</Rectangle.Fill>
<Rectangle.Effect>
<BlurEffect Radius="35" KernelType="Gaussian"/>
</Rectangle.Effect>
</Rectangle>
<!-- Button base border with rounded corners
Contains base background
-->
<Border x:Name="ButtonBackground" BorderThickness="1" CornerRadius="2">
<Border.BorderBrush>
<SolidColorBrush Color="Black" Opacity="0.8"/>
</Border.BorderBrush>
<Border.Background>
<SolidColorBrush x:Name="BackgroundBrush" Color="{DynamicResource NormalBackground}"/>
</Border.Background>
<!-- Button Overlay
Adds the background overlay gradient -->
<Border CornerRadius="2">
<Border.Background>
<LinearGradientBrush x:Name="OverlayGradient" Opacity="0.5" StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="White"/>
<GradientStop Offset="0.02" Color="White"/>
<GradientStop Offset="0.02" Color="Transparent"/>
<GradientStop Offset="0.85" Color="#000000" />
</LinearGradientBrush>
</Border.Background>
<Border BorderThickness="1" CornerRadius="2">
<Border.BorderBrush>
<SolidColorBrush Color="#b4b4b4" Opacity="0.2"/>
</Border.BorderBrush>
<!-- Inner text -->
<TextBlock Text="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}"
FontFamily="Segoe UI"
Foreground="White"
TextWrapping="Wrap"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextOptions.TextFormattingMode="Display"
RenderOptions.BitmapScalingMode="NearestNeighbor">
<TextBlock.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="6" Color="Black" RenderingBias="Quality"/>
</TextBlock.Effect>
</TextBlock>
</Border>
</Border>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{DynamicResource DisabledAnimation}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{DynamicResource EnabledAnimation}"/>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{DynamicResource MouseOverAnimation}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{DynamicResource MouseOutAnimation}"/>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{DynamicResource MouseDownAnimation}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{DynamicResource MouseUpAnimation}"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Quoting documentation on MSDN:
You can't use dynamic resource references or data binding expressions
to set Storyboard or animation property values. That's because
everything inside a Style must be thread-safe, and the timing system
must Freeze Storyboard objects to make them thread-safe. A Storyboard
cannot be frozen if it or its child timelines contain dynamic resource
references or data binding expressions. For more information about
freezing and other Freezable features, see the Freezable Objects
Overview.
You can certainly use a super hacks, etc., but in your case, in my opinion, it's easier to use a different style or colors in resources. It will not be so difficult.
For more information see:
MSDN docs
Similar question
Although its been years since this question was asked and answered I have some useful information for others to keep in mind so you don't make the same mistake I did years ago when trying to solve this problem.
TLDR
Be very cautious about using ComponentResourceKey as a way to use make your dynamic resource static so that you can use it with freezables. It will compile, it may even run but you got lucky and it probably shouldn't even be allowed in the first place as it could save people from walking off a cliff. See code example at the bottom, don't do that with freezables.
Full Details
Like others, I wanted to keep my resources as flexible as possible. I was aware that we cannot use Dynamic Resources for animations but came across a 'clever' way around this with code similar to the following example. The key here (no pun intended) was to use the ComponentResourceKey. After I used this approach a year or so ago I was nearly break dancing on the floor when it worked with the animations. At first glance you might be thinking, "Well of course this worked, you used a static resource per your code example". However, once you become aware that the ComponentResourceKey is a markup extension that provides 'super powers' that let you refer to a resource that may not even exist in the current assembly and you don't have to include that assembly as a reference, it becomes easier to understand that this effectively translates to a pseudo dynamic resource.
In the case of a freezable, I believe this was working for me at the time because I accidentally created an initialization ordering that made this appear to work. That is the value was defined before it was first consumed. Then over this weekend (and now years later) I started to dump all of my bin/obj and ext files into a common location where they could easily be clobbered by my build system so I would feel confident I had a clean build. Suddenly, I began hitting fatal xaml exceptions indicating that the ComponentResourceKey's I used in some locations were not defined. I then directly included the assemblies right where they were used rather than in the main exe. I knew this went against what I was trying to avoid (coupling) but it was after midnight and I wanted it to compile before I retired, but it still crashed with the same XAML exceptions.
After I overcame the
well it worked for over a year, it must be something I changed
recently
feeling that we all have, it became clear as day that what I was doing shouldn't have even be used in the first place. I think the "good programmer" in us always wants to be as flexible and decoupled as possible, even if that means coming up with some really creative techniques that satisfy our need to solve the problem in our faces that day.
In addition to truly clobbering the binaries between builds, I also
turned about 128 libraries into Nuget packages and I think this
somehow affected the initialization ordering of when the key's value
was set vs. when it was used. It all seemed like voodoo after midnight.
I still think that using the ComponentResourceKey markup extension can be a great way of decoupling xaml library inter-dependencies, you just cannot use them safely with freezables such as those in storyboard animations. Back when I first applied this technique, I didn't try to dynamically change the value during runtime as for me this was merely a stretch goal and I knew that someday I would look back and be glad I took the time to make it that flexible. (Now I wish I had that time back!)
Example of using a ComponentResourceKey
Don't do this with freezables
<BeginStoryboard>
<Storyboard FillBehavior="Stop" Duration="0:0:.1">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource {ComponentResourceKey TypeInTargetAssembly={x:Type local:SettingKeys}, ResourceId=DefaultButtonClickBackgroundBrush}}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
BTW, here is an example of defining the key in case you want to apply this technique to anything other than freezables. Note that the local:SettingKeys is just an empty C Sharp class, google the technique to fully understand.
<SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:SettingKeys},ResourceId=DefaultButtonClickBackgroundBrush}" Color="#FE8D00" />
If this saves someone else one headache, I will be happy. Like the accepted answer's author stated, you can use creative hacks but you should avoid them or walk off a cliff like me.
The follow XAML represents an object I am trying to build in Expression Blend. I am having trouble with the DataTrigger in the StackPanel - the application does not go to Empty when the trigger matches the data. Further explanation is after this code:
<DataTemplate x:Key="SampleTemplate">
<StackPanel x:Name="SampleStack" Style="{StaticResource DefaultSampleStyle}" Width="64" Height="60">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0">
<Storyboard>
<ColorAnimation Duration="0" To="#FFDFE04B" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="SampleStack" d:IsOptimized="True"/>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Empty">
<Storyboard>
<ColorAnimation Duration="0" To="#FF4B6FE0" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="SampleStack" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<VisualStateManager.CustomVisualStateManager>
<ei:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding IsActive}" Value="False">
<ei:GoToStateAction StateName="Empty" UseTransitions="False"/>
</ei:DataTrigger>
</i:Interaction.Triggers>
<TextBlock x:Name="StartOn" Text="{Binding StartOn, StringFormat=hh:mm}"/><TextBlock x:Name="textBlock" Text="-" />
<TextBlock x:Name="EndOn" Text="{Binding EndOn, StringFormat=hh:mm}"/>
</StackPanel>
</DataTemplate>
If I use an EventTrigger with a Loaded value, the Empty state is correctly applied based on the IsActive binding.
If I use the existing DataTrigger and change a Property on the Stackpanel, such as Height, based on the binding of IsActive this also works.
Am I doing something fundamentally wrong in the XAML? Do you need a more complete example of the XAML to understand the issue?
do you need the GoToStateAction?
I guess, the problem is the Binding "at startup". I added a dispatcher and threw the NotifyPropertyChanged again after one second. Then it works. Propably you can workaround it like this. You wait till the control is loaded and then throw the PropertyChanged again. This is not a nice way and similar to your idea (If I use an EventTrigger with a Loaded value,...)
I would recommend you to use a DataStateBehaviour. If you hav a boolean to decide in which satte you have to go, this is great. It is a behaviour where you can bind the condition to a property and then set a true and a false state.
It would look like this (I did a few adjustments just for testing at my computer):
<DataTemplate x:Key="SampleTemplate">
<StackPanel x:Name="SampleStack" Width="64" Height="60" Background="White">
<i:Interaction.Behaviors>
<ei:DataStateBehavior Binding="{Binding IsChecked}" Value="True" TrueState="Empty" FalseState="Base"/>
</i:Interaction.Behaviors>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Empty">
<Storyboard>
<ColorAnimation Duration="0" To="Red" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="SampleStack" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Base"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<VisualStateManager.CustomVisualStateManager>
<ei:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<TextBlock x:Name="StartOn" Text="Test"/>
</StackPanel>
</DataTemplate>
As you can see I added a second state to the VisualStateGroup (There is now empty and base). I would recommend this not only because the DataStateBehaviour needs at least two states in one group. If you have only one state, you have no chance to change the state of this group back to normal, e.g.
I hope this answer helps you.
BR,
TJ
I've video player with two button: Play and Pause.
I want to use only one button. when user clicks on Play, the button appearance will changed to Pause and vice versa.
What is the better approach to achieve that task without using cs code behind?
I've tried to use DataTrigger to my IsPlaying property, but with no much success....
Here is my code:
<Window.Resources>
<Viewbox x:Key="viewboxSource" >
<Viewbox.Triggers>
<DataTrigger Binding="{Binding IsPlaying}" Value="True">
<Setter Property="Path">
<Setter.Value>
<Path Stroke="Black" StrokeThickness="1" Fill="AliceBlue">
<Path.Data>
<GeometryGroup>
<EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/>
</GeometryGroup>
</Path.Data>
</Path>
</Setter.Value>
</Setter>
</DataTrigger>
</Viewbox.Triggers>
</Viewbox>
</Window.Resources>
<StackPanel>
<Button Content="{StaticResource viewboxSource}"></Button>
</StackPanel>
But I gut an error that says " 'Path' member is not valid because it does not have a qualifying type name " .
Can anyone can help or give me a better solution?
These kind of behaviour fits toggle button patern.
Make a style in your resources
<Style x:Key="PlayToggleButtonStyle" TargetType="ToggleButton" >
and then define a templeate in it
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
What is the most important here is to use VisualStateManager.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled"/>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimation Duration="0" To="2" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="border" />
<ColorAnimation Duration="0:0:0.2" To="#FF392929" Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="border"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
I use 2 animation. One moves button for 2 pixels and second change the gradient which gives a nice experience.
The only drawback is you need to use storyboards to handle these states. You need to add a Path object which I called Geometry nad mainupulate it.
<Storyboard Storyboard.TargetName="Geometry"
Storyboard.TargetProperty="Data">
<ObjectAnimationUsingKeyFrames>
<DiscreteObjectKeyFrame KeyTime="0" Value=""/> <!-- place the data here (how your button looks like) -->
</ObjectAnimationUsingKeyFrames>
</Storyboard>
But IMHO the better solution is to place 2 Path object in the template that on is over another and change the opacity of the top-most one.
<Storyboard>
<DoubleAnimation Storyboard.TargetName="TopGeometry" Storyboard.TargetProperty="Opacity" Duration="0:0:0.5" To="0.0">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
You would have a nice transition between these two states. What is more, no data is needed f.e IsPLaying property.
Can anyone please help me or is there anything I miss out? the visualstate is not triggered
xmlns:swi="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:esi="clr-namespace:Expression.Samples.Interactivity;assembly=Expression.Samples.Interactivity"
xmlns:mei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
<my:DataGridTemplateColumn IsReadOnly="True">
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="vsgUrgency">
<VisualState x:Name="UrgencySerious">
<Storyboard>
<ColorAnimation Storyboard.TargetName="orbUrgency"
Storyboard.TargetProperty="Fill" To="Red"/>
</Storyboard>
</VisualState>
<VisualState x:Name="UrgencyNormal">
<Storyboard>
<ColorAnimation Storyboard.TargetName="orbUrgency"
Storyboard.TargetProperty="Fill" To="Green"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<swi:Interaction.Triggers>
<esi:DataTrigger Binding="{Binding Urgency}" Value="Serious">
<mei:GoToStateAction StateName="UrgencySerious"/>
</esi:DataTrigger>
<esi:DataTrigger Binding="{Binding Urgency}" Value="Normal">
<mei:GoToStateAction StateName="UrgencyNormal"/>
</esi:DataTrigger>
</swi:Interaction.Triggers>
<TextBlock Text="{Binding Urgency}"/>
<Path x:Name="orbUrgency" Width="14.6566" Height="14.5449" Stretch="Fill" StrokeThickness="1"
StrokeLineJoin="Round" Fill="#FFE50A0A"
Data="F1 M 9.3269,3.61737C 13.3742,3.61737 16.6552,6.87332 16.6552,10.8898C 16.6552,14.9063 13.3742,18.1623 9.3269,18.1623C 5.2796,18.1623 1.99862,14.9063 1.99862,10.8898C 1.99862,6.87332 5.27956,3.61737 9.3269,3.61737 Z ">
</Path>
</StackPanel>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
Assuming you mean the states on the CellTemplate using the DataTriggers on Urgency, I think you need to change the Target property on the GoToStateActions
the default value for TargetName is the root scope such as your UserControl or Window.
You want the Target to be the Cell.
http://blogs.msdn.com/expression/archive/2010/02/22/switching-visual-states-easily-using-gotostateaction.aspx
I have this controltempalte + trigger stuff in my WPF application.
<ControlTemplate TargetType="me:MyControl" x:Key="fade">
<ContentPresenter - other stuff />
<ControlTemplate.Triggers>
<Trigger Property="IsTransitioned" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation -<stuff>- />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
This works cool in WPF, and is very intuitive too for me to write this based on trigger as above.
When i port this to Silverlight (3), i am told i have to use VSM, states and groups etc. since triggers on control template is not supported.
I h ave looked at some samples, and i even atempted to apply teh VSM bits in, in the place of trigger as above, but can't get it to work.
Someone suggested to me that apart from VSM in the xaml, i will have to handle some events etc.
SL3 model is just being painful for me. Please help.
Silverlight 3 introduced interaction triggers which as far as I can tell do what you want but are a little more complex. There's very few examples about them out yet though.
If you're doing this manually you need references to System.Windows.Interactivity and Microsoft.Expression.Interactions (from Blend 3, the class will be in your references tab if you've installed it).
If you add the triggers in Blend then it will add those automatically. This is called Behaviours in Silverlight 3 and you will find these in Blend in the Behaviours section of the Assets tab.
An example of how they work. Note the storyboard sitting in the resource of the second rectangle, I couldn't get it to work inside the ControlStoryboardAction.Storyboard, but it did work if I made the rectangle a ContentControl and put it in the Template. This may be a bug or me missing something :
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="SLTrigger.MainPage"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
xmlns:im="clr-namespace:Microsoft.Expression.Interactivity.Media;assembly=Microsoft.Expression.Interactions">
<Grid x:Name="LayoutRoot">
<StackPanel>
<Rectangle Margin="5" Fill="Blue" Width="200" Height="100">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<ic:ChangePropertyAction PropertyName="Fill" Duration="0">
<ic:ChangePropertyAction.Value>
<SolidColorBrush Color="Red"/>
</ic:ChangePropertyAction.Value>
</ic:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
<Rectangle Margin="5" x:Name="AnimatedRectangle2" Fill="Blue" Width="200" Height="100">
<Rectangle.Resources>
<Storyboard x:Key="AnimationStoryboard">
<ColorAnimation
Storyboard.TargetName="AnimatedRectangle2"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Red"
AutoReverse="True"
Duration="0:0:0.5" />
</Storyboard>
</Rectangle.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<im:ControlStoryboardAction ControlStoryboardOption="Play" Storyboard="{StaticResource AnimationStoryboard}">
<!--
Doesn't work, but does work inside control templates??
<im:ControlStoryboardAction.Storyboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="AnimatedRectangle2"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Red"
AutoReverse="True"
Duration="0:0:0.5" />
</Storyboard>
</im:ControlStoryboardAction.Storyboard>
-->
</im:ControlStoryboardAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
<ContentControl>
<ContentControl.Template>
<ControlTemplate>
<Rectangle Margin="5" x:Name="AnimatedRectangle3" Fill="Blue" Width="200" Height="100">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<im:ControlStoryboardAction ControlStoryboardOption="Play">
<im:ControlStoryboardAction.Storyboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="AnimatedRectangle3"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Red"
AutoReverse="True"
Duration="0:0:0.5" />
</Storyboard>
</im:ControlStoryboardAction.Storyboard>
</im:ControlStoryboardAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
<TextBlock TextAlignment="Center" Text="Click the rectangles" />
</StackPanel>
</Grid>
</UserControl>
The class file has nothing in it:
using System.Windows.Controls;
namespace SLTrigger
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
}
}