DataTrigger don't seems to fire - wpf

I want to create a datatrigger that makes my page blink (from transparent to red). So I created a DataTrigger that listens to a boolean flag within my viewmodel. This flag shall indicate whenever the user needs to be reminded. In that case, my page shall blink from transparent to red.
I was pretty sure that I have implemented the data trigger in a correct manner, but my app does nothing - no error, no blinking... So I must have something missed.
<Style x:Key="ReminderPage" TargetType="{x:Type ViewTemplates:TpApplicationBarView}" BasedOn="{StaticResource TpApplicationBarViewStyle}">
<Style.Triggers>
<!-- Reminder animation, when the time comes to remind the user -->
<DataTrigger Binding="{Binding IndicateReminderAnimation}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard x:Name="Blink">
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
AutoReverse="True"
From="Transparent"
To="Red"
Duration="0:0:1"
RepeatBehavior="Forever">
</ColorAnimation >
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding IndicateReminderAnimation}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
AutoReverse="False"
To="Transparent"
Duration="0:0:1">
</ColorAnimation >
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
So, what do I have done wrong?
Update: I can see the following message in the output window:
System.Windows.Media.Animation Warning: 6 : Unable to perform action because
the specified Storyboard was never applied to this object for interactive control.;
Action='Stop'; Storyboard='System.Windows.Media.Animation.Storyboard';
Storyboard.HashCode='61356140'; Storyboard.Type='System.Windows.Media.Animation.Storyboard';
TargetElement='System.Windows.Media.Animation.Storyboard'; TargetElement.HashCode='61356140';
TargetElement.Type='System.Windows.Media.Animation.Storyboard'
Update2: After googling arround I found out, that it is a problem with the UI Thread. So I made a dispatcher call whenever I set the bound property. But even with this trick, there's no color animation. But the error in the output window seems to be vanished. So, I'm searching for further ideas on how to fix the animation.
Update3: It seems to be a general problem setting the background color of the page. But it's really strange. The Page is placed in a NavigationFrame. Setting the background color of the navigation frame will change the color of the application, but setting the background color of the page (even without any animation) won't change anything.

I think you will have to set the animations Target, something like this -
Storyboard.TargetName="yourWindowName"
You may have already checked this, but make sure that correct object is set as your TpApplicationBarView's DataContext(having IndicateReminderAnimation property).

I found the bug - or better the two bugs.
1.) It seems not be possible to change the background color of a page that is placed within a Navigation Frame.
So first was to move the binding and event to the MainWindow itself (wpf window class)
2.) The Style that contains the data trigger did not work. After googling around I found a working solution for what I'm searching for.
<Storyboard x:Key="RemindUser" >
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
AutoReverse="True"
From="Transparent"
To="{StaticResource WinAccentBackgroundColor}"
Duration="0:0:1"
RepeatBehavior="Forever">
</ColorAnimation >
</Storyboard>
<Storyboard x:Key="StopRemindUser">
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
AutoReverse="True"
To="Transparent"
Duration="0:0:1">
</ColorAnimation >
</Storyboard>
<Style x:Key="ReminderWindow" TargetType="{x:Type Metro:SnappedTransparentWindow}" BasedOn="{StaticResource TransparentWindow}">
<Style.Triggers>
<!-- Reminder animation, when the time comes to remind the user -->
<DataTrigger Binding="{Binding IndicateReminderAnimation}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource RemindUser}"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource StopRemindUser}"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
The key was to split the binding and storyboard into different parts.

Related

Go back to old color after storyboard color animation in WPF

I have a datagrid where the row color is decided by a level parameter that I convert in my rowstyle. This is fine but now I also want to change the color temporarily when I enter the row with my mouse and drag and drop (and change back when I leave or drop). I manage to change the color with this code:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource MyDataGridRowStyle}">
<Setter Property="Background" Value="{Binding Level,Converter={StaticResource LevelToIndentConverter}}" />
<Style.Triggers>
<EventTrigger RoutedEvent="DataGridRow.DragEnter">
<BeginStoryboard x:Name="DragHoverStoryboard">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Background.Color"
Duration="0:0:0" To="#41B1E1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="DataGridRow.DragLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Background.Color"
Duration="0:0:0" To="Transparent" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
The problem is to get back to the orginal color. Currently I have "To" as transparent in the DragLeave event trigger but I want it to be my "old" color.
I tried to do a simple bind (same as my setter) but I got exception and read that you can't bind color animations. So is there something else I can use or get around this problem? In summary I simply want this:
Mouse enter row with drag and drop
Row change to color x
Mouse leave row (or I drop)
Row change back to it's color y (where y is different for different rows so not hard coded).
then add this to property to your animation and remove the second animation
FillBehavior="Stop"

WPF Datagrid events DataTriggers vs EventTriggers

