2015-06-28 4 views
1

У меня есть TreeView, где я показываю элементы, связанные через TreeViews HierarchicalDataTemplate.ItemsSource. Контекстное меню TreeView изменяется в зависимости от того, какой элемент выбран. Элементы меню зависят от выбранного элемента. Это означает: контекстное меню построено полностью динамично. Для этого я написал класс MenuItemModel, который служит бизнес-объектом для элемента меню. Например:WPF Build ContextMenu динамически через MVVM

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; } 
} 

Пока все хорошо. Но теперь у меня есть два вопроса:

Вопрос 1 Как отображать разделитель в меню? У меня есть другой класс SeparatorMenuItemModel, который я планировал использовать для разделителей. Но в этом случае мой ContextMenu должен содержать Separator, а не MenuItem. Как я могу это сделать?

Вопрос 2 Я попытался использовать DataTemplate, чтобы настроить, как отображаются мои пункты MenuItems. Но это не изменяет меню, а только часть содержимого. Я должен был бы использовать ControlTemplate для этого, но как я могу изменить свое меню на ControlTemplate так, как я мог бы сделать с DataTemplate?

ответ

1

Я нашел способ решить обе проблемы.

Во-первых: Я создал два стиля. Один для типа MenuItemModel и другого для типа 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> 

Я использовал стили также изменить шаблон управления (в дополнении к какому-либо другому материалу, который не важно здесь).

Затем я использовал StyleSelector, который выбирает стиль, который будет применяться в зависимости от типа отображаемого элемента. Как это:

<TreeView.ContextMenu> 
    <ContextMenu ItemsSource="{Binding ContextMenuItemRoot.ChildItems}" 
       ItemContainerStyleSelector="{StaticResource MenuItemStyleSelector}" /> 
    </TreeView.ContextMenu> 

И сама StyleSelector определяется следующим образом:

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; 
    } 
} 
0

Похоже, вы используете классический образец композиции здесь. Что касается SeparatorMenuItemModel, как насчет того, как и MenuItemModel, и SeparatorMenuItemModel наследуются от общего класса или интерфейса, например, IMenuItemModel (или MenuItemModelBase)? Тогда вы можете использовать

public ObservableCollection<IMenuItemModel> ChildItems {get; set;} 

, содержащий оба.

Не уверен, что я полностью понимаю вопрос 2, но важно понимать, что ControlTemplate полностью заменяет визуальное дерево для элемента управления; по сути, вы можете (и должны) полностью перестроить управление с нуля. Довольно часто это намного больше, чем вы действительно хотите.

+0

Мои "SeparatorMenuItemModel" происходит от MenuItemModel. Так что это не проблема. Я говорил о том, как настроить отображение меню «MenuItem» или «Separator» на основе типа данных. Для ControlTemplate: да, я знаю. Я просто хотел знать, есть ли какие-то механизмы «ControlTemplateSelector». – Hemisphera

Смежные вопросы