WPF Select ComboBox text style based on variable - wpf

I have a ComboBox and I'd like to be able to change the style of the text inside the ComboBoxItem based on an attribute of the ComboBoxItem.
<ComboBox ItemsSource="{Binding Countries}">
<ComboBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}" Focusable="False">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Name}" Style="{StaticResource MyStyle}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ComboBox.ItemTemplate>
I've been trying to set the TextBlock Style from MyStyle to a different one if the Country's attribute IsWestern is true, but I am not managing. I figure I need a Trigger somewhere, but I can't figure it out and added a variety, but none worked so far.

use DataTrigger to change ContentTemplate:
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Name}" Style="{StaticResource MyStyle}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsWestern}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Name}" Style="{StaticResource WesternStyle}" />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
alternatively include <DataTrigger Binding="{Binding Path=IsWestern}" Value="True"> in TextBlock Style (MyStyle) and change required TextBlock properties there:
<Style x:Key="MyStyle" TargetType="TextBlock">
<Setter Property="LineStackingStrategy" Value="BlockLineHeight"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsWestern}" Value="True">
<Setter Property="Padding" Value="20,0,0,0"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>

Related

Two bindings; One Works, Other Doesn't. Why?

Why does one label update but not the other? Both bound to the same property. I assume there's a problem with the binding being in a dataTemplate? Using Resharper I'm told that my lblOverallInt cannot resolve the symbol. How could I fix this?
<Label Name="lbl1" Content="{Binding Path=lblOverallInt, UpdateSourceTrigger=PropertyChanged}"/>
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Name="lbl2" Content="{Binding Path=lblOverallInt, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
</Expander>
UPDATE
Related follow on question; I have the following style binding also which works when applied to the label but not to the Expander. Is there a similar process for wiring this up as mm8 solution to the top part of this question?
Added separate solution for this part
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=lblOverallInt}" Value="0">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=lblOverallInt, Converter={StaticResource isZeroConverter}}" Value="False">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
The DataContext of the HeaderTemplate is the header itself. Try this:
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Name="lbl2" Content="{Binding Path=DataContext.lblOverallInt, RelativeSource={RelativeSource AncestorType=Expander}}"/>
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
</Expander>
Or this:
<Expander Header="{Binding Path=lblOverallInt}">
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Name="lbl2" Content="{Binding}"/>
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
</Expander>
For part 2 of my question I had the style binding part still attached to the Expander when it actually needed to be included in the DataTemplate;
<Expander.HeaderTemplate>
<DataTemplate>
<Border Height="24">
<StackPanel Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Resources>
<Style TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="0">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
<DataTrigger Binding="{Binding Converter={StaticResource isZeroConverter}}" Value="False">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
</StackPanel.Style>
<Label>Errors/Warnings:</Label>
<Label Name="lbl2" Content="{Binding}"/>
</StackPanel>
</Border>
</DataTemplate>
</Expander.HeaderTemplate>

Unable to disable textblock text in the itemtemplate

<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<StackPanel Orientation="Horizontal" Width="150" >
<TextBlock MaxWidth="125" Name="name" Text="{Binding name}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Margin="0,4,4,4" />
</StackPanel>
<Button Command="{buttontext}" Visibility="{Binding IsAvailable, Converter={uil:BoolToVisibilityConverter}}">
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="{Binding Isenable}"/>
</Style>
</ListBox.ItemContainerStyle>
I am unable to disable the text(Grey out) but as for the button is working fine.
Do anyone know how to solve this issue?
Hi Chris, i have referred to the link. i tried using
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding name}" Value="False">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
but it is still not working. have any idea on this?
TextBlock doesn't support IsEnabled. The easiest fix would be to change your TextBlock to a Label

Merge Style.Triggers with property Template in WPF

I want to set a style for my DataGrid, but I do not know where is the problem
the backgroud property does not work with its value in the presence of the Template property.
my code:
<Style x:Key="DataGridStyle1" TargetType="{x:Type DataGrid}">
<Setter Property="CellStyle" Value="{DynamicResource GridStyle1}"/>
</Style>
<Style x:Key="GridStyle1" TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="Background" Value="SeaGreen"/>
</Trigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Name="DataGridCellBorder">
<ContentControl Content="{TemplateBinding Content}">
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock Background="Transparent" TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis"
Height="auto" Width="auto" Text="{Binding Text}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Help me please.
You have explicitly set TextBlock background to Transparent, so it won't pick value from DataGridCell. You should bind with background of DataGridCell using RelativeSource like this:
<TextBlock Background="{Binding Background, RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType=DataGridCell}}"
TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis"
Height="auto" Width="auto" Text="{Binding Text}"/>

WPFdatagrid - how to use(give) different colors while grouping?

