ControlTemplate DataTrigger is not fired in ItemsControl ControlTemplate - c#

I have a NavigationMenuControl with an ObservableCollection<HtNavigationMenuQuickLinkItem>. Everything is working fine, but the Style on my HtMenuIcon Control is not triggered. Where the Visibility is changed correctly. Can someone please give me a hint where I have a mistake? QuickLinkSymbol is a DependencyProperty of an Enum.
I also want to put the Visibility Behavior into the DataTrigger section.
Navigation Menu
<Style TargetType="Navigation:HtNavigationMenu">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Navigation:HtNavigationMenu">
<Grid>
<StackPanel Orientation="Vertical">
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=QuickLinkItems}"/>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
QuickLinkItem
<Style TargetType="Navigation:HtNavigationMenuQuickLinkItem">
<Style.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Navigation:HtNavigationMenuQuickLinkItem">
<Controls:MyButton Width="40" Height="40" Margin="10,10,10,0">
<Viewbox Margin="3">
<Controls:HtMenuIcon x:Name="icon" Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsQuicklink, Converter={StaticResource BoolToVis}}"/>
</Viewbox>
</Controls:MyButton >
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding QuickLinkSymbol, RelativeSource={RelativeSource TemplatedParent}}" Value="Home">
<Setter TargetName="icon" Property="Style" Value="{StaticResource Home}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

You need to reference Home as {x:Static EnumNAmeSpace:EnumType.Home}.
Oh, and if QuickLinkSymbol is a DepProp of HtNavigationMenuQuickLinkItem,
just use Trigger instead of DataTrigger.

Related

How can I add something to my custom listbox?

I made a custom listbox but when I push the button show every language nothing is showing. How can I fix this. When I delete the listbox style it just works fine. It's all in C#.
I hope you can help me.
greetings
Elias
<ListBox x:Name="lsbResultaatTaal"
Foreground="Black"
FontSize="15"
Grid.Row="1"
Margin="528,56,0,0"
Height="450"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="233">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{d:SampleData ItemCount=5}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Background" Value="Gray"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<Border Width="230" Height="450"
CornerRadius="9"
BorderThickness="1"
BorderBrush="Black"
Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</ListBox.Template>
</ListBox>
You can set style in resources
<Window.Resources>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray" />
<!--
Why you choose same background color when hover listbox
Maybe same color your background and foreground
-->
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
OR
Can you try below changes:
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding YourProp}" />

Wpf TreeView With CheckBox

I need to add "Select All" to my wpf application ,
I've tried to do a simple binding but it doesn't work .
Can Someone Please advise , performing a simple binding
or other strait forward solution ?
Here's my treeview xaml :
<TreeView Name="CurrentTreeView" Margin="5" BorderBrush="Transparent" BorderThickness="0"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox
Focusable="False"
Checked="CheckedItemCurreuntSession"
Unchecked="UnCheckedItemCurreuntSession"
Name="treeChk"
Tag="{Binding Path=ChName}"
Style="{StaticResource CheckBoxStyle1}"
IsChecked="{Binding Path=IsChecked}"
VerticalAlignment="Center"/>
<TextBlock VerticalAlignment="Center" Text="{Binding}"
Margin="5"
TextOptions.TextFormattingMode="Display"
TextOptions.TextHintingMode="Auto"
/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
<Style x:Key="CheckBoxListStyle" TargetType="{x:Type ListBox}">
<Setter Property="SelectionMode" Value="Multiple"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<CheckBox Focusable="False" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent} }">
<ContentPresenter/>
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>

WPF Listbox with separators, missing highlighted colors

