WPF - ListBoxItem alternating background and story board - wpf

for a WPF prototype I would like to accomplish the following:
I want display a listbox where each item looks like "Text Button1 Button2". All the 3 of them are bound to an Observable collection. Text displays a string, Button1 and Button2 display a double. SO far no problem. I would like to extend the functionality as follows and have no idea in how to accomplish this in the best possible practice:
1) The entries in the listbox should have an alternating background, based on the index. ie
If (index % 2) == true, then background = red,
else background = green.
The index might change and the background should update automatically.
2) If the value of double bound to the button text increases, the button should be highlighted green for a second,
else if the value of the double bound to the button text decreases, the button should be highlighted red for a second,
else the button should do nothing.
Can someone help me?
Thanke, br
// edit:
For #2 I now tried the following: Having 2 Storyboards, bound to data triggers. My problem is, that it does not highlight do each of the triggered changes Any ideas?
<Storyboard x:Key="ValueDecreaseAnimationStoryBoard" Name="ValueDecreaseAnimationStoryBoard">
<ColorAnimation
Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
To="Red"
AutoReverse="True"
Duration="0:0:0.5" />
</Storyboard> <Storyboard x:Key="ValueIncreaseAnimationStoryBoard" Name="ValueIncreaseAnimationStoryBoard">
<ColorAnimation
Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
To="Green"
AutoReverse="True"
Duration="0:0:0.5" />
</Storyboard>
<Style x:Key="ValueTriggerStyle" TargetType="{x:Type Button}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="LightGray" />
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Value1Trend}" Value="{x:Static local:Trend.Decreased}">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource ValueDecreaseAnimationStoryBoard}" />
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Value1Trend}" Value="{x:Static local:Trend.Increased}">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource ValueIncreaseAnimationStoryBoard}" />
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>

Related

WPF Source Name property cannot be set within Style. Triggers section Error

I'm getting an error with the following details:
Source Name property cannot be set within Style. Triggers section
<Rectangle Margin="121,163,0,248" HorizontalAlignment="Left" Width="33" Height="34">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="Blue"></Setter>
<Style.Triggers>
<EventTrigger SourceName="myButton" RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="Fill.Color" To="Orange"
Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever"
BeginTime="0:0:0">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
I want to change the rectangle fill color with Color Animation tag when click on button.
Like it says, you cannot use source name in a style like that.
You can use a data trigger instead. Set say a bool property in your viewmodel from your button's command of click.
Then start your storyboard with a datatrigger binding that bool property and comparing value.
You can probably easily Google datatrigger and storyboard but here's a so question includes an example.
WPF Data Triggers and Story Boards
Btw.
Routed events are rarely very useful IME. Binding icommand is way more practical. Usually.
Edit:
Here's a quick and dirty sample using a togglebutton. Since this approach uses binding it can reference controls by name. Binding is resolved at run time.
<Grid>
<Rectangle>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="Blue"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=StartStop}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="ColourStoryboard">
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="Fill.Color" To="Orange"
Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever"
>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="ColourStoryboard"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
<ToggleButton Content="Start Stop"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Name="StartStop"/>
</Grid>
</Window>
Paste the grid inside a mainwindow, spin it up. When you click the togglebutton it sets ischecked true so the rectangle animates to orange and back to blue. When you click the button again, ischecked becomes false and the animation stops.
You could instead write code in a button handler that set a bound property which is in the datacontext and bind the datatrigger to that bound property. That's what the markup in the link is doing with IsBusy.

WPF Datagrid row colour change while row property changed

I'm trying to create a datagrid that change the row colour when the row property changed. Below is the code i tried and it doesn't work at all. Any advise is appreciated.
<DataGrid.Resources>
<Style TargetType="DataGridRow">
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard AutoReverse="True">
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" From="White" To="Green" Duration="0:1:0"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
why you use Storyboard? if you want just change row color you can use just trigger and mention trigger property and value.

DataTrigger don't seems to fire

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.

Datagrid MouseOver and Selected States when using arrow keys

I have a wpf datagrid. I have added styling to show a mouseover color on a row.
What I am trying to achieve is when the mouseover appears, and a user starts using the arrow keys to navigate up and down, the mouseover needs to disappear and only the row that the user used arrow keys to get to, is the highlighted one.
The issue is the mouse cursor has been left on the grid while the user navigates with the arrow keys and the row under the cursor holds the highlight as well as the row the went to using arrows.
Here is my sample xmal:
<DataGrid AutoGenerateColumns="True" Height="277" HorizontalAlignment="Left" Margin="0,311,0,0" Name="dataGrid1"
VerticalAlignment="Top"
Width="478" ItemsSource="{Binding Path=Persons}"
RowHeight="20"
RowHeaderWidth="35" Grid.ColumnSpan="2" >
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="Green" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
Thanks
You'll need to set some kind of flag when the user hits an Arrow key so that the background only changes if IsMouseOver and IsUsingArrowKeys is false. You might even be able to use the Mouse Visibility as a condition instead of using a flag
I'm not positive the exact syntax, but it should be something like this
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<!-- May need to reference RelativeSource here, not sure -->
<Condition Property="IsMouseOver" Value="False" />
<Condition Binding="{Binding IsUsingArrowKeys}" Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Green" />
</MultiDataTrigger>
</Style.Triggers>
I would suggest highlighting the row based on thier focus triggers.
Something like this:
<EventTrigger RoutedEvent="GotFocus">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="dataGrid1" Storyboard.TargetProperty="Background" Duration="0:0:0.1" To="Green"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="LostFocus">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="dataGrid1" Storyboard.TargetProperty="Background" Duration="0:0:0.1" To="White"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
And giving focus to them manually, something like this:
private void Btn_Click(object sender, RoutedEventArgs e)
{
dataGrid1.Focus();
}
So when another row gets focus, the current row loses focus & automatically falls back to non highlighted color background.

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