Problem
I have a MenuItem with a control template that changes the MenuItem's Foreground like so:
<ControlTemplate TargetType="MenuItem">
<StackPanel Background="{Binding Background}" Orientation="Horizontal">
<ContentPresenter Content="{TemplateBinding Icon}"/>
<TextBlock Text="{TemplateBinding Header}"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I want to bind the icon's color to this foreground color. The icon is just a circle in this case. I tried the following binding:
<MenuItem Header="Sub">
<MenuItem.Icon>
<Ellipse Width="16" Height="16" Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType=MenuItem}}"/>
</MenuItem.Icon>
</MenuItem>
However, this gives the following binding error on application start and the ellipse ends up not being rendered:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.MenuItem', AncestorLevel='1''. BindingExpression:Path=Foreground; DataItem=null; target element is 'Ellipse' (Name=''); target property is 'Fill' (type 'Brush')
I also tried to put a dummy element in the icon that gets the foreground propagated and bind to this:
<MenuItem.Icon>
<Grid>
<TextBlock Name="foregroundCapture"/>
<Ellipse Width="16" Height="16" Fill="{Binding Foreground, ElementName=foregroundCapture}"/>
</Grid>
</MenuItem.Icon>
But this gives a similar error:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=foregroundCapture'. BindingExpression:Path=Foreground; DataItem=null; target element is 'Ellipse' (Name=''); target property is 'Fill' (type 'Brush')
How can I make the binding work? FYI, the icon will be an object in a resource dictionary in the end. So it will not have access to the actual menu item.
Alternative Solutions
I can think of a couple of alternative solutions. But none of them are actually very nice:
- Create a subclass of MenuItem that has a
MouseOverIconproperty and have the trigger use it. - Create custom controls for each icon, which have the
Foregroundproperty propagated. This would allow a direct binding directly within the control.
Full Example
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="Role" Value="SubmenuItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<StackPanel Background="{Binding Background}" Orientation="Horizontal">
<ContentPresenter Content="{TemplateBinding Icon}"/>
<TextBlock Text="{TemplateBinding Header}"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="Header">
<MenuItem Header="Sub">
<MenuItem.Icon>
<Grid>
<TextBlock Name="foregroundCapture"/>
<Ellipse Width="16" Height="16" Fill="{Binding Foreground, ElementName=foregroundCapture}"/>
</Grid>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
<Grid>
</Grid>
</DockPanel>
</Window>