I have a listbox (C# WPF) which gets filled on startup. I would like a separator between every item in the list and I have found this code from another old post and it's actually working, but when I use the code, I loose the highlighted and selected colors instead and I can't figure out where it's going wrong.
How can I get back those highlighted and selected colors?
Here is the code I'm using.
<ListBox x:Name="radioBox" HorizontalAlignment="Left" Height="494" Margin="14,14,0,0" VerticalAlignment="Top" Width="287" Background="{x:Null}" FontFamily="Calibri" FontWeight="Thin" FontSize="25" Foreground="#FFEDEDF7" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" BorderThickness="1" Padding="30,30,0,0" >
<ListBox.ItemBindingGroup>
<BindingGroup/>
</ListBox.ItemBindingGroup>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel>
<Separator x:Name="Separator" Background="White" Opacity="0.1" Height="20"/>
<ContentPresenter/>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Separator" Value="Collapsed"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Try below code. It's a sample done by me and it should work.
<Window x:Class="ListBoxStyle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:ListBoxStyle"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="_ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="_Border"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="_Border" Property="Background" Value="Yellow"/>
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox ItemContainerStyle="{DynamicResource _ListBoxItemStyle}"
Width="200" Height="250"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBoxItem>Hello</ListBoxItem>
<ListBoxItem>Hi</ListBoxItem>
</ListBox>
</Grid>

TemplatedParent is null when used inside a ControlTemplate's DataTrigger

Consider this (edited-down) Style, designed for a Button whose Content is a String:
<Style x:Key="Test" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<TextBlock x:Name="text" Text="{TemplateBinding Content}" />
<TextBlock x:Name="demo" Text="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<DataTrigger.Value>
<system:String>Test</system:String>
</DataTrigger.Value>
<Setter TargetName="test" Property="Foreground" Value="Red" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The intention in this example is to turn the button text red if it equals the word "Test"1. But it doesn't work, because the trigger's TemplatedParent binding resolves to null instead of to the Button the Style is applied to. However, the TextBlock named "demo" will have its Text set to "System.Windows.Controls.Button: [ButtonText]" as expected, which means TemplatedParent works correctly at that level. Why doesn't it work inside the DataTrigger?
1 I know there are other ways to achieve that, but I'm trying to understand why the binding doesn't work the way I expect it to.
TemplatedParent in your ControlTemplate.Triggers is not what you expect. Inside trigger it actually references Button.TemplatedParent. As such, it will only be non-null if your create that button inside template. You don't create button inside template, so it is null in your case. Now consider this xaml:
<Window.Resources>
<Style x:Key="Test"
TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<TextBlock x:Name="text"
Text="dummy" />
<TextBlock x:Name="demo"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<DataTrigger.Value>
<system:String>Test</system:String>
</DataTrigger.Value>
<Setter TargetName="text"
Property="Foreground"
Value="Red" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="Test2" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Button Style="{StaticResource Test}"></Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<!--<Button Content="Test" Style="{StaticResource Test}"/>-->
<ContentControl Style="{StaticResource Test2}" Content="Test" />
</Grid>
Here I retemplate ContentControl and inside template I use button with your template. If you run this code, you will see "dummy" text in red, because Button.TemplatedParent is now ContentControl, and it has it's Content equals "Test", which confirms what I said above.
Now back to your problem: just change RelativeSource TemplatedParent to RelativeSource Self (no need to change DataTrigger to Trigger) - this one would reference your Button.
I think it might be a similar issue in .NET Core WPF.
My DataTrigger was not firing with {Binding MyProp, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Convert}}, but instead when I changed the RelativeSource to Self the binding started to work. I'm not sure whether it's a hack or a solution, but it worked.
Maybe it's worth mentioning that my template was based on MyView (see below) and I was binding to a DependencyProperty on MyView.
So my final code looked like this:
<ControlTemplate x:Key="Template" TargetType="{x:Type ns:MyView}">
<!-- Some template -->
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding MyProp, RelativeSource={RelativeSource Self}, Converter={StaticResource Convert}}" Value="True">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I'm not quite sure, but I think the trigger equals by referenc, because Content returns an Object. So it will never be true with your string defined within the trigger.

Use an image for a menu option in WPF

I use the following XAML to achieve a menu using radio buttons:
<Grid.Resources>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<TextBlock Text="{TemplateBinding Content}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={x:Type RadioButton}}}" Value="True">
<Setter Property="Foreground" Value="Gold" />
</DataTrigger>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type RadioButton}}}" Value="True">
<Setter Property="Foreground" Value="Gold" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<StackPanel Margin="25,74,644,78" Background="{x:Null}">
<RadioButton Content="1. Do something." Click="RadioButton1_Click" FontSize="16" Margin="5"/>
<RadioButton Content="2. Do something else." Click="RadioButton2_Click" FontSize="16" Margin="5"/>
</StackPanel>
This works fine but I want to include an image as a menu option instead of text. (The image is for 'Home' and it will have a normal image and a hover over image)
Here is what I want to achieve:
How do I do this?
You can define another style for displaying Radio Button as an Image based on the existing style posted in question, just need slight changes in ControlTemplate's content part. Following is an example of such a Style and the usage :
<StackPanel Orientation="Horizontal" Background="Black">
<StackPanel.Resources>
<Style x:Key="PictSTyle" TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Image Width="50" Height="50">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="home_default.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type RadioButton}}}" Value="True">
<Setter Property="Source" Value="home_hovered.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<RadioButton Margin="5" Style="{StaticResource ResourceKey=PictSTyle}"/>
</StackPanel>
To give a menu item an image:
<MenuItem>
<MenuItem.Icon>
<Image Source=""/>
</MenuItem.Icon>
</MenuItem>
for your trigger just change the MenuItem's icon to the "highlighted one", when the user hovers over the menu item (IsMouseOver), by changing the Icon's image source.
Put an image element as the "Content" property for your radio button
<RadioButton Click=HomRadioButtonClick>
<RadioButton.Content>
<Image Source=""/>
</RadioButton.Content>
</RadioButton>
You'll need some extra logic for the hover behavior, but that should at least get the image in your menu.

Categories