Я бы хотел иметь возможность связать ItemsSource
из ContextMenu
с Collection
в моей модели вида, показать Separator
s в ContextMenu
, и ItemsSource
должно бытьиерархический (каждый уровень иерархии будет выглядеть одинаково).
В один из моих других вопросов Мне удалось показать элементы меню и разделители в привязке данных ContextMenu
,но сейчас я изо всех сил пытаюсь сделать иерархию ItemsSource
.
Сейчас я не знаю, что происходит, может быть, вы можете просветить меня?
Вот мой код снова (упрощенно, чтобы быть кратким, но работает):
MenuItemViewModel.vb
Public Class MenuItemViewModel
Implements ICommand
Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
Public Property IsSeparator As Boolean
Public Property Caption As String
Private ReadOnly _subItems As List(Of MenuItemViewModel)
Public Sub New(createItems As Boolean, level As Byte)
_subItems = New List(Of MenuItemViewModel)
If createItems Then
_subItems.Add(New MenuItemViewModel(level < 4, level + 1) With {.Caption = "SubItem 1"})
_subItems.Add(New MenuItemViewModel(False, level + 1) With {.IsSeparator = True, .Caption = "SubSep 1"})
_subItems.Add(New MenuItemViewModel(level < 4, level + 1) With {.Caption = "SubItem 2"})
End If
End Sub
Public ReadOnly Property SubItems As List(Of MenuItemViewModel)
Get
Return _subItems
End Get
End Property
Public ReadOnly Property Command As ICommand
Get
Return Me
End Get
End Property
Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
MessageBox.Show(Me.Caption)
End Sub
Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
Return True
End Function
End Class
Модель представления для каждого элемента меню на каждом уровне имеет Caption
для отображения в контекстном менюфлаг IsSeparator
, указывающий, является ли он разделителем или функциональным элементом меню, Command
, с которым нужно связываться, когда он является функциональным элементом меню, и, конечно, коллекция SubItems
, содержащая функциональные элементы меню и разделители вплоть до определенногоуровень иерархии.
MainViewModel.vb
Public Class MainViewModel
Private ReadOnly _items As List(Of MenuItemViewModel)
Public Sub New()
_items = New List(Of MenuItemViewModel)
_items.Add(New MenuItemViewModel(True, 0) With {.Caption = "Item 1"})
_items.Add(New MenuItemViewModel(False, 0) With {.IsSeparator = True, .Caption = "Sep 1"})
_items.Add(New MenuItemViewModel(True, 0) With {.Caption = "Item 2"})
_items.Add(New MenuItemViewModel(True, 0) With {.Caption = "Item 3"})
_items.Add(New MenuItemViewModel(False, 0) With {.IsSeparator = True, .Caption = "Sep 2"})
_items.Add(New MenuItemViewModel(True, 0) With {.Caption = "Item 4"})
End Sub
Public ReadOnly Property Items As List(Of MenuItemViewModel)
Get
Return _items
End Get
End Property
End Class
Модель основного вида имеет только коллекцию Items
, содержащую элементы функционального меню и разделители.
MainWindow.xaml
<Window x:Class="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:WpfApp3"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:MainViewModel, IsDesignTimeCreatable=True}"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Window.Resources>
<ControlTemplate x:Key="mist" TargetType="{x:Type MenuItem}">
<Separator />
</ControlTemplate>
<ControlTemplate x:Key="mict" TargetType="{x:Type MenuItem}">
<MenuItem Header="{Binding Caption}" Command="{Binding Command}" ItemsSource="{Binding SubItems}" />
</ControlTemplate>
<Style x:Key="cmics" TargetType="{x:Type MenuItem}">
<Setter Property="Template" Value="{StaticResource mict}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSeparator}" Value="True">
<Setter Property="Template" Value="{StaticResource mist}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Text="Right click me">
<TextBox.ContextMenu>
<ContextMenu ItemsSource="{Binding Items}" ItemContainerStyle="{StaticResource cmics}">
<ContextMenu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding SubItems}" />
</ContextMenu.ItemTemplate>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</Grid>
</Window>
Ресурсы окна содержат два ControlTemplate
s "mist" и "mict" и Style
"cmics", которые переключаются между двумя ControlTemplate
s в зависимости от значения флага IsSeparator
.Это прекрасно работает, если ItemsSource
не является иерархическим (см. мой другой вопрос ).
Если мои Style
"смайлики" присоединены к ItemContainerStyle
из *Только 1054 * (как в моем примере кода), тогда это выглядит так:
Первый уровень работает, но другие нет.Это не изменится и при присоединении моих Style
"cmics" к ItemContainerStyle
из HierarchicalDataTemplate
.
Если я только прикреплю свои Style
"cmics" к HierarchicalDataTemplate
, тоэто выглядит так:
Первый уровень не показывает заголовки и разделители, второй уровень работает, а другие уровни не работают.
Итак, как я могу убедить ContextMenu
использовать мои Style
"cmics" в качестве ItemContainerStyle
для каждого уровня иерархии?