Why XAML defined animation causes System.InvalidOperationException - wpf

I need define simple animation in the XAML (without code behind), that must rotate the background image of button by changing the bounded boolean property. I have a button in the XAML:
<Button Style="{StaticResource btnStyle}" />
In the Resources section of the Window I create following:
<RotateTransform Angle="180" x:Key="rotAt180" />
<Style TargetType="Button" x:Key="btnStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image Source="Images\pic.png" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding MyBoolProp}" Value="False">
<Setter Property="RenderTransform" Value="{StaticResource rotAt180}" />
<!-- This animation works good -->
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="180" Duration="0:0:0.2" Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<!-- This animation causes exception -->
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="180" To="0" Duration="0:0:0.2" Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
MyBoolProp is initialized by True.
The first animation is works perfect. But the second animation causes System.InvalidOperationException in PresentationFramework.dll ("Unable to resolve all property references in the "RenderTransform.Angle" property path. Check that the corresponding objects support such properties").
I tried to move the second animation into the trigger, where MyBoolProp is True:
<DataTrigger Binding="{Binding MyBoolProp}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="180" To="0" Duration="0:0:0.2" Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
But the result is the same. What is wrong in such realization?

The RenderTransform must be set in the Style, not in the DataTrigger:
<Style TargetType="Button" x:Key="btnStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image Source="Images\pic.png" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="RenderTransform" Value="{StaticResource rotAt180}"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
<Style.Triggers>
<DataTrigger Binding="{Binding MyBoolProp}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="0" Duration="0:0:0.2"
Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="180" Duration="0:0:0.2"
Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>

Related

WPF Style Property Trigger not firing on load

I have a style trigger on my Buttons IsEnabled property that fires and wiggles my buttons when set to True. This works fine if I disable and then re-enable the button from the code behind (MVVM) once the application has loaded and running. However, the trigger does not fire on initial load. So all my buttons that are enabled by default do not wiggle. What can I do to make the trigger work on load?
Here is my Style from my App.xaml
<Setter Property="RenderTransformOrigin" Value="0.5,0" />
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform />
</Setter.Value>
</Setter>
<Style TargetType="{x:Type Button}" x:Key="btnDefaultStyle">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetProperty="RenderTransform.Angle" RepeatBehavior="Forever">
<DoubleAnimation From="0" To="-5" BeginTime="0:0:0:5.00" Duration="0:0:0.05"/>
<DoubleAnimation From="-5" To="0" BeginTime="0:0:0:5.05" Duration="0:0:0.05"/>
<DoubleAnimation From="0" To="4" BeginTime="0:0:0:5.10" Duration="0:0:0.05"/>
<DoubleAnimation From="4" To="0" BeginTime="0:0:0:5.15" Duration="0:0:0.05"/>
<DoubleAnimation From="0" To="-3" BeginTime="0:0:0:5.20" Duration="0:0:0.05"/>
<DoubleAnimation From="-3" To="0" BeginTime="0:0:0:5.25" Duration="0:0:0.05"/>
<DoubleAnimation From="0" To="2" BeginTime="0:0:0:5.30" Duration="0:0:0.05"/>
<DoubleAnimation From="2" To="0" BeginTime="0:0:0:5.35" Duration="0:0:0.05"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard TargetProperty="RenderTransform.Angle">
<DoubleAnimation From="0" To="0" BeginTime="0:0:0:0" Duration="0:0:0.0"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource btnDefaultStyle}" />
EventTriggers RoutedEvent, I.e. RoutedEvent="Window.Loaded" is no use as it overrides the Property IsEnable event, and therefore my disabled buttons also wiggle.
Use DataTrigger like below :
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
...
</BeginStoryboard>
</DataTrigger.EnterActions>
...
</DataTrigger>
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="False">
...
</DataTrigger>
This works at load time too.

ListBoxItem in WPF - scale animation when selected

I have a ListBox with customized item's style. I want the item to grow a bit when selected, and go back to its original size when deselected. I've tried several solutions but none seemed to work. I think the problem lies in the proper setting of Storyboard.TargetProperty.
My current XAML looks like this:
...
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="LayoutTransform.(ScaleTransform.ScaleX)" To="1.2" Duration="0:0:.3" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
...
My final code (with answers applied):
...
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" To="1.1" Duration="0:0:.1" />
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" To="1.1" Duration="0:0:.1" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" To="1.0" Duration="0:0:.1" />
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" To="1.0" Duration="0:0:.1" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
...
Try using following code:
...
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform x:Name="scaleTransform" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleX" To="1.2" Duration="0:0:.3" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
...

WPF XAML Grid Visibility Trigger

I have a status message located on the first row of my grid and I want it to slide in and out when the visibility changes.
The first visibility trigger works great and slides the first grid row open quickly. As soon as I add the 'Collapsed' trigger, nothing works at all. How do I reverse the animation to slide closed when the visibility is set to collapsed?
<Grid Grid.Row="0" Height="55" Visibility="{Binding StatusMessageVisibility, Mode=TwoWay}">
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height" From="0" To="55" Duration="0:0:.1" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="Visibility" Value="Collapsed">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height" From="55" To="0" Duration="0:0:.1" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
<TextBlock Text="Hi There" />
</Grid>
You should remove the Visibility binding in your grid and use a DataTrigger that binds to the StatusMessageVisibility property. If you bind the grid's visibility then once it's collapsed it's collapsed and you won't be able to see the animation.
Also, instead of having two data triggers with EnterActions, use a single data trigger that also has an ExitAction for the collapsed state:
<Grid Grid.Row="0" Height="55">
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding StatusMessageVisibility}" Value="Visible">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height" From="0" To="55" Duration="0:0:.1" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height" From="55" To="0" Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<TextBlock Text="Hi There" />
</Grid>

How do I write WPF Trigger to change cursor on textblock hover

I have a textblock that currently has a trigger that sets the foreground colour when the mouse enters and back to the default when it leaves. The problem I have is that I would also like the mouse pointer to change I currently have the following
<Style TargetType="TextBlock" x:Key="FlatStyleButton">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#FF333333" />
<Style.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.3" Storyboard.TargetProperty="Foreground.Color" To="CornflowerBlue" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.3" Storyboard.TargetProperty="Foreground.Color" To="White" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
I have tried adding <Setter Property="Cursor" Value="Hand"></Setter> to various places but it never seems to work
Sorry guys Proper school boy error on my part im afraid, what I was trying would have worked but I was modifiying in the wrong resource file. So if anyone else is intrested the answer was:
<Style TargetType="TextBlock" x:Key="FlatStyleButton">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#FF333333" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand" />
</Trigger>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.3" Storyboard.TargetProperty="Foreground.Color" To="CornflowerBlue" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.3" Storyboard.TargetProperty="Foreground.Color" To="White" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>

WPF Multiple DataTriggers bound to same source

I finally tracked down my storyboard datatrigger issue. The issue appears to occur because I have 2 DataTriggers bound to the same viewmodel property:
<Grid Panel.ZIndex="95" Height="234" HorizontalAlignment="Left" Margin="0,85,0,0" Name="grid1" VerticalAlignment="Top" Width="64" Background="#FF454540" Opacity="1">
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding SearchMenuState}" Value="{x:Static local:SideMenuState.Shown}">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Duration="0:0:.1" Storyboard.TargetProperty="Margin" To="69,85,0,0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding SearchMenuState}" Value="{x:Static local:SideMenuState.Hidden}">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Duration="0:0:.1" Storyboard.TargetProperty="Margin" To="0,85,0,0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
When I comment out the second DataTrigger, the first one works. Why is that, and how can I correct it so that both work?

Resources