How can I make a XAML Trigger call a XAML Style? - wpf

This style correctly fades my toolbar in or out based on the changing of a ViewModel Property:
<Style x:Key="PageToolBarStyle" TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding PageToolBarVisible}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="0.0"
To="1.0"
Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="1.0"
To="0.0"
Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<Trigger Property="Opacity" Value="0">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
</Style.Triggers>
</Style>
However, when the application loads the status of the toolbar (faded out or in) is not in sync with the value of the ViewModel property (true or false). So I want to force this style to be executed upon loading the window, what is the syntax to do this, here is pseudo code of what I want to do:
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<EventTrigger.Actions>
<!-- PSEUDO-CODE: -->
<ExecuteTriggerStyle StyleToExecute="{StaticResource PageToolBarStyle}"/>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>

Related

Visibility fadeout and fade in infinite loop

I have some Grid with some element inside and I want to add it some fade in fade out effect with Visibility property in infinite loop base on some bool property.
This is what I have tried:
<Grid.Style>
<Style TargetType="FrameworkElement">
<Setter Property="Visibility" Value="Visible"/>
<Setter Property="Opacity" Value="0"/>
<Style.Triggers>
<Trigger Property="Visibility" Value="Collapsed">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0.0"
To="1.0"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
Currently I cannot see my Grid at all.
There are a few issues in your style:
You do not see the Grid, because you set the initial Opacity to 0.
You can remove both of your Setters, because those are the default values
Making the trigger dependent on Visibility does not work, because when it is set to Collapsed, the Grid is already invisible, so the animation is not even visible.
There is no exit action to make the Grid fade in again.
You could solve the issues by exposing a property (here MyAnimationTriggerProperty) that you use as trigger for the animation. Depending o your actual application this could also be the IsChecked state of another control. Then you can add an ObjectAnimationUsingKeyFrames to set the Visibility at the end of the animation.
<Style TargetType="FrameworkElement">
<Style.Triggers>
<DataTrigger Binding="{Binding MyAnimationTriggerProperty}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="1.0"
To="0.0"
Duration="0:0:0.2"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.2" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0.0"
To="1.0"
Duration="0:0:0.2"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>

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.

WPF XAML Animation How do i stop it when bound boolean becomes false?

I want the animation to stop when the boolean CanAnimate becomes false. It starts on true, so how do i tell it to stop when CanAnimate is false? (The CanAnimate bool is set inside a SelectedItem setter)
<Border BorderBrush="Black" BorderThickness="2" Margin="1" Name="ReviewNote">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding CanAnimate}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Border.Opacity)"
From="1.0" To="0.0" AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock/>
</Border>
You can try using the ExitActions on the DataTrigger to stop the animation, by overriding with another animation. For instance:
<DataTrigger Binding="{Binding CanAnimate}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Border.Opacity)"
From="1.0" To="0.0" AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Border.Opacity)"
From="0.0" To="0.0" Duration="0:0:0.0" FillBehavior="HoldEnd" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
Alternatively, there is a way to stop storyboards in XAML by name, again you could use ExitActions for this. This previous question shows the way.
Hope this helps!

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>

EventTrigger in XAML when a property changes?

I have this code (it's working, so far);
<Image Name="img_person" Tag="{Binding Path=MyProperty1, NotifyOnTargetUpdated=True}" Canvas.Top="0" Canvas.Left="0">
<Image.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="img_person"
Storyboard.TargetProperty="(Canvas.Top)"
By="64"
Duration="0:0:0.8"
AutoReverse="False" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
I'd like to change this line;
<EventTrigger RoutedEvent="Binding.TargetUpdated">
To something like this;
<EventTrigger ThisParticularPropertyHasChanged="MyProperty1">
I want to do this as I'll have several storyboards, each to be started when a particular property changes. With 1 property I've been binding it to the image's Tag property, but now that I have several to do (roughly 8) I'm not sure how to go about this.
The class implement INotifyPropertyChanged.
thanks.
SOLUTION, thanks to sa_ddam213;
<Style x:Key="PersonImageStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="South">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="64" Duration="0:0:0.8" AutoReverse="False" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="East">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="64" Duration="0:0:0.8" AutoReverse="False" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>

Resources