Animation causes button to become invisible - wpf

I've been trying to get a user control to animate when IsEnabled changes.
Loosely based on this post Button Blinking on DataTrigger
However, when I include the ControlTemplate style the button is invisible. :)
<UserControl x:Class="View.UserControls.MainButton"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="40" d:DesignWidth="300">
<UserControl.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="MinHeight" Value="24" />
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="3" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
</Style>
<Style TargetType="{x:Type Image}">
<!--<Setter Property="Height" Value="32" />
<Setter Property="Width" Value="32" />-->
<Setter Property="Stretch" Value="Uniform" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="5 0 0 0" />
</Style>
</UserControl.Resources>
<Button Width="{Binding Width, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
Command="{Binding Command, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
ToolTip="{Binding ToolTip, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<StackPanel>
<Image Source="{Binding ButtonImageSource, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<TextBlock Text="{Binding ButtonText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
</StackPanel>
</Button>

Move the triggers to the Style and avoid overriding the ControlTemplate if you want the Button to still look like a Button:
<Style TargetType="{x:Type Button}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="MinHeight" Value="24" />
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="3" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>

The template defines the visual appearance of the control. Anything not put there by the template isn't there. Your template puts no visual elements in the control. Therefore, there is nothing visual to be seen.
If you're replacing the template, at absolute minimum, you'll have to give it a ContentPresenter inside a Border that will show the blinking Background brush color:
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter
/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="3" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
But if you're happy with the standard Button template, use mm8's approach instead, which leaves that in place. Rewriting standard templates usually turns out to be a lot more effort than it's worth, if you can find another way to do what you need to.

Related

XAML: Style ControlTemplate storyboard animation won't play, but trigger IS hit

I have a button style which I'm currently making. I want to trigger a smooth animation when the user clicks on the button. I need the two rectangle to be contained within the ControlTemplate as shown below.
The idea is that upon pressing the button, one of the rectangles fades out, and upon releasing it fades back in.
The triggers ARE being hit. I can prove this by adding a simple colour change for the buttons by doing the following before the Trigger.EnterActions:
<Setter TargetName="BackgroundNormal" Property="Fill" Value="Cyan" />
The storyboards seem not to trigger at all regardless of their content.
What am I doing wrong, please?
<Style x:Key="MyButton" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{DynamicResource TextParagraphWhiteP1}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontWeight" Value="Light" />
<Setter Property="Background" Value="{DynamicResource Gradient_Playback_ButtonBase}" />
<Setter Property="MinHeight" Value="15" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="Padding" Value="6,2" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="BackgroundDepressed" Fill="Magenta" />
<Rectangle x:Name="BackgroundNormal" Fill="{DynamicResource Gradient_Playback_ButtonBase}" />
</Grid>
<ControlTemplate.Resources>
<Storyboard x:Key="PressDown">
<DoubleAnimation Storyboard.TargetName="BackgroundNormal" Storyboard.TargetProperty="(UIElement.Opacity)" To="0.0" Duration="0:0:0.1" />
</Storyboard>
<Storyboard x:Key="Release">
<DoubleAnimation Storyboard.TargetName="BackgroundNormal" Storyboard.TargetProperty="(UIElement.Opacity)" To="1.0" Duration="0:0:0.35" />
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource PressDown}" />
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsPressed" Value="false">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Release}" />
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

WPF Multiple Triggers & DataTrigger on Button Style

Working on a "data entry style" program. After a certain combination of data changes a property IsSaveNeeded (enum: Yes, No) is set to Yes and the Save button is suppose to flash.
I have been able to get the button to flash with a basic button
<!--Save Button-->
<Button Content=" Save
Settings
 to File" x:Name="SaveBtn" Command="{Binding SaveCMD}" Padding="10,5" Margin= "10,0" IsEnabled="{Binding SaveEnabled}"