relatively simple question that I am struggling to find a nice elegant solution to. I have a grid with a column that displays values that update every n seconds. I wish to show an animation when the value changes and flash the cell in different colours based on if the number is negative or positive. Found a whole host of methods that do almost what I want, but nothing that exactly matches my needs.
Using an EventTrigger I can make a cell flash every time an update occurs. Using a relatively simple animation below. But I am unable to make the colour the animation uses conditional as the storyboard freezes the UI elements, so I cannot use binding in the storyboard to define the colour.
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard HandoffBehavior="Compose" Name="GreenCell">
<Storyboard TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)">
<ColorAnimation Duration="0:0:1.50" From="Green" To="Transparent" AutoReverse="False"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
Using a DataTrigger I can make the cell colour conditional by creating a Converter that converts the updates to this Value and if the value is negative and then binding a data trigger to this and setting the background colour when this changes. But if the number is already negative, and remains negative (but changes) the trigger is not fired.
<DataTrigger Binding="{Binding Value, Converter={StaticResource cellBackGroundConverter}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard HandoffBehavior="Compose" Name="GreenCell">
<Storyboard TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)">
<ColorAnimation Duration="0:0:1.50" From="Green" To="Transparent" AutoReverse="False"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding Value, Converter={StaticResource cellBackGroundConverter}}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard HandoffBehavior="Compose" Name="RedCell">
<Storyboard TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)">
<ColorAnimation Duration="0:0:1.50" From="Red" To="Transparent" AutoReverse="False"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
What I require seems to be an event trigger, to capture every update and play the animation with the conditional aspect of the data trigger.
Surely I am missing something simple here, would love for someone to set me straight!
Many thanks
Matt

How to make a DevExpress grid row blink?

Trying to perform a simple red blinking effect for a single row in a DevExpress grid.
I've applied the following style on the grid's row:
<Style x:Key="AlertedRowStyle" TargetType="{x:Type dxg:GridRowContent}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Row.IsAlerted}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="Background"
To="Red"
Duration="0:0:0.500"
AutoReverse="True"
RepeatBehavior="Forever">
<ColorAnimation.EasingFunction>
<CircleEase EasingMode="EaseOut" />
</ColorAnimation.EasingFunction>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="Background"
To="White"
Duration="0:0:0.500" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
It causes the following exception:
'System.Windows.Media.Animation.ColorAnimation' animation object cannot be used to animate property 'Background' because it is of incompatible type 'System.Windows.Media.Brush'.
Also tried to change the Storyboard.TargetProperty to Background.Color and got:
Cannot resolve all property references in the property path 'Background.Color'. Verify that applicable objects support the properties.
How can I solve this issue?
Storyboard.TargetProperty="Background.Color" is right. Try
<Style x:Key="AlertedRowStyle" TargetType="{x:Type dxg:GridRowContent}">
<Setter Property="Background" Value="Transparent" />
<Style.Triggers>
...
I guess Background is Null and so the Storyboard can not find something to animate.
Try
Storyboard.TargetProperty="Background.(SolidColorBrush.Color)"
worked for me.
you can open a new thread. In this thread you use a loop. In this loop you can change the Backcolor of the row. In the loop you sleep the thread for 0.3 sec or something. So it should look like blinking.
regards

How do I bind to a color in a WPF ColorAnimation?

I would like to do something that is seemingly quite simple, but I cannot figure out how to do it. I have a ColorAnimation that is triggered when the MouseEnter event occurs. It simply changes the background color of a Border from one color to another color.
Unfortunately, I can't figure out how to put anything but hardcoded colors into this ColorAnimation. So it looks currently like this:
<Style x:Key="MouseOverStyle">
<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.5" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="Red" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
However, I'd like do something either like this:
<SolidColorBrush x:Key="MyEventColor" Color="{Binding EventColor}" />
<Style x:Key="MouseOverStyle">
<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.5" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="{StaticResource MyEventColor}" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
Or like this:
<Style x:Key="MouseOverStyle">
<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.5" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="{Binding EventColor}" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
When I try to do either of those, an exception gets thrown. For the first, it throws an exception telling me essentially that the "Color" property can't take a SolidColorBrush value...which makes sense...but it certainly doesn't help me out because the ColorAnimation won't let me animate the "(Border.Background).(SolidColorBrush)" property...it will only let me animate the "(Border.Background).(SolidColorBrush.Color)" property....
The exception on the second example basically tells me that it "Cannot freeze this Storyboard timeline tree for use across threads" ...so it sounds like the ColorAnimation is trying to do this binding in some other thread than the UI thread or something? Whatever it's trying to do...it isn't working.
How the heck can I do such a simple task?
For the first one, you could use {StaticResource MyColor} with MyColor defined as such:
<Color x:Key="MyColor">#FF00FF00</Color>
However, this doesn't solve your problem: you can't bind to animation properties since those properties need to be frozen (unchangeable) for the animation to work. Either try to remove your dependence on a binding, or recreate the storyboard with the correct color from code behind when the color changes.

How can I get a trigger to fire when the contents of a StackPanel changes?

The following code makes the contents of a StackPanel fade in when it is loaded (StackPanel.Loaded).
What do I have to change to get the fade it to start when the contents of the StackPanel change, e.g. every time a message in the StackPanel changes I want it to fade in again?
<Style x:Key="MessageStyle" TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding SaveStatus}" Value="Failed">
<Setter Property="StackPanel.Background" Value="Red"/>
</DataTrigger>
<EventTrigger RoutedEvent="StackPanel.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(StackPanel.Opacity)"
From="0.0" To="1.0" Duration="0:0:5"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
You should be able to do what you're looking for with the StackPanel.SourceUpdated/StackPanel.TargetUpdated event after setting the accompanying
NotifyOnSourceUpdated/NotifyOnTargetUpdated property to True on the binding that binds the contents of the StackPanel.

Resources