Reputation: 876
I have a TreeView where I display items bound via the TreeViews HierarchicalDataTemplate.ItemsSource
. The context-menu of the TreeView changes based on which item is selected. The menu-items depend on the selected item. This means: the context-menu is built completely dynamic. For this purpose I wrote a MenuItemModel
class, that serves as the business-object for a menu item. Like this:
public class MenuItemModel : ViewModelBase
{
public string Header { get; set; }
public string Icon { get; set; }
public ObservableCollection<MenuItemModel> ChildItems { get; set; }
public UiCommand Command { get; set; }
}
So far so good. But now I have two questions:
Question 1 How can I display a separator in the menu? I have another class SeparatorMenuItemModel
that I planned to use for separators. But in that case my ContextMenu needs to contain a Separator
and not a MenuItem
. How can I do that?
Question 2 I tried to use a DataTemplate
to customize how my MenuItems are displayed. But that does not change the menu itself, just the content-part. I'd have to use a ControlTemplate
for that, but how can I make my Menu change ControlTemplate
the way I could do with DataTemplate
?
Upvotes: 1
Views: 1496
Reputation: 876
I have found a way that resolved both issues.
First: I have created two styles. One for the type MenuItemModel
and another for the type SeparatorMenuItemModel
:
<Style x:Key="theMenuItemStyle" TargetType="{x:Type MenuItem}">
...
</Style>
<Style x:Key="theSeparatorStyle" TargetType="{x:Type MenuItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate> ... </ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I used the styles to also change my control template (in addition to some other stuff that's not important here).
I then used a StyleSelector that chooses the Style to be applied based on the type of the item displayed. Like this:
<TreeView.ContextMenu>
<ContextMenu ItemsSource="{Binding ContextMenuItemRoot.ChildItems}"
ItemContainerStyleSelector="{StaticResource MenuItemStyleSelector}" />
</TreeView.ContextMenu>
And the StyleSelector itself is defined like this:
public class MenuItemStyleSelector : StyleSelector
{
public Style MenuItemStyle { get; set; }
public Style SeparatorStyle { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
if (item is SeparatorMenuItemModel)
return SeparatorItemStyle;
return MenuItemStyle;
}
}
Upvotes: 2
Reputation: 939
Looks like you're using a classic Composition pattern here. As far as the SeparatorMenuItemModel, how about having both the MenuItemModel and the SeparatorMenuItemModel inherit from a common class or interface, for example IMenuItemModel (or MenuItemModelBase)? Then you could use
public ObservableCollection<IMenuItemModel> ChildItems {get; set;}
to contain both.
Not sure I entirely understand question 2, but it's important to understand that a ControlTemplate completely replaces the visual tree for a control; essentially you are able to (and have to) completely rebuild the control from scratch. Quite often this is a lot more work than you really want to do.
Upvotes: 0