Change my binding Check-Box style when mouse over ListViewItem - wpf

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>

Related

XAML: Custom Binding in DataTemplate for use in GridViewColumn CellTemplate

I have the following DataTemplate in resources that I would like to reuse throughout a GridView.
<Window.Resources>
<DataTemplate x:Key="NumericalDataTemplate" DataType="GridViewColumn.CellTemplate">
<StackPanel Orientation="Horizontal" Height="32">
<TextBlock Text="{Binding MyLength}" VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}" >
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding PropertyEditable}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</Window.Resources>
Which is implemented as follows.
<GridViewColumn Header="MyLength" Width="80"
CellTemplate="{StaticResource NumericalDataTemplate}" />
I would like change the Binding of the TextBlock (Currently Text={Binding MyLength} ) so that it can use a custom binding for each GridViewColumn Cell Template (eg MyHeight, MyWeight etc).
The way I envisaged doing this is changing the Binding of the TextBlock to simply use {Binding} and having the GridViewColumn set the Binding. However, I'm not sure where or how to do this, as setting the DisplayMemberValue to {Binding MyLength} (for example) simply overrides the template.
I would preferably like to do this entirely in XAML.
It seems that CellTemplate will always be ignored when we have DisplayMemberBinding property set. Possible workaround for this limitation is, by creating markup-extension as pointed by #H.B in his answer to similar question here. Creating markup-extension involves C#/VB codes, but using it only needs XAML codes.
You can reuse the same markup-extension C# code provided by #H.B. Then to use it in your XAML, declare namespace prefix :
<Window ......
xmlns:local="clr-namespace:WpfProject">
Modify DataTemplate key and binding of the TextBlock inside :
<DataTemplate x:Key="TemplateBuilder_BaseTemplate" DataType="GridViewColumn.CellTemplate">
<StackPanel Orientation="Horizontal" Height="32">
<TextBlock Text="{local:TemplateBuilderTag}" VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}" >
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding PropertyEditable}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
Now you can use the same DataTemplate for different column binidngs :
<GridView.Columns>
<GridViewColumn Header="MyLength" Width="80"
CellTemplate="{local:TemplateBuilder MyLength}" />
<GridViewColumn Header="MyHeight" Width="80"
CellTemplate="{local:TemplateBuilder MyHeight}" />
</GridView.Columns>

How to change TreeViewItem background color according to property of bound data?

I have a TreeView where the data is bound to generic derived wrapper classes over my data hierarchy.
My bound wrapper classes include added fields like "IsHilighted" and "IsExpanded".
I would like to change the background of any TreeViewItem according to its bound data property "IsHiglighted". I would like to set the color of Hilighted item to the same (or lighter) color as the default Selected item background color.
Ideally, I would like to not modify existing XAML... I mean being able to eventually add the behavior through code.
UPDATE
I have found a partial solution: I had to add triggers as defined below. Code included below.
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsHilighted}" Value="true">
<Setter Property="Background" Value="SlateBlue"></Setter>
<Setter Property="Opacity" Value="160"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
Still not resolved: How could I bind the color of Hilighted item (see partial solution above) to the "Selected" TreeViewItem background color, i.e. replace "SlateBlue" on partial solution to binding to existing selected item style background color ?
Original TreeView XAML code:
<TreeView Name="TreeViewSelectScopeStudy" MinHeight="24" Margin="7" ItemsSource="{Binding Path=TvItemRootPssTreeViewRoot.ChildsView}" Height="Auto"
VerticalAlignment="Stretch"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<TreeView.Resources>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded}"/>
</Style>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Green" />
<HierarchicalDataTemplate DataType="{x:Type scopeSelection:WrapperSimulatedInfoStudy}" ItemsSource="{Binding Path=Childs}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsSelected}"></CheckBox>
<TextBlock Text="{Binding Path=TvItemName}" Margin="5,0,0,0"></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type scopeSelection:WrapperSimulatedInfoSimulation}">
<StackPanel Orientation="Horizontal" ToolTip="{Binding Path=Item.InvalidityReason}">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Item.IsValid}" Value="false">
<Setter Property="Opacity" Value="160"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<CheckBox IsChecked="{Binding Path=IsSelected}" IsEnabled="{Binding Path=Item.IsValid}" ToolTip="{Binding Path=Item.InvalidityReason}"></CheckBox>
<CheckBox IsChecked="{Binding Path=IsHilighted}"></CheckBox>
<TextBlock Text="{Binding Path=TvItemName}" Margin="5,0,0,0" ToolTip="{Binding Path=Item.InvalidityReason}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Item.IsValid}" Value="false">
<Setter Property="Background" Value="LightPink"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
You could define one more property called IsItemSelected and bind it to TreeViewItems IsSelected property (similar to how you have done for IsExpanded).
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded}"/>
<Setter Property="IsSelected" Value="{Binding Path=IsItemSelected}"/>
</Style>
Then you could define a DataTrigger for the IsItemSelected property and set the background color.
<DataTrigger Binding="{Binding Path=IsItemSelected}" Value="true">
<Setter Property="Background" Value="Blue"></Setter>
</DataTrigger>

Understandig DataTrigger

I have a ComboBox and a TextBox and want to enable/disable TextBox only, when first item is selected in ComboBox.
This code works: (disable when first item is selected)
<ComboBox SelectedIndex="{Binding Mode}">
<ComboBoxItem>Mode 1</ComboBoxItem>
<ComboBoxItem>Mode 2</ComboBoxItem>
<ComboBoxItem>Mode 3</ComboBoxItem>
</ComboBox>
<TextBox Text="{Binding ValueNotForMode1}">
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding ="{Binding Mode}" Value="0">
<Setter Property="TextBox.IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
This one doesn't work: (enable when first item is selected)
<ComboBox SelectedIndex="{Binding Mode}">
<ComboBoxItem>Mode 1</ComboBoxItem>
<ComboBoxItem>Mode 2</ComboBoxItem>
<ComboBoxItem>Mode 3</ComboBoxItem>
</ComboBox>
<TextBox IsEnabled="False" Text="{Binding ValueForMode1}">
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding ="{Binding Mode}" Value="0">
<Setter Property="TextBox.IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Isn't it possible to enable a control via DataTrigger?
Or how can I tell the control, what to do, when the Trigger not occures?
Move IsEnabled="False" from your TextBox to your TextBox.Style.
<Setter Property="TextBox.IsEnabled" Value="False" />
See Dependency Property Value Precedence for clearer understanding.

Combobox ItemTemplate and foreground

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>

How to disable a databound ListBox item based on a property value?

Does anyone know if and how one can disable items in a databound ListBox based on the value of a property?
Preferably I would like a DataTrigger which, when a certain property is false, disables this item (make it impossible to select) without affecting other items in the ListBox.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Name="textBlock" Text="{Binding Description}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
??
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can use ItemContainerStyle:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding YourPropertyName}" Value="False">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

Resources