Background="{StaticResource {x:Static SystemColors.ControlLightBrushKey}}">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSaveNeeded}" Value="Yes">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="FlashBackground">
<Storyboard BeginTime="00:00:00" RepeatBehavior="Forever" >
<ColorAnimation Storyboard.TargetProperty="Background.Color" Duration="00:00:00.75" AutoReverse="True" To="Red" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="FlashBackground" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I have been required to make all the buttons a custom style button.
<!--My Custom Buton-->
<Style x:Key="myBtn" TargetType="{x:Type Button}">
<Setter Property="Background" Value="White" />
<Setter Property="Margin" Value="0" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="{StaticResource myColorBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid UseLayoutRounding="True" SnapsToDevicePixels="True">
<!--Button Content / DropShadow / Border-->
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" CornerRadius="5" BorderThickness="1" BorderBrush="{StaticResource myColorBrush}">
<Border.Effect>
<DropShadowEffect ShadowDepth="4" Direction="330" Color="Black" Opacity="0.2" BlurRadius="4"/>
</Border.Effect>
</Border>
<Border Padding="{TemplateBinding Padding}" UseLayoutRounding="True" SnapsToDevicePixels="True">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Content}" SnapsToDevicePixels="True" >
<!--<TextBlock.Effect>
<DropShadowEffect ShadowDepth="4" Direction="330" Color="{StaticResource MyColor}" Opacity="0.3" BlurRadius="4"/>
</TextBlock.Effect>-->
</TextBlock>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="#FFC1C1C1" />
<Setter Property="Foreground" Value="#FFACA8A8" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource myHoverBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{StaticResource myColorBrush}"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
I need to add the IsSaveNeeded DataTrigger to this custom button style, myFlashingBtn, but when I do the Flashing works but the other Triggers stop working.
How do I incorporate the IsSaveNeeded Flashing into my custom button style and keep all the Triggers working? MultiTrigger and MultiDataTriggers haven't helped unless I wrote them wrong.
I believe you're looking for the BasedOn property (Style.BasedOn).
This allows you to inherit everything from a specific style and add to it.
<!--Save Button-->
<Button Content=" Save
Settings
 to File" x:Name="SaveBtn" Command="{Binding SaveCMD}" Padding="10,5" Margin= "10,0" IsEnabled="{Binding SaveEnabled}" >
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource myBtn}">
<Setter Property="Background" Value="{StaticResource {x:Static SystemColors.ControlLightBrushKey}}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSaveNeeded}" Value="Yes">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="FlashBackground">
<Storyboard BeginTime="00:00:00" RepeatBehavior="Forever" >
<ColorAnimation Storyboard.TargetProperty="Background.Color" Duration="00:00:00.75" AutoReverse="True" To="Red" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="FlashBackground" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Edit: I moved the Background to a setter of the Style

Button background color is not updating when button clicked

My WPF application is not updating button background for when button is clicked AND mouse cursor is over it. The backgrund color is still light green. Other property changes are working ok. What is wrong?
File ControlStyles.xaml
...
<Style TargetType="{x:Type Button}" x:Key="MyButton">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="DarkCyan"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="20"/>
<Style.Triggers>
<Trigger Property="Control.IsMouseOver" Value="true">
<Setter Property="Control.FontStyle" Value="Italic"></Setter>
<Setter Property="Control.Foreground" Value="Red"></Setter>
<Setter Property="Control.Background" Value="black"></Setter>
</Trigger>
<Trigger Property="Button.IsPressed" Value="true">
<Setter Property="Control.Foreground" Value="Firebrick"></Setter>
<Setter Property="Control.Background" Value="Yellow"></Setter>
</Trigger>
</Style.Triggers>
</Style>
...
Window.xaml
...
<Button Name="btn7" Content="7" Grid.Column="0" Grid.Row="3" Style="{StaticResource MyButton}" Click="btn7_Click"/>
<Button Name="btn8" Content="8" Grid.Column="1" Grid.Row="3" Style="{StaticResource MyButton}" Click="btn8_Click"/>
...
See if this solves your problem :
<Style TargetType="{x:Type Button}" x:Key="MyButton">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="DarkCyan"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="20"/>
<Style.Triggers>
<Trigger Property="Control.IsMouseOver" Value="true">
<Setter Property="Control.FontStyle" Value="Italic"></Setter>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="Black"/>
<ColorAnimation Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)" To="Red"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="DarkCyan"/>
<ColorAnimation Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)" To="Black"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="Button.IsPressed" Value="true">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="Yellow"/>
<ColorAnimation Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)" To="Firebrick"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
This is my solution with usage of ControlTemplate. It's important to use x:Name and TargetName inside of it.
ControlTemplate.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ControlTemplate TargetType="{x:Type Button}" x:Key="MyButtonTemplate">
<Border x:Name="tempBorder" CornerRadius="20" Margin="4" BorderThickness="1" BorderBrush="Black" Background="Gold">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Margin="8,6,8,6" ContentSource="Content" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="tempBorder" Property="Background" Value="MediumVioletRed"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="tempBorder" Property="Background" Value="LightPink"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ResourceDictionary>
ConstrolStyles.xaml:
...
<Style TargetType="{x:Type Button}" x:Key="MyButton">
<!-
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="DarkCyan"/>
-->
...
Window.xaml:
...
<Button Name="btnAdd" Content="Add" Grid.Column="4" Grid.Row="1" Style="{StaticResource MyButton}" Template="{StaticResource MyButtonTemplate}" />
...
App.xampl:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/MyColors.xaml"/>
<ResourceDictionary Source="Styles/ControlStyles.xaml"/>
<ResourceDictionary Source="Styles/ControlTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

