In my scenario, I have an ItemsControl
where the DataTemplate
needs to change in a few ways depending on the properties of the item. One of the things that needs to change is the context menu for the item.
I've put together this example to show my situation. Take the following classes:
Class MainWindow
Public Property Things As New List(Of Thing) From {New Thing With {.Name = "Thing 1", .Type = ThingType.A},
New Thing With {.Name = "Thing 2", .Type = ThingType.B},
New Thing With {.Name = "Thing 3", .Type = ThingType.C}}
End Class
Public Class Thing
Public Property Name As String
Public Property Type As ThingType
End Class
Public Enum ThingType
A
B
C
End Enum
Thing
has some data to display (Name
), and something that should influence the template (Type
).
Now take the following XAML:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VBTest"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<ContextMenu x:Key="DefaultMenu">
<MenuItem Header="A or C"/>
</ContextMenu>
<ContextMenu x:Key="BMenu">
<MenuItem Header="B Only"/>
</ContextMenu>
</Window.Resources>
<ItemsControl ItemsSource="{Binding Things}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="local:Thing">
<TextBlock Name="Title" Text="{Binding Name}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Type}" Value="B">
<Setter TargetName="Title" Property="FontWeight" Value="Bold"/>
<Setter Property="ContextMenu" Value="{StaticResource BMenu}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
In DataTemplate.Triggers
, I define a trigger for items of type B
. For these items, I want to change some aspects of the template, so I use TargetName
on the Setter
to change the FontWeight
of a TextBlock
(in the real code I change a number of properties for a number of elements). But I also want to change the ContextMenu
for the entire item. To do this, I use a Setter
without TargetName
and the property ContextMenu
.
The above works somehow. If you run this and right-click "Thing 2" you see BMenu
. But how does this work? What object is the Setter
being applied to? DataTemplate
has no ContextMenu
property.
And I ask this for more than just curiosity. I want all other types of items (A
and C
) to use DefaultMenu
. That should be the default, with the DataTrigger
overriding it for B
items. But I don't even know what object I'm Setter
-ing at this point, so I don't know where or how to set this default.
What object is the Setter being applied to?
It's applied to the ContentPresenter
item container that wraps each element in the Things
source collection.
You can set the default ContextMenu
using an ItemContainerStyle
:
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="ContextMenu" Value="{StaticResource DefaultMenu}"/>
</Style>
</ItemsControl.ItemContainerStyle>