挣扎与ContextMenu中的HierarchicalDataTemplate

时间:2019-05-25 05:23:45

标签: wpf contextmenu hierarchicaldatatemplate

我希望能够将ItemsSource的{​​{1}}绑定到我的视图模型中的ContextMenu,并在{{1} },并且Collection必须是层次结构的(层次结构的每个级别看起来都一样)。

one of my other questions中,我设法能够在数据绑定的Separator中显示菜单项和分隔符,但是现在我很难使ContextMenu成为分层结构。

现在我不知道发生了什么,也许您可​​以启发我?

这又是我的代码(简化了一下,但是可以正常工作):

MenuItemViewModel.vb

ItemsSource

每个级别上每个菜单项的视图模型都有一个ContextMenu显示在上下文菜单中,一个ItemsSource标志指示它是分隔符还是功能菜单项,{{1 }}作为功能菜单项时的绑定,当然还有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 集合,其中包含功能菜单项和分隔符,直到特定的层次结构级别。

MainViewModel.vb

Caption

主视图模型仅包含一个IsSeparator集合,其中包含功能菜单项以及分隔符。

MainWindow.xaml

Command

窗口资源包含两个SubItems的“ mist”和“ mict”,以及一个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 “ cmics”,根据{{的值在两个Items之间切换1}}标志。只要<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> 不分层(参见my other question),此方法就可以正常工作。

如果仅将我的ControlTemplate“ cmics”附加到Style的{​​{1}}(如我的示例代码),则它看起来像这样:

enter image description here

第一个级别有效,而其他级别则无效。将我的ControlTemplate“ cmics”附加到IsSeparator的{​​{1}}时,这种情况也不会改变。

如果我仅将ItemsSource“ cmics”附加到Style,则它看起来像这样:

enter image description here

第一级不显示标题和分隔符,第二级有效,而其他级别无效。

那么,如何说服ItemContainerStyle将我的ContextMenu“ cmics”用作每个层次结构级别的Style

2 个答案:

答案 0 :(得分:1)

我找到了答案here

我必须为分隔符创建一个空视图模型,并创建一个从ItemContainerTemplateSelector派生的类,以返回属于菜单项类型的DataTemplate(“ MenuItemViewModel”或“ SeparatorViewModel “)。

链接的文章应具有自我解释性。

答案 1 :(得分:0)

我只是在Xaml部分对您的(TextBox)做了一些更改。看看这个,

<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Text="Right click me">
            <TextBox.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding SubItems}">
                    <Button Content="{Binding Caption}" Command="{Binding Command}" Background="Red"/>
                </HierarchicalDataTemplate>
            </TextBox.Resources>
            <TextBox.ContextMenu>
                <ContextMenu ItemsSource="{Binding Items}" ItemContainerStyle="{StaticResource cmics}"/>
            </TextBox.ContextMenu>
        </TextBox>

基本上,我已删除了ContexttMenu ItemTemplate,并在TextBox下添加了。提供了一个分层数据模板。

我现在在数据模板中添加了一个单选按钮。您可以根据需要更改内容。

让我知道这是否可以解决您的问题,或者是否需要其他帮助。