Path Animation into a Button

I have a button with a Path, What I want is that when I make a click over the button the path moves to the rigth side; I've added the style and the trigger to the button, but it doesn't work. I've tried to add the trigger to the ControlTemplate but it doesn't let me
If you have any suggestions, I'd appreciate it.
This is my code:
<Button x:Name="btnEnviarCorreo" Height="50" Width="100" Padding="5" Content="Enviar Correo" Margin="2,2" >
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="SteelBlue"/>
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="15" />
<Setter Property="FontFamily" Value="./#Segoe UI" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="{TemplateBinding Background}">
<Grid>
<Path x:Name="PathIcon" Width="15" Height="25" Stretch="Fill" Fill="#E59400" HorizontalAlignment="Left" Margin="17,0,0,0" Data="F1M30.0833,22.1667L50.6665,37.6043 50.6665,38.7918 30.0833,53.8333 30.0833,22.1667z"/> <ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E59400" />
<Setter Property="Foreground" Value="White" />
<Setter TargetName="PathIcon" Property="Fill" Value="Black" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="OrangeRed" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PathIcon" Storyboard.TargetProperty="RenderTransform.(TranslateTransform.X)" From="0" To="200" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Thanks for your time.
Add the following code somewhere inside ControlTemplate.Triggers block:
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation From="17,0,0,0" To="100, 0, 0, 0" Duration="0:0:1" Storyboard.TargetProperty="Margin"
Storyboard.TargetName="PathIcon"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
It's not perfect, you should work out to set some details on your own. I use animation for Margin within an EventTrigger. You can try to make some other experiments :D

How to address children of a style ControlTemplate for animation?

I have a custom control extending a toggle button. This custom control has three dependency properties for ImageSources that can be used to customize Images that present a certain visual impression:
<Style TargetType="{x:Type local:SimpleFeedbackToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SimpleFeedbackToggleButton}">
<Grid x:Name="BtnGrid">
<Image x:Name="FeedbackImage" Source="{TemplateBinding FeedbackImageSource}" Visibility="Hidden" />
<Image x:Name="NormalImage" Margin="{TemplateBinding Padding}" Source="{TemplateBinding NormalImageSource}" />
<Image x:Name="DisabledImage" Source="{TemplateBinding DisabledImageSource}" Visibility="Hidden" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Visibility" Value="Visible" TargetName="DisabledImage"/>
<Setter Property="Opacity" Value="1.0" TargetName="BtnGrid"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Visibility" Value="Visible" TargetName="FeedbackImage"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding FeedbackBlink, RelativeSource={RelativeSource Self}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="SB_BlinkFeedback">
<Storyboard Storyboard.TargetProperty="Opacity">
<DoubleAnimation From="1.0" To="0.3" Duration="0:0:1" RepeatBehavior="Forever" AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="SB_BlinkFeedback" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
Another dependency property FeedbackBlink shall be used to start and stop blinking of only one of the images (FeedbackImage). Unfortunately I cannot find out how to address this image from the Storyboard "SB_BlinkFeedback". How could I do that?
Found a working solution shortly after posting the question: I had to move the DataTrigger from <Style.Triggers> to <ControlTemplate.Triggers>. Then the Storyboard declaration can be completed by Storyboard.TargetName="FeedbackImage" without compiler or runtime error.

Resources