Button blinking on Datatrigger - wpf

I would like to have a button that blinks/animate when triggered by DataTrigger. I want to animate the button's background. Below is my xaml code.
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid>
<Button x:Name="Button" Content="Button" Width="25" Height="25" Margin="158,62,320,224" Click="Button_Click"></Button>
<Button Style="{StaticResource ButtonStyle}" Content="Button" Focusable="False" Height="75" HorizontalAlignment="Left" Margin="23,146,0,0" Name="btnImgBrush" VerticalAlignment="Top" Width="160"></Button>
</Grid>
</Grid>
Here are the back end code:
public Boolean Notification
{
get { return new_notification; }
set
{
new_notification = value;
RaisePropertyChanged("Notification");
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (Notification)
{
Notification = false;
}
else
{
Notification = true;
}
}
But, it didn't work. Any ideas why it didn't work?
Any help is greatly appreciated, Thanks.

At last its working. Thanks :)
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>

Try this-
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Notification,RelativeSource={RelativeSource AncestorType=Window}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" From="Transparent" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Notification,,RelativeSource={RelativeSource AncestorType=Window}}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>

Both TM Rocket and Vishal answer are correct but probably the following is the most correct and clean way to do it
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>

Related

Not all DataTriggers of StackPanel are working

I have a button which shows a text and an image:
For this I use a StackPanel with a TextBlock and an Image inside of it.
When the variable "ActiveState" changes the Background of the StackPanel should change too, for this I use DataTriggers
ActiveState=0 -> Red /
ActiveState=1 -> Blue /
ActiveState=2 -> blinking Blue (for this I use a Storyboard and a Color Animation)
The blinking Trigger (Value=2) is working fine, but the two other Triggers (Value=0 + Value=1) are not working.
When I remove the Background of the Stackpanel (Background="Transparent") the first two Triggers are working but the last one get the following Exception:
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll
Additional information: Background property does not point to a dependencyobject in path '(0).(1)'
This is my code:
<Button>
<Button.Template>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Horizontal" Name="SelectButtonStackpanel" Background="Transparent">
<TextBlock Text="{Binding Text}"/>
<Image Source="{Binding Image}" Stretch="Uniform" Height="40" Width="40"/>
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding ActiveState}" Value="0">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="1">
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(StackPanel.Background).(SolidColorBrush.Color)"
To="Blue" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever"
>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(StackPanel.Background).(SolidColorBrush.Color)"
Duration="0:0:1"
>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
Do you have any idea how I get all three Triggers working?
best regards
Phil
When you directly set Background="Transparent" on the StackPanel, this has higher precedence than a value set from a Style Setter. So remove the direct assignment and add another Setter for the default Background.
Besides that, if you want to animate Background.Color you should always explictly assign SolidColorBrushes instead of predefined Brushes like Background="Red".
<StackPanel Orientation="Horizontal" Name="SelectButtonStackpanel">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ActiveState}" Value="0">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Red"/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="1">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Blue"/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="Background.Color"
To="Blue" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>

WPF: Stop Animation For Hidden Controls on Windows Load

I have a very simple fade in/out animation which works fine using data triggers. I have bind the data trigger to a bool property and inside trigger it set the opacity to 0 on false and vice versa.
Now the problem is the objects whose bool value is false upon loading, I don't expect them to show on load and then animate themselves to hide.
I have tried to set the opacity to 0 on style setter but no use
Here is the button style
<Style x:Key="LocationPickerButtonStyle" TargetType="{x:Type Button}">
<Style.Setters>
<Setter Property="Height" Value="93"/>
<Setter Property="Width" Value="93"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid >
<Image x:Name="DefaultImage" Source="something.png"/>
<Ellipse x:Name="HitTest" Fill="Transparent" Height="93" Width="93" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsLocationVisible}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="showSelectedLocation">
<Storyboard Storyboard.TargetProperty="Opacity">
<DoubleAnimation Duration="0:0:1" From="0" To="1"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="showSelectedLocation"></StopStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsLocationVisible}" Value="false">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="hideSelectedLocation">
<Storyboard Storyboard.TargetProperty="Opacity" >
<DoubleAnimation Duration="0:0:1" From="1" To="0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="hideSelectedLocation"></StopStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<Trigger Property="Opacity" Value="0">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</Trigger>
<Trigger Property="Opacity" Value="1">
<Setter Property="Visibility" Value="Visible"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Do these changes in your XAML :
Shift your DataTriggers from <ControlTemplate.Triggers> to Style.Triggers.
Set Opacity = 0 in Style Setter as starting Opacity for every Button.
Remove From = 1 in false DataTrigger.
With all the changes, your Style would look like this :
<Style x:Key="LocationPickerButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsLocationVisible}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="showSelectedLocation">
<Storyboard Storyboard.TargetProperty="Opacity">
<DoubleAnimation Duration="0:0:1" From="0" To="1"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="showSelectedLocation"></StopStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsLocationVisible}" Value="false">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="hideSelectedLocation">
<Storyboard Storyboard.TargetProperty="Opacity" >
<DoubleAnimation Duration="0:0:1" To="0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="hideSelectedLocation"></StopStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Height" Value="93"/>
<Setter Property="Width" Value="93"/>
<Setter Property="Opacity" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid >
<Image x:Name="DefaultImage" Source="something.png"/>
<Ellipse x:Name="HitTest" Fill="Transparent" Height="93" Width="93" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Opacity" Value="0">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</Trigger>
<Trigger Property="Opacity" Value="1">
<Setter Property="Visibility" Value="Visible"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>

