Combobox ItemTemplate and foreground - wpf

I have a comboBox that is bound to a list of strings from my viewModel. What I am trying to do is have the foreground of a comboBox item be set to a different color if a property in my viewModel is true:
<ComboBox x:Name="myComboBox" ItemsSource="{Binding Names}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ...}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Foreground" Value="Navy"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I am not sure what to bind the Text of the TextBlock to. All I want is to display the list of strings. I always end up with a dropdown that has the items but they are not visible. I tried removing the style trigger thinking that maybe I was screwing up there, but that didn't help.
Am I taking the right approach? Will the ComboBox.ItemTemplate correctly look at my viewModel (which is the data context) when searching for IsActive or is that binding incorrect as well?

The DataContext for each ComboBoxItem is a string so
For the TextBlock, bind to the DataContext like Text="{Binding}
For the DataTrigger to be able to find IsActive, use RelativeSource in the binding
<ComboBox x:Name="myComboBox" ItemsSource="{Binding Names}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ComboBox}},
Path=DataContext.IsActive}"
Value="True">
<Setter Property="Foreground" Value="Navy"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Related

XAML custom text in TextBlock

Good afternoon,
I´m binding a list of doubles (Latlng) to an ItemsControl and in a TextBlock I want to make a custom text when the list binded has a count of 0. With the code I have the TextBlock is empty when the ItemsSource of the ItemsControl is that list.
What am I doing wrong?
Btw the list Latlng is a property of a class.
<ItemsControl Name="icLatLng" ItemsSource="{Binding Latlng}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock FontFamily="Arial" FontSize="14">
<TextBlock.Style>
<Style>
<Setter Property="TextBlock.Text" Value="{Binding}"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}, Path=Items.Count}" Value="0">
<Setter Property="TextBlock.Text" Value="—"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Thanks in advance.
Welcome to SO.
ItemsControl.ItemTemplate is the template that gets applied to each element in the Items list the control is bound to. If there are no items to begin with, then it won't be created, so anything you do in it won't be seen.
I suspect what you're really trying to do is replace the look of the entire control when the list is empty. If so, you can do that by applying a new template to the ItemsControl itself using a DataTrigger on the HasItems property:
<ItemsControl Name="icLatLng" ItemsSource="{Binding Latlng}">
<ItemsControl.Style>
<Style TargetType="{x:Type ItemsControl}" BasedOn="{StaticResource {x:Type ItemsControl}}">
<Style.Triggers>
<DataTrigger Binding="{Binding HasItems, RelativeSource={RelativeSource Self}}" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<TextBlock Text="-" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.Style>
</ItemsControl>

Change my binding Check-Box style when mouse over ListViewItem

So i have ListView with Check-Box cell:
<ListView.Resources>
<DataTemplate x:Key="CheckBoxCell">
<CheckBox IsChecked="{Binding Path=IsChecked}"/>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridViewColumn Width="30" x:Name="gridViewColumnIsChecked" CellTemplate="{StaticResource CheckBoxCell}"/>
</ListView.View>
And i have ListViewItem style with several triggers like IsMouseOver so when IsMouseOver is True i am change my Background color for example.
So i want to change my Check-Box style\color when mouse over ListViewItem.
How i can i achieve that ?
Use this snippet:
<DataTemplate x:Key="CheckBoxCell">
<CheckBox>
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Value="True" Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</DataTemplate>
The solution is to create a DataTrigger, which binds to parent ListViewItem.IsMouseOver property, like another answer shows
However, the trigger can be also placed in <DataTemplate.Triggers> to make markup shorter. In that case Setter uses TargetName to access the correct control.
<DataTemplate x:Key="CheckBoxCell">
<CheckBox IsChecked="{Binding Path=IsChecked}" Name="Chk" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter TargetName="Chk" Property="Background" Value="Red" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

SelectedItem value of combo box gets empty on updating from viewmodel in wpf

