I want to write XAML code to change color of button when user changes selectionIndex of ListBox. How can I do it? I try
<Trigger Property="IsSelectionChanged" Value="True">
<Setter TargetName="btnSave" Property="Background" Value="Red" />
</Trigger>
But property IsSelectionChanged is not found.
There is no such property, you need to use an EventTrigger:
<Button Name="buton" Content="The Buton"/>
<ListBox ItemsSource="{Binding Data}">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<EventTrigger RoutedEvent="SelectionChanged">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.Target="{x:Reference buton}"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Brushes.Red}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
Related
I have 2 checkboxes (chkMfsUi and chkMfs). When I check chkMfsUi, I also want to check chkMfs (and disable it).
I tried it with a datatrigger:
<Style x:Key="MfsCheckBoxStyle" TargetType="CheckBox">
<Setter Property="IsEnabled" Value="True" />
<Setter Property="IsChecked" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=chkMfsUi}" Value="True">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="IsChecked" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
And these are my checkboxes:
<StackPanel>
<CheckBox Name="chkMfsUi"
Checked="CheckBox_Checked"
Content="MFS - UI"
IsChecked="{Binding MfsUi}"
Unchecked="CheckBox_Checked" />
<CheckBox Content="MFS" IsChecked="{Binding Mfs}" Style="{StaticResource MfsCheckBoxStyle}" />
</StackPanel>
The IsEnabled property work fine, but the IsChecked doesn't. Maybe because it is bound? I am also using INotifyPropertyChanged with these properties.
If I set it in code behind, it works, but is it possible with a trigger though?
Regards,
Alfons
EDIT:
As appeared from the current answers, my question seems to be incomplete. I need to have the following three states:
AND last but not least: Both checkboxes' IsChecked properties must be bound! (This is the moment when the trouble comes in)
Try this
<StackPanel Grid.Column="1">
<CheckBox x:Name="chkMfsUi" IsChecked="True"></CheckBox>
<CheckBox x:Name="chkMfs" IsChecked="{Binding ElementName=chkMfsUi,Path=IsChecked}">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Another Method : By using style in resource
Add this namespace first xmlns:Globalvaribale="clr-namespace:System;assembly=mscorlib"
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Globalvaribale="clr-namespace:System;assembly=mscorlib">
<Window.Resources>
<Globalvaribale:String x:Key="chkMfsUi">chkMfsUi</Globalvaribale:String>
<Style x:Key="chkMfsstyle" TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,ElementName={StaticResource chkMfsUi}}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Grid.Column="1">
<CheckBox x:Name="chkMfsUi"></CheckBox>
<CheckBox Style="{StaticResource chkMfsstyle}"/>
</StackPanel>
Output
In this case you can use the EventTrigger:
Represents a trigger that applies a set of actions in response to an event.
Example:
<StackPanel>
<StackPanel.Triggers>
<EventTrigger RoutedEvent="CheckBox.Checked" SourceName="First">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="Second"
Storyboard.TargetProperty="IsChecked">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="CheckBox.Checked" SourceName="Second">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="First"
Storyboard.TargetProperty="IsChecked">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="CheckBox.Unchecked" SourceName="First">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="Second"
Storyboard.TargetProperty="IsChecked">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="CheckBox.Unchecked" SourceName="Second">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="First"
Storyboard.TargetProperty="IsChecked">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</StackPanel.Triggers>
<CheckBox Name="First"
Content="First" />
<CheckBox Name="Second"
Content="Second" />
</StackPanel>
The Storyboard can be stored in Resources for readability, like so:
<Window.Resources>
<Storyboard x:Key="FirstCheckedStory" ... />
</Window.Resources>
And then use like this:
<EventTrigger RoutedEvent="CheckBox.Checked" SourceName="First">
<BeginStoryboard Storyboard="{StaticResource FirstCheckedStory}" />
</EventTrigger>
Also, the Storyboard can contain several actions, just put him in order:
<Storyboard>
<BooleanAnimationUsingKeyFrames ... />
<BooleanAnimationUsingKeyFrames ... />
</Storyboard>
I am trying to build a designer like visual studio.
Take a look at the xaml:
<Style x:Key="myStyle" TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="DodgerBlue" />
</Trigger>
</Style.Triggers>
</Style>
...
...
...
<Border Style="myStyle">
<Grid>
<Border Style="myStyle">
<Rectangle Fill="Transparent" />
<TextBlock Text="abc" />
</Border>
</Grid>
</Border>
The above code is working perfectly. Now I want to extend the above style, such that the border's color should change to green when I click on any of the control.
Update :
I have changed the above style to something like below code.
<Style x:Key="BorderStyle" TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="DodgerBlue" />
</Trigger>
<EventTrigger RoutedEvent="MouseDown">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="BorderBrush.Color" To="Green" Duration="0:0:0.100" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
Now I can see the border is changing its color to green when I click on it. But when mouse leaves the textblock, the border changes its color back to transparent.
<Style.Triggers>
<EventTrigger RoutedEvent="MouseDown">
<Setter Property="BorderBrush" Value="DodgerBlue" />
</EventTrigger>
</Style.Triggers>
and you dont want to bind the style for all the border, if you need to apply that style for all the border, just remove the key name of that style. It will apply to all the Targeted Control.
If you need to check and apply the color as like the button click as like a Toggle button, you need to maintain a property and that property is to be given in the trigger and it need to be changed in the button's click..
Try this
<Style x:Key="myStyle" TargetType="{x:Type Border}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush">
<Setter.Value>
<SolidColorBrush x:Name="BorderBrushColor" Color="Transparent"></SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="DodgerBlue" />
</Trigger>
<EventTrigger RoutedEvent="MouseDown">
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="Green" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
Try this
<Style x:Key="myStyle" TargetType="{x:Type Border}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush">
<Setter.Value>
<SolidColorBrush x:Name="BorderBrushColor" Color="Transparent"></SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames FillBehavior="HoldEnd" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="DodgerBlue" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseDown">
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames FillBehavior="HoldEnd" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="Green" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
Add this code in previous style
<Trigger Property="IsMouseOver" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames FillBehavior="HoldEnd" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="Transparent" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
I'm setting DataGridRow BackgroundColor to Green or to Red with trigger based on LogError value.
I want to animate newly added rows with transparency.
This works fine:
From="Transparent" To="Red"
But what I want color to goes to is current color set with Style. Its not always Red it could be Green as well.
This does not work:
From="Transparent" To="{TemplateBinding DataGridRow.Background}"
or
From="Transparent" To="{Binding RelativeSource={RelativeSource Self}, Path=Backgound}"
Code:
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property = "Background" Value="LimeGreen"/>
<Style.Triggers>
<DataTrigger Binding="{Binding LogMessage}" Value="Exception has occured">
<Setter Property = "Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(DataGridRow.Background).(SolidColorBrush.Color)"
Duration="00:00:03"
From="Transparent"
To="{TemplateBinding DataGridRow.Background}"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Error message: Cannot freeze this Storyboard timeline tree for use across threads.
There are few problems in your XAML code.
First, you have specified default style under resources section of DataGrid and later provide your own style which will override default style.
Either you should define new style and set its BasedOn DP to refer to default style. But in your case i don't see any use of defining separate style just for trigger.
Second, you want your animation to go from Transparent to colour selected in style which can either by LimeGreen or Red depending on trigger. So, you should not set To value in your animation since it will automatically picked up.
This will work as you desire -
<DataGrid>
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property ="Background" Value="LimeGreen"/>
<Style.Triggers>
<DataTrigger Binding="{Binding LogMessage}"
Value="Exception has occured">
<Setter Property = "Background" Value="Red"/>
</DataTrigger>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty=
"(DataGridRow.Background).(SolidColorBrush.Color)"
Duration="00:00:03"
From="Transparent"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
</DataGrid>
#Den
You have to determinate a standart Color, before you animate. This is my Style for animating a row and cell.
<Style TargetType="{x:Type DataGridRow}">
<Style.Setters>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Background" Value="Transparent"/>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="#FFF37C21"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(DataGridRow.Background).(SolidColorBrush.Color)" Duration="00:00:0.2" To="#FFF37C21"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(DataGridRow.Background).(SolidColorBrush.Color)" Duration="00:00:0.2" To="Transparent"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type DataGridCell}">
<Style.Setters>
<Setter Property="FontWeight" Value="Light"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="IsTabStop" Value="False" />
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid x:Name="gridCell" Background="#00FFFFFF">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ContentPresenter
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(TextElement.FontWeight)">
<DiscreteObjectKeyFrame KeyTime="00:00:0.2">
<DiscreteObjectKeyFrame.Value>
<FontWeight>Bold</FontWeight>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(TextElement.FontWeight)">
<DiscreteObjectKeyFrame KeyTime="00:00:0.2">
<DiscreteObjectKeyFrame.Value>
<FontWeight>Light</FontWeight>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
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'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.