When using Normal trigger I can get the functionality to work easily.
But when I use MultiDataTrigger I cannot get it to work.
This does not work.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="Brush_GridBackground" TargetType="{x:Type Grid}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" Value="Red" />
<Condition Binding="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" Value="White" />
<Condition Binding="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" Value="Black" />
<Condition Binding="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" Value="Blue" />
<Condition Binding="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" Value="Green" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
This works
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="Brush_GridBackground" TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" Value="Red">
<Setter Property="Background" Value="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" Value="White">
<Setter Property="Background" Value="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" Value="Black">
<Setter Property="Background" Value="{Binding ElementName=cb_BackgroundColor, Path=SelectedItem.Tag}" />
</DataTrigger>
</Style.Triggers>
</Style>
Howcome?
A MultiDataTrigger is like using an AND statement with your Triggers, so you are basically saying if the Tag is equal to Red, White, Black, Blue, and Green, then apply the following style, however the tag can only equal to one of those values, so the trigger is always going to end up as False.
Having Multiple triggers, such as your working code, is the syntax I use if I want to OR the triggers.
Related
I want to change 2 Properties on 2 different conditions using Multi-/DataTrigger.
I have 1 Button which changes its IsEnabled Property when ValidationRule returns an error.
I also want to change the Command Property of this Button but on other conditions.
<Button Content="Save">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource MaterialDesignFlatButton}">
<Setter Property="IsEnabled" Value="False" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=FirstNameBox}" Value="False" />
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=LastNameBox}" Value="False" />
[...]
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Now I want to implement another Trigger which changes the Binding of the Command Property when anoither Propertie's Binding equals to XY.
So i need to implement this next to the Datatrigger above.
<Setter Property="Command" Value="{Binding CreateEmployeeCommand}" />
<DataTrigger Binding="{Binding CurrentManageMode}" Value="2">
<Setter Property="Command" Value="{Binding EditEmployeeCommand}" />
</DataTrigger>
So is it even possible to have 2 Triggers at the same time?
Okay, i fixed it adding another Trigger just in Style.Triggers.
I didn't tried this cuz many Controls/Properties doesn't allow multiple Content.
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource MaterialDesignFlatButton}">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Command" Value="{Binding CreateEmployeeCommand}" />
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentManageMode}" Value="2">
<Setter Property="Command" Value="{Binding EditEmployeeCommand}" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=FirstNameBox}" Value="False" />
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=LastNameBox}" Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
I've tried searching for the answer, but the question that's been posted here has not been answered.
I've tried some complicated XAML, but it's never worked. The code below grays out all rows if the first row is selected. I need to gray out the first row only, regardless of which row index is selected.
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontStyle" Value="Normal"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=SelectedIndex, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}" Value="0"/>
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="FontStyle" Value="Italic"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
Would anyone be able to help?
Thanks.
You can use the AlternationCount property found on all ItemsControls (ref ListBox).
<DataGrid ItemsSource="{Binding Items}"
AlternationCount="2147483647"
...
>
<DataGrid.ItemContainerStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="FontStyle" Value="Italic"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.ItemContainerStyle>
...
</DataGrid>
EDIT
<DataGrid ItemsSource="{Binding Items}"
AlternationCount="2"
VirtualizingStackPanel.IsVirtualizing="False">
...
>
<DataGrid.ItemContainerStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="Gray"/>
</Trigger>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Mode=PreviousData}}"
Value="{x:Null}">
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="FontStyle" Value="Italic"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.ItemContainerStyle>
...
</DataGrid>
I have a status bar that, via data binding and triggers, shows whether a user is connected to a server. I'm styling two different elements to achieve this: the actual StatusBarItem to set a colored background (red, green, yellow), and a TextBlock inside to display the text ("Not Connected", "Connected" etc.) As I'm doing this in XAML, I have to duplicate the DataTrigger logic across two styles (to update the background in one and text in another), like so:
<StatusBarItem Grid.Column="0" HorizontalAlignment="Left" Padding="10,0,10,0">
<StatusBarItem.Style>
<Style TargetType="StatusBarItem">
<Setter Property="Background" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.NotConnected}">
<Setter Property="Background" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.Connected}">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.OfflineMode}">
<Setter Property="Background" Value="Goldenrod" />
</DataTrigger>
</Style.Triggers>
</Style>
</StatusBarItem.Style>
<TextBlock Width="Auto" Height="Auto">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="Not Connected" />
<Setter Property="Foreground" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.NotConnected}">
<Setter Property="Text" Value="Not Connected" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.Connected}">
<Setter Property="Text" Value="Connected to Perforce" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.OfflineMode}">
<Setter Property="Text" Value="Offline Mode" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StatusBarItem>
Question: is there a way to compress this code and not duplicate the DataTrigger logic?
Please note that I'm not interested in solutions that make the TextBlock fill out the entire StatusBarItem. Sure, that would solve this particular issue (I'd just style the TextBlock for both background color and text). But it doesn't address the issue at large (duplicate code that has to be updated in two places).
In this particular case you could set the Content property using the DataTriggers in the StatusBarItem style instead of using an explicit TextBlock as the Content:
<StatusBarItem Grid.Column="0" HorizontalAlignment="Left" Padding="10,0,10,0">
<StatusBarItem.Style>
<Style TargetType="StatusBarItem">
<Setter Property="Background" Value="Red" />
<Setter Property="Content" Value="Not Connected" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.NotConnected}">
<Setter Property="Background" Value="Red" />
<Setter Property="Content" Value="Not Connected" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.Connected}">
<Setter Property="Background" Value="Green" />
<Setter Property="Content" Value="Connected to Perforce" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.OfflineMode}">
<Setter Property="Background" Value="Goldenrod" />
<Setter Property="Content" Value="Offline mode" />
</DataTrigger>
</Style.Triggers>
</Style>
</StatusBarItem.Style>
</StatusBarItem>
Another option would be to define your own custom ControlTemplate for the StatusBarItem and use ControlTemplate.Triggers to change the background and the text in one place.
I come from a web background, so I'm really struggling with this one.
I have a style that I need applied when both IsMouseOver is true and a class variable (called _isLinking) is true within my Linking class is true also. I have the style built and functioning with the IsMouseOver, but I'm not sure how to get the second condition with the _isLinking in there.
<Path.Style>
<Style>
<Setter Property="Path.Stroke" Value="Black" />
<Setter Property="Path.Fill" Value="LightGray" />
<Style.Triggers>
<Trigger Property="Canvas.IsMouseOver" Value="True">
<Setter Property="Path.Stroke" Value="Blue" />
<Setter Property="Path.Fill" Value="LightBlue" />
</Trigger>
</Style.Triggers>
</Style>
</Path.Style>
You should use MultiDataTrigger (msdn).
Example:
<Canvas>
<Path>
<Path.Data>
<PathGeometry Figures="M 10,100 C 10,300 300,-200 300,100" />
</Path.Data>
<Path.Style>
<Style>
<Setter Property="Path.Stroke" Value="Black" />
<Setter Property="Path.Fill" Value="LightGray" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Canvas}}" Value="True" />
<Condition Binding="{Binding IsLinking}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Path.Stroke" Value="Blue" />
<Setter Property="Path.Fill" Value="LightBlue" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Canvas>
In the above example DataContext is set to object of type Linking.
this.DataContext = new Linking { IsLinking = true };
How should i change the background of the wpftoolkit autocompletebox.? I tried by subscribing to enabledchanged event and changed the background of the control which is not changing at all.Can any body help.
<WpfToolkit:AutoCompleteBox x:Name="txtBxSearch" Background="White" IsTextCompletionEnabled="True" MinimumPrefixLength="0" FilterMode="Contains" Height="24" Width="150" KeyDown="txtBxSearch_KeyDown" >
<WpfToolkit:AutoCompleteBox.TextBoxStyle>
<Style TargetType="TextBox">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
</Style>
</WpfToolkit:AutoCompleteBox.TextBoxStyle>
</WpfToolkit:AutoCompleteBox>
You can do this in XAML:
<toolkit:AutoCompleteBox
ToolTip="Enter the path of an assembly."
x:Name="tbAssembly" Height="27" Width="200"
Populating="tbAssembly_Populating"
>
<toolkit:AutoCompleteBox.Style>
<Style TargetType="toolkit:AutoCompleteBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tbAssembly, Path=IsEnabled}" Value="True">
<Setter Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tbAssembly, Path=IsEnabled}" Value="False">
<Setter Property="Background" Value="Black" />
<Setter Property="Foreground" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</toolkit:AutoCompleteBox.Style>
</toolkit:AutoCompleteBox>