I have created a combo box in each datagrid row. The following piece of code is used to create the combo box:
<ComboBox Width="166"
ItemTemplate="{StaticResource GridBinding}"
SelectedItem="{Binding Path=Car, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, IsAsync=True}"
SelectedValue="{Binding Path=Car, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, IsAsync=True}">
<ComboBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource GroupHeader}" />
</ComboBox.GroupStyle>
<ComboBox.Style>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Path=Cars}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType=DataGridCell}}" Value="True">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.GroupedCars, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
The "Car" property for binding "SelectedItem" in combo box is an object of class "Car" holding some properties like id, name, etc.
The problem I am facing is that when I update the value of "Car" property and call "NotifyPropertyChanged" in its setter, then the value of "SelectedItem" in combo box goes blank/empty.
Please suggest.
The SelectedItem can no longer be found in the Collection (when you update your ItemSource) and gets set to null.
I've simplified your XAML to demonstrate
<ComboBox ItemsSource="{Binding Cars}"
SelectedItem="{Binding Car}">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<Trigger Property="SelectedItem" Value="{x:Null}">
<Setter Property="SelectedIndex" Value="0" />
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
Now the first Item will get selected when you update.

WPF DataTemplate on ListView to visualize different kinds of user controls

I have a ListView which I want to present different kinds of user controls, depending on which view model is set for the list view item.
In xaml:
<ListView ItemsSource="{Binding Items}">
<ListView.Resources>
<DataTemplate DataType="{x:Type viewModels:LabelledTextViewModel}">
<controls:LabelledTextBox/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:FolderChooserViewModel}">
<standardControls:FolderChooser/>
</DataTemplate>
</ListView.Resources>
</ListView>
Now this works fine, but my LabelledTextViewModel can be editable or not editable. How do I say in XAML to check the property "IsEditable" on my viewmodel, and depending on its value show LabelledTextBlockControl or LabelledTextBoxControl?
You can use a DataTrigger in your DataTemplate:
<ListView ItemsSource="{Binding Items}">
<ListView.Resources>
<DataTemplate DataType="{x:Type viewModels:LabelledTextViewModel}">
<Grid>
<controls:LabelledTextBlockControl x:Name="textBlock"/>
<controls:LabelledTextBoxControl x:Name="textBox" Visibility="Collapsed"/>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEditable}" Value="True">
<Setter TargetName="textBlock" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="textBox" Property="Visibility" Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:FolderChooserViewModel}">
<standardControls:FolderChooser/>
</DataTemplate>
</ListView.Resources>
</ListView>
For your requirements, you either need to use the DataTemplateSelector Class to make that selection for you, or you could try to name your DataTemplates and set them using a DataTrigger:
<ListView>
<ListView.Resources>
<DataTemplate x:Key="DefaultDataTemplate" DataType="{x:Type viewModels:LabelledTextViewModel}">
<controls:LabelledTextBox/>
</DataTemplate>
<DataTemplate x:Key="AnotherDataTemplate" DataType="{x:Type viewModels:FolderChooserViewModel}">
<standardControls:FolderChooser/>
</DataTemplate>
</ListView.Resources>
<ListView.Style>
<Style TargetType="{x:Type ListView}">
<Setter Property="ItemTemplate" Value="{StaticResource DefaultDataTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditable}" Value="True">
<Setter Property="ItemTemplate" Value="{StaticResource AnotherDataTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Style>
</ListView>
This example assumes that you are setting the DataTemplates to the ItemTemplate property... if not, you'll need to change that property to the relevant one.

WPF color nodes based on view property

I have a WPF treeview that I would like the color of a node to be based on a particular getter. I can't figure how to databind for that case. I would like it to look like this except that odd numbers would be a child node of the even numbers
If you already use HierarchicalDataTemplate, you can simply add a trigger:
<TreeView ItemsSource="{Binding}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Highlight}" Value="True">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Resources