Bold changed cells in DataGrid - wpf

I would like to bold changed DataGrid cells when data source gets updated. I found that <EventTrigger RoutedEvent="Binding.TargetUpdated"> is the event I need. However I cannot get the Storyboard to work with the FontWeight property.
Here is what I am trying:
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<Int32Animation Duration="00:00:05"
Storyboard.TargetProperty="(Int32)(DataGridCell.FontWeight)"
From="400" To="700" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
Can someone please recommend how to get the above fixed or propose new smarter way of bolding changed cells in DataGrid?

This works for me...
I have a resource...
<Style TargetType="TextBlock" x:Key="ElementStyle">
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames
Duration="00:00:01"
Storyboard.TargetProperty="(TextElement.FontWeight)">
<DiscreteObjectKeyFrame
KeyTime="00:00:00"
Value="{x:Static FontWeights.Thin}" />
<DiscreteObjectKeyFrame
KeyTime="00:00:00.5"
Value="{x:Static FontWeights.Heavy}" />
<DiscreteObjectKeyFrame
KeyTime="00:00:01"
Value="{x:Static FontWeights.UltraBold}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
Assign this to relevant column,
<toolkit:DataGridTextColumn
Binding="{Binding Quantity, NotifyOnTargetUpdated=True}"
ElementStyle="{StaticResource ElementStyle}" />
EDIT
Bcause the code above makes the default values also Bold, we have another way to do this wherein ONLY the updates done by user would trigger boldness in the cell.
Style
<Style TargetType="Controls:DataGridCell"
BasedOn="{StaticResource {x:Type Controls:DataGridCell}}"
x:Key="CellBoldStyle">
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.SourceUpdated">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames
Duration="00:00:01" Storyboard.TargetProperty
="(TextBlock.FontWeight)">
<DiscreteObjectKeyFrame KeyTime="00:00:00.5"
Value="{x:Static FontWeights.Normal}" />
<DiscreteObjectKeyFrame KeyTime="00:00:01"
Value="{x:Static FontWeights.Bold}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
Column
<Controls:DataGridTextColumn
Binding="{Binding Side, Mode=TwoWay,
NotifyOnTargetUpdated=True,
NotifyOnSourceUpdated=True}"
CellStyle="{StaticResource CellBoldStyle}" />
Limitations
Virtualized cells would loose the bold highlighted effect when you scroll them out of your scroll view.
Even your TextBox shows Bold value . (I dont know if this is a limitation for you!)

Related

WPF : Animating Width of an Control alternately with start value

I have an image whose width should be animated from 0 to 30 pixels when a boolean property changes to true an back from 30 to 0 pixels if the property switches back to false.
In general, this works with this XAML code:
<Image.Style>
<Style TargetType="{x:Type Image}">
<!-- <Setter Property="Width" Value="0"/> -->
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=AIM, Path=IsDeletingEnabled}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<!-- Animate the Width of the Image from 0 to 30px within 300ms-->
<DoubleAnimation Storyboard.TargetProperty="Width" From="0" To="30" Duration="0:0:0.3"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<!-- Animate the Width of the Image from 30 to 0px within 300ms-->
<DoubleAnimation Storyboard.TargetProperty="Width" From="30" To="0" Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
The problem is, that before the Property IsDeletingEnabled switches to true the first time, the images witdh is 30px and it is visible. When I uncomment the first setter and set the Witdh to 0px by default (or the Visibilityto Hidden), the image isn't shown at startup but disappears instantly after switching IsDeletingEnabled from trueto fals. In this case, no animation is visible.
Has anywone a solution how I can set the Visibilityto Hiddenor the Witdhto 0px at startup without hiding the DataTrigger.ExitAction ?
Do you explicitly need to set the Visibility to Hidden if you're setting the Width to 0? A zero-width element and a hidden element look the same onscreen.
Your exit action is not being 'hidden', what's happening is the DataTrigger is 'undoing' the <Setter Property="Visibility" Value="Visible"/> in addition to running the exit action. But since the visibility has immediate effect you don't see the exit action being run.
Your enter action needs to both Visibility=Visible and start the expanding animation. Your exit action needs to perform the shrinking animation, but wait to set Visibility=Visible until after it's complete. You can do this with an ObjectAnimationUsingKeyFrames animation:
<Image.Style>
<Style TargetType="Image">
<Setter Property="Visibility" Value="Hidden"/>
<Setter Property="Width" Value="0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsShown}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<!-- Animate the Width of the Image from 0 to 30px within 300ms-->
<DoubleAnimation Storyboard.TargetProperty="Width" From="0" To="30" Duration="0:0:0.3"/>
<!-- Set the Image to Visible immediately -->
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<!-- Animate the Width of the Image from 30 to 0px within 300ms-->
<DoubleAnimation Storyboard.TargetProperty="Width" From="30" To="0" Duration="0:0:0.3" />
<!-- After 300ms, hide the Image -->
<ObjectAnimationUsingKeyFrames BeginTime="0:0:0.3" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Hidden</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>

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>