Trigger on other element with SourcName

I want to enable / disable button by Validation.HasError of a text box. (With Storyboard)
I tried to do it in the following way:
Storyboard :
<Window.Resources>
<Storyboard x:Key="SB" x:Name="SB">
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.IsEnabled)">
<DiscreteBooleanKeyFrame KeyTime="0" Value="False"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
Textbox: (Bind to Num - only int)
<TextBox x:Name="txt1" Grid.Row="1" Text="{Binding Num}" Height="50" Width="200">
Button:
<Button x:Name="Btn1" Height="50" Width="200" Content="My Button">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=txt1, Path=Validation.HasError}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource SB}"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="SB"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
It does not work.
If I put the Style, on the TextBox in the following, it works (it does not allow the TextBox):
<TextBox x:Name="txt1" Grid.Row="1" Text="{Binding Num}" Height="50" Width="200">
<TextBox.Style>
<Style>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource SB}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="SB"/>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The problem is that I can not set SourceName on Trigger like this and put it in the same way on the the button.
If I do that I get error:
SourceName property cannot be set within Style.Triggers section.
I'd love some help...
All I was missing, it brackets:
<DataTrigger Binding="{Binding ElementName=txt1,Path=(Validation.HasError)}" Value="True">

DataTrigger breaks the previous one

There are two DataTriggers. Right after launching application both triggers work, but after second trigger fires the first doesn't work anymore. How to fix this problem?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ButDown,Path=IsPressed}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Margin" By="20" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ButUp,Path=IsPressed}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Margin" By="-20" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<Button x:Name="ButUp">UP</Button>
<Button x:Name="ButDown">DOWN</Button>
<TextBlock Margin="100">TextBlock</TextBlock>
</StackPanel>
</Window>

WPF DataTrigger cannot find Trigger Target

<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid">
<Grid.Background>
<SolidColorBrush x:Name="backgroundBrush" Color="Transparent" Opacity="0.1"/>
</Grid.Background>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsExpanded}" Value="True">
<Setter TargetName="backgroundBrush" Property="Color" Value="Green" />
</DataTrigger>
<Trigger SourceName="grid" Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="backgroundBrush"
Storyboard.TargetProperty="Color"
To="White" Duration="0:0:1.5"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="backgroundBrush"
Storyboard.TargetProperty="Color"
AccelerationRatio="1" Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
Doesn't compile with error 'Cannot find the trigger target 'backgroundBrush'.'
If I remove the DataTrigger it will compile and work. If I change the DataTrigger to use TargetName="grid" Property="Background" it will compile and work (but without the desired opacity).
Where am I going wrong?
While I'm not sure why the brush isn't in the namescope, you can do this by swapping out the brush, and "dotting-down" to the Color property of the background brush in the animations like so:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid">
<Grid.Background>
<SolidColorBrush Color="Transparent" Opacity="0.1"/>
</Grid.Background>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsExpanded}" Value="True">
<Setter TargetName="grid" Property="Background">
<Setter.Value>
<SolidColorBrush Color="Green" Opacity="0.1"/>
</Setter.Value>
</Setter>
</DataTrigger>
<Trigger SourceName="grid" Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="grid"
Storyboard.TargetProperty="Background.Color"
To="White" Duration="0:0:1.5"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="grid"
Storyboard.TargetProperty="Background.Color"
AccelerationRatio="1" Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>

Resources