I am using WPF datagrid by codeplex.
I have a wpf grid with grouping features. I want the grouped region in different colors.
The screenshot is as follows:
Can different colors be assigned during grouping? If yes how do I achieve this in WPF datagrid?
Hope this helps...
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text=" ("/>
<TextBlock Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" "/>
<TextBlock Text="Items"/>
<TextBlock Text=")"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter>
<ItemsPresenter.Resources>
<Style TargetType="{x:Type toolkit:DataGridRow}">
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource=
{RelativeSource AncestorType={x:Type
GroupItem}}, Path=DataContext.Name}"
Value="1">
<Setter Property="Background"
Value="LightGreen"/>
</DataTrigger>
<DataTrigger
Binding="{Binding RelativeSource=
{RelativeSource AncestorType={x:Type
GroupItem}}, Path=DataContext.Name}"
Value="2">
<Setter Property="Background"
Value="LightPink"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsPresenter.Resources>
</ItemsPresenter>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
The data triggers above check which value we have created the groups upon and accordingly assigns data grid row background colors.
So first group represents all values under text "1" (LightGreen) and next group is grouped under value 2 (LightPink).

WPF Style Triggers in DataTemplate

i hope you can help me. I got following Code in the Resources:
<UserControl.Resources>
<BitmapImage x:Key="img_src_lock" UriSource="/EEBase;component/Images/Lock_24x32.png" />
<BitmapImage x:Key="img_src_unlock" UriSource="/EEBase;component/Images/Unlock_24x32.png" />
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource img_src_lock}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource img_src_unlock}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<!-- TypeComboTemplateCollapsed -->
<DataTemplate x:Key="TypeComboTemplateCollapsed">
<TextBlock
Text="{Binding Path=Text, Mode=OneWay}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,5"
/>
</DataTemplate>
<!-- TypeComboTemplateExpanded -->
<DataTemplate x:Key="TypeComboTemplateExpanded">
<TextBlock
Text="{Binding Path=Text, Mode=OneWay}"
VerticalAlignment="Center"
Margin="5,0,0,5"
/>
</DataTemplate>
<!-- EditCircleTemplate -->
<DataTemplate x:Key="EditCircleTemplate">
<!-- some content here, no ToggleButton -->
</DataTemplate>
<!-- EditRectangleTemplate -->
<DataTemplate x:Key="EditRectangleTemplate">
<!-- some other content here, including the ToggleButtons -->
<ToggleButton
IsChecked="{Binding Path=BaseLocked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Margin="5"
/>
<ToggleButton
IsChecked="{Binding Path=HeightLocked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Margin="5"
/>
</DataTemplate>
</UserControl.Resources>
To me that looks all correct.
Now, the problem is:
When i do the following, an exceptions occurs:
Specified element is already the logical child of another element. Disconnect it first.
1. load the control, selected type is CIRC
2. change the dropdown to select RECT (template triggers and togglebuttons are shown correctly)
3. change the dropdown back to CIRC
--> now the Exception occurs.
4. if i ignore the exception, the template "EditCircleTemplate" does not get loaded, and the normal ToString of the model object gets displayed.
Additional info:
originally there are 4 different types in the WPF, two of them with ToggleButtons (that's why i use templates). I cut them out, they dont differ really. But what i found out using all 4 templates is that the error does not occur when switching to a new Template, but when unloading a template with the toggle buttons. Which is kinda strange.
Also if i remove the DataTriggers for the ToggleButtons everything works like a charm.
The Exception comes from the XAML-Interpreter, so the Stacktrace is not useful at all.
Can anyone give me a hint what i am doing wrong?
Edit:
oops, i guess i forgot the content code:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<ComboBox
Margin="5"
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding Path=PossibleTypes, Mode=OneTime}"
SelectedItem="{Binding Path=SelectedType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ContentControl x:Name="content" Content="{Binding}" ContentTemplate="{StaticResource TypeComboTemplateExpanded}"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ComboBoxItem}}" Value="{x:Null}">
<Setter TargetName="content" Property="ContentTemplate" Value="{StaticResource TypeComboTemplateCollapsed}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ContentControl
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="2"
Content="{Binding Mode=OneWay}">
<ContentControl.ContentTemplate>
<DataTemplate >
<ContentControl
Name="inputContent"
Content="{Binding Mode=OneWay}"
ContentTemplate="{x:Null}"
/>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=SelectedType.Type, Mode=OneWay}"
Value="CIRC">
<Setter
TargetName="inputContent"
Property="ContentTemplate"
Value="{StaticResource EditCircleTemplate}"
/>
</DataTrigger>
<DataTrigger
Binding="{Binding Path=SelectedType.Type, Mode=OneWay}"
Value="RECT">
<Setter
TargetName="inputContent"
Property="ContentTemplate"
Value="{StaticResource EditRectangleTemplate}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
Edit2/Solution:
I just found a workaround - it just does not satisfy me:
Instead of putting the style in the UserControl.Resources, which for me would be the more clean and intuitive solution, i have to set the style with the triggers on each ToggleButton separately.
So removing the and adding following code to each ToggleButton did the trick:
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True" >
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource img_src_lock}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource img_src_unlock}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
The big question still persists: WHY?
The problem is that if you create an Image in a style there is only one instance, so as soon as multiple controls use the style there is going to be a fight over this one instance which can only be owned by one control.
The easiest solution to this is placing the Style in a resource and setting x:Shared to false, that way a copy of the style is used whereever referenced.
Why do you need to create BitmapImages and set them as Source to your Content Images in Triggers? Why arent you using the URI source to Images directly?
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="/EEBase;component/Images/Lock_24x32.png" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="/EEBase;component/Images/Unlock_24x32.png" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
Let me know if this helps.

Resources