Fade out animation on DockPanel

<DockPanel Name="MyPanel" IsVisibleChanged="MyPanel_IsVisibleChanged">
<DockPanel.Triggers>
<EventTrigger RoutedEvent="IsVisibleChanged"> // error here
</EventTrigger>
</DockPanel.Triggers>
</DockPanel>
Above is my dockpanel xmal code. Because IsVisibleChanged is not a RoutedEvent I can not add in the EventTrigger this code:
<Storyboard x:Key="hideMe">
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:2" To="0.0"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:2" Value="{x:Static Visibility.Hidden}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="showMe">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:5" To="0.75"/>
</Storyboard>
I try to give a fade out animation to my dockpanel.
Instead of using an event trigger, I would use a normal trigger to check the value of the Visibility property of the DockPanel.
You can create a style on the DockPanel to do it, like this:
<DockPanel Name="MyPanel">
<DockPanel.Style>
<Style TargetType="DockPanel">
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<!-- Set storyboard to run when DockPanel is set visible here: -->
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<!-- Set storyboard to run when DockPanel is no longer set visible here: -->
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</DockPanel.Style>
</DockPanel>

Re-Triggering WPF animations

I've the following WPF XAML that tries to animate the visibility of 2 rectangles depending on the IsChecked property of a checkbox. So Checked means the blue box appears and the red box disappears after a second, Unchecked means the red box appears and the blue box disappears, and Undetermined means none are visible.
I'm using storyboards but I'm missing something. It work's for the first trigger but some of the animated properties get stuck.
<DataTemplate x:Key="dt">
<DockPanel>
<CheckBox x:Name="ckToggle" Content="Toggle" DockPanel.Dock="Top" IsThreeState="True"/>
<StackPanel Orientation="Horizontal">
<Rectangle x:Name="a" Visibility="Hidden" Width="100" Height="100" Fill = "Red"/>
<Rectangle x:Name="b" Visibility="Hidden" Width="100" Height="100" Fill = "Blue"/>
</StackPanel>
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=ckToggle, Path=IsChecked}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="a" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="b" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Hidden}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ckToggle, Path=IsChecked}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="b" Storyboard.TargetProperty="Visibility" >
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="a" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Hidden}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
</DataTrigger.ExitActions>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<ContentControl ContentTemplate="{StaticResource dt}"/>
If anyone can help, thanks
Bryan
The problem you have is a property of a wpf storyboard. It´s the case that when you begin a storyboard it´ll never stop until you tell it to to that. So the first storyboard you call is still running when you call the second one and you get in trouble. The way to get out there is the following:
First combine the two storyboards for each trigger in one (You can put multiple animations in one storyboard, you don´t have to do that but it makes things easier..). Now add a name to each of the two remaining BeginStoryboard calls and add StopStoryboard calls with the same names to each dataTrigger in the exitActions block. I ended up with the following code that (hopefully) works as you want:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="dt">
<DockPanel>
<CheckBox x:Name="ckToggle" Content="Toggle" DockPanel.Dock="Top" IsThreeState="True"/>
<StackPanel Orientation="Horizontal">
<Rectangle x:Name="a" Visibility="Hidden" Width="100" Height="100" Fill = "Red"/>
<Rectangle x:Name="b" Visibility="Hidden" Width="100" Height="100" Fill = "Blue"/>
</StackPanel>
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=ckToggle, Path=IsChecked}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="st1">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="a" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="b" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Hidden}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="st1"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ckToggle, Path=IsChecked}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard Name="st2">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="b" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="a" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Hidden}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="st2"/>
</DataTrigger.ExitActions>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<ContentControl ContentTemplate="{StaticResource dt}"/></Window>

WPF TextBlock text changed notify

I have a screen contain about 15-20 TextBlocks each one bind to a different property, at first all the TextBlocks are empty the text update come from other client.
The thing I want to do is to animate flashing text for 3 seconds when ever text change.
I used the below storyboard to make that happen:
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard >
<Storyboard Duration="0:0:03">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.5" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01.5" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:02" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:02.5" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:03" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
Using the mouse enter event the text flash is fine but using the Binding.TargetUpdated event didn't trigger anything.
Anyone know about event that raise when the TextBlock text is changed ?
did you set the NotifyOnTargetUpdated property to true
<TextBlock Text="{Binding Path=YourProperty, NotifyOnTargetUpdated=True}" TargetUpdated="OnTargetUpdated"/>
Already a bit old, but here the solution in pure xaml:
<TextBlock VerticalAlignment="Center"
Text="{Binding ErrorMsg, NotifyOnTargetUpdated=True}">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="0:0:0"
Duration="0:0:1"
From="0.0"
Storyboard.TargetProperty="Opacity"
To="1.0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>

Resources