I want to change the grid background via binding, if a condition is true.
I am using the MVVM light framework.
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding SuccessBooked, UpdateSourceTrigger=PropertyChanged}"
Value="True">
<!--Setter Property="Background" Value="LimeGreen" />-->
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="LimeGreen"
Storyboard.TargetName="ActualWeightBg"
Storyboard.TargetProperty="Background"
FillBehavior="Stop"
Duration="0:0:12"/>
<!--<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0.0" To="1.0" Duration="0:0:15"/>-->
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding LowerBooked, UpdateSourceTrigger=PropertyChanged}"
Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding HigherBooked, UpdateSourceTrigger=PropertyChanged}"
Value="True">
<Setter Property="Background" Value="DarkOrange" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
The compiler complains:
If I remove Storyboard.TargetName="ActualWeightBg":
<ColorAnimation To="LimeGreen"
Storyboard.TargetProperty="Background"
FillBehavior="Stop"
Duration="0:0:12"/>
I get this exception:
Exception thrown: 'System.InvalidOperationException' in PresentationFramework.dll
I want that background color is going to change for 5s, after that it should change back to the standard color.
Update
So when a background color is not set, it will throw the error:
Cannot resolve all property references in the property path
'Background.Color'. Verify that applicable objects support the
properties.
As you see here, the background color is not set
then the error will occur:
But when the background is set:
Then it will work as expected.
How can I set an animated background color, without background color being set.
It is an usercontrol.
First of all, StyleTriggers in general dont support TargetNames.
AFAIK only TemplateTriggers do support them.
Your DataTrigger should look like this.
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Background.Color" To="LimeGreen"
FillBehavior="Stop" AutoReverse="True" Duration="0:0:5" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
Notice the Storyboard.TargetProperty="Background.Color". Also your TimeSpan was too high. Another thing is setting the AutoReverse to true.
EDIT
To get this Trigger to work, in the Grid's Style there has an initial Background to be set.
<Style TargetType="Grid">
<Setter Property="Background" Value="Red"/>
Related
I have the following XAML:
<UserControl.Resources>
<SolidColorBrush x:Key="Brush"></SolidColorBrush>
<Style TargetType="{x:Type StackPanel}" x:Key="ColourChangingStyle">
<Setter Property="Background" Value="{StaticResource Brush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path='Stage'}" Value="1">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.Target="{StaticResource Brush}"
Storyboard.TargetProperty="Color" From="{StaticResource FirstColor}" To="{StaticResource FinishedColor}" Duration="0:0:10" BeginTime="0:0:0"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel x:Name="InfoPanel" Orientation="Vertical" Margin="1,2" Style="{DynamicResource ColourChangingStyle}">
...
</StackPanel>
And I keep getting the same error that:
Cannot animate 'Color' on an immutable object instance
which is the brush. I looked up the problem, and believe that it's something to do with the binding the brush to the StackPanel making it unavailable to alter later.
Is there any way around this, I literally have no clue what my other options for the same effect are without hardcoding colors in, and doing all the events in code.
It seems that you can not animate a Brush in Resources with Storyboard.Target. But you can set the Background of your Style (you have done this already) and animate this property.
<ColorAnimation Storyboard.TargetProperty="Background.Color"
From="{StaticResource FirstColor}"
To="{StaticResource FinishedColor}"
Duration="0:0:10" BeginTime="0:0:0" />
I've just started with WPF (I'm sorry if the question is too obvious), and I managed to put together this mouseover style. The background color animates to a darker color. I now want to also animate the text to white, so it's easier to read.
This is how I tried to add it, but it gives me the error "Cannot resolve all property references in the property path 'TextBlock.Foreground'. Verify that applicable objects support the properties" when I mouseover it.
<Border Background="#e6ebf3" CornerRadius="0,10,0,10" >
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#e6ebf3" />
<Setter Property="TextBlock.Foreground" Value="Black"/>
<Style.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Background.Color" To="#6d809b" />
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="TextBlock.Foreground" To="white" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Background.Color" To="#e6ebf3" />
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="TextBlock.Foreground" To="Black" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Border.Style>........
I found an alternative way without using storyboard or animations, so I'll post it just in case. Still wondering about the original one, though.
<Border CornerRadius="0,10,0,10" >
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#e6ebf3" />
<Setter Property="TextBlock.Foreground" Value="Black"/>
<Style.Triggers>
<Trigger Property ="IsMouseOver" Value="True">
<Setter Property= "Background" Value="#6d809b"/>
<Setter Property= "TextBlock.Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
...
Indirect property targeting, that being TextBlock.Foreground is described here http://msdn.microsoft.com/en-us/library/ms742451.aspx. It's basically saying, "hey I couldn't find a property called TextBlock on type button." It works with Background.Color because the Background Property does exist on Button and it's of type ColorBrush which itself has a property of type Color.
I have a control that can appear on the left- or right-hand side of a window depending on the value of a viewmodel property (which changes as a result of a button click elsewhere in the UI). I'm using DataTriggers to achieve this positioning:
<DataTrigger Binding="{Binding ShowOnLeft}" Value="True">
<Setter Property="HorizontalAlignment" Value="Left"/>
</DataTrigger>
<DataTrigger Binding="{Binding ShowOnLeft}" Value="False">
<Setter Property="HorizontalAlignment" Value="Right"/>
</DataTrigger>
I now want to make the control fade in when it's position changes, so I added these triggers:-
<Trigger Property="HorizontalAlignment" Value="Left">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="0.8" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="HorizontalAlignment" Value="Right">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="0.8" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
However it produces some odd results. The fade works the first time HorizontalAlignment changes to "Left", but not on subsequent attempts. However the fade will happily work every time HorizontalAlignment changes to "Right". It partly seems to be down to trigger order - if I swap the two triggers then the reverse happens (the fade only works the first time I set HorizontalAlignment to "Right", but works every time for "Left").
What am I doing wrong?
Maybe a wild guess, but I have had similar (unwanted) behavior some time ago. Finally, I had succes with the property FillBehavior of a DoubleAnimation set to Stop (the default is HoldEnd).
Read this to learn more about this property / enumeration.
I'm trying to animate the background colour on a grid to change, once an event happens, but I can't get it working, I can get it to change colour immediately (via data triggers), but as soon as I try to introduce an animation into it, then I can't get it working (the animation doesn't seem to come into effect).
This is the current XAML I'm using (though I've tried various variations and cannot get it to animate):
<DataTrigger Binding="{Binding ElementName=me, Path=Viewed}" Value="False">
<Setter Property="Background" Value="LightYellow" />
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="00:00:02" To="White" Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<!--
<DataTrigger Binding="{Binding ElementName=me, Path=Viewed}" Value="True">
<Setter Property="Background" Value="White" />
</DataTrigger>
-->
Where Viewed is a dependency property (bool) on my Control. Any hints in the right direction would be appreciated. I've also tried setting it as an EventTrigger on a raised event which happens when the bool switches to true.
Thanks to Clemens helps, figured out what I needed to do:
<SolidColorBrush x:Key="GridColourBrush" Color="LightYellow" />
<Style x:Key="GridStyle" TargetType="Grid">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=me, Path=Viewed}" Value="False">
<Setter Property="Background" Value="{StaticResource GridColourBrush}" />
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="00:00:02" To="White" Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
<!-- snipped stuff -->
<Grid MinWidth="525" x:Name="ContainerGrid" Style="{StaticResource GridStyle}" Background="{StaticResource GridColourBrush}" />
So setting the background to be flat white by default, then if the DP bool is false, change the background to the static solid colour brush, which I can then animate via the exit actions.
What i meant was simply that instead of
<Grid Background="LightYellow">
</Grid>
you would have to write
<Grid>
<Grid.Background>
<SolidColorBrush Color="LightYellow" />
</Grid.Background>
</Grid>
No need to have an extra resource.
I'm developing an XBAP and i have a simple requirement.
The DataContext of the whole main page is set to an instance of my UserViewModel. The UserViewModel has a DependencyProperty called AuthenticationState which is an enum with values like 'Authenticated','NotAutheticated' and 'AuthenticationFailed'.
Now, i need to respond to any change in this value by hiding/displaying various elements on the page.
What (and where) is the best way of doing that?
As you mentioned you can't use a DataTrigger directly on a control. A work around would be to use a style on each Control that needs to be hidden.
<Grid>
<Rectangle Fill="Red" />
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding Test}" Value="true">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
A preferable method would be to use a Converter called "AuthenticationStateToVisibilityConverter" that is used in binding the control's Visibility property to the data context's AuthenticationState property.
The best way would be to use a DataTrigger. So something like this:
<Window.Triggers>
<DataTrigger Binding="{Binding AuthenticationState}" Value="NotAuthenticated">
<Setter TargetName="nameOfControl" Property="Visibility" Value="Collapsed" />
</DataTrigger>
...
<TextBox x:Name="nameOfControl" />
</Window.Triggers>
As long as you UserViewModel object is in the DataContext of the Window then this should work!
Managed to sort it using styles. It's a pain but it works!
The full source is below.
<Grid x:Name="contentGrid" Grid.Row="1">
<!--login-->
<controls:LoginControl>
<controls:LoginControl.Style>
<Style>
<Setter Property="Control.Opacity" Value="0"/>
<Setter Property="Control.IsHitTestVisible" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Source={StaticResource UserViewModel},Path=UserAuthenticationState}"
Value="{x:Static model:AuthenticationState.NotAuthenticated}">
<Setter Property="Control.IsHitTestVisible" Value="True"/>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1" Duration="0:0:2"
Storyboard.TargetProperty="Opacity"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="0" Duration="0:0:2"
Storyboard.TargetProperty="Opacity"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</controls:LoginControl.Style>
</controls:LoginControl>
<!--slider-->
<slider:PageSlider>
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<slider:PageSlider.Style>
<Style>
<Setter Property="Control.Opacity" Value="0"/>
<Setter Property="Control.IsHitTestVisible" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Source={StaticResource UserViewModel},Path=UserAuthenticationState}"
Value="{x:Static model:AuthenticationState.Authenticated}">
<Setter Property="Control.IsHitTestVisible" Value="True"/>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1" Duration="0:0:2"
Storyboard.TargetProperty="Opacity"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="0" Duration="0:0:2"
Storyboard.TargetProperty="Opacity"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</slider:PageSlider.Style>
</slider:PageSlider>
</Grid>
Actually, the best way to do this is to expose the appropriate properties from your view model. This makes your logic more centralized and easier to test. Also, it performs better than converters. It is, after all, a view model. Therefore, it should model the view. If the view needs a property to tell it when to hide / show a panel, add such a property to your view model.