I'm having a strange issue with my ContextMenu
. The ItemsSource
is a List<Layer> Layers;
, where the Layer
class overrides the ToString()
to return the Name
property.
If I don't use any ItemContainerStyle
for the context menu, it all works fine - it takes the Layer
object and displays the ToString()
of that object, like it should. When I add the ItemContainerStyle
, it shows an empty string.
Here's the XAML:
<Style x:Key="myItemControlTemplate" TargetType="{x:Type MenuItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Border SnapsToDevicePixels="True" Height="32" Width="200" Background="White">
<Grid VerticalAlignment="Center" Height="Auto" Width="Auto" Background="{x:Null}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{TemplateBinding Header}" VerticalAlignment="Top" Foreground="#FF3B3D52"
Grid.Column="1" Margin="6,0,0,0"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button ContextMenuService.IsEnabled="False">
<Button.ContextMenu>
<ContextMenu FontFamily="Global Sans Serif" Height="Auto" Width="200" Padding="0,6" VerticalOffset="5" BorderThickness="0"
HasDropShadow="True" ItemContainerStyle="{StaticResource myItemControlTemplate}">
</ContextMenu>
</Button.ContextMenu>
</Button>
And here's how I fire it:
private void btn_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
ContextMenu ctm = btn.ContextMenu;
ctm.ItemsSource = Layers;
ctm.PlacementTarget = btn;
ctm.Placement = PlacementMode.Bottom;
ctm.IsOpen = true;
}
Could it be that for some reason this binding gets busted somehow?
Text="{TemplateBinding Header}"
BTW, if I change the layers list to be a List<string>
and just feed it the names of the layers, it works correctly with the ItemContainerStyle
.
What am I missing?
The issue is the TemplateBinding
. This is a less powerful but optimized variant of a relative source binding to a templated parent, but it comes at the expense of several limitations, like not supporting two-way binding. Although not officially stated in the documentation, it seems that this binding does not support conversion of the underlying type to string
, as ToString
is never called in this case.
Replace the TemplateBinding
with a binding to the templated parent using relative source.
<TextBlock x:Name="textBlock"
HorizontalAlignment="Left" TextWrapping="Wrap"
Text="{Binding Header, RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="Top" Foreground="#FF3B3D52"
Grid.Column="1" Margin="6,0,0,0"/>