【问题标题】:Binding Items collection on Menu to be shown on MenuItem Popup将菜单上的绑定项目集合显示在 MenuItem 弹出窗口上
【发布时间】:2018-10-15 20:00:56
【问题描述】:

我需要一个自定义菜单(AMTMenu 类继承菜单加上一些额外的 DependencyProperties)和一个带有动态子项的 MenuItem(实际上是一个汉堡按钮),因为这个菜单要在很多布局中重复使用。除此之外,它应该显示其他 5 个 TopLevel 菜单项,这些菜单项显示 DataContext 中包含的信息,没有附加任何子项和刷新按钮。它工作正常,除了当我单击汉堡包 MenuItem 时未显示的子菜单部分,因为我似乎无法正确绑定项目。这是我到目前为止的代码:

<Menu.Template>
    <ControlTemplate>
        <Grid Name="ContentGrid"
              Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Width}"
              IsItemsHost="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="HamburgerButtonColumn" Width="5*" />
                <ColumnDefinition x:Name="ButtonsColumn" Width="90*" />
                <ColumnDefinition x:Name="RefreshButtonColumn" Width="5*"/>
            </Grid.ColumnDefinitions>
            <MenuItem Foreground="{DynamicResource BlackBrush}"
                      Focusable="False"
                      Template="{DynamicResource MainMenuButtonTemplate}">
                <MenuItem.Icon>
                    <iconPacks:PackIconMaterial Kind="Menu"
                                                HorizontalAlignment="Left"
                                                VerticalAlignment="Center"
                                                MinHeight="20" />
                </MenuItem.Icon>
            </MenuItem>
            <UniformGrid Name="ButtonsUniformGrid"
                         Grid.Column="1"
                         Columns="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:AMTMenu}}, Path=ButtonCount}"
                         Rows="1"
                         HorizontalAlignment="Stretch">
                <MenuItem Grid.Column="0"
                          Template="{DynamicResource OiButtonsTemplate}"
                          Foreground="{Binding RelativeSource={RelativeSource Self}, Path=Tag, Converter={StaticResource OiMainMenuButtonsColorBrushConverter}}"
                          Focusable="False"
                          Command="{Binding ShowRefreshDataCommand}"
                          CommandParameter="Button1">
                    <MenuItem.Tag>
                        <MultiBinding Converter="{StaticResource MainMenuButtonsTextConverter}" ConverterParameter="INC">
                            [ ... MultiBinding logic ... ]
                        </MultiBinding>
                    </MenuItem.Tag>
                </MenuItem>

                [ ... XAML Code for the other 4 MenuItems ... ]

            </UniformGrid>
            <DockPanel Name="PART_Refresh"
                       Grid.Column="2"
                       HorizontalAlignment="Stretch"
                       VerticalAlignment="Stretch">

                [ ... XAML Code for the refresh button ... ]

            </DockPanel>
        </Grid>
    </ControlTemplate>
</Menu.Template>

至于汉堡包菜单项,我有以下模板:

<ControlTemplate x:Key="MainMenuButtonTemplate"
                 TargetType="{x:Type MenuItem}">
    <Grid SnapsToDevicePixels="true"
          HorizontalAlignment="Stretch">
        <StackPanel Background="{TemplateBinding Background}"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center">
            <ContentControl x:Name="PART_Button"
                            Foreground="{TemplateBinding Foreground}"
                            Background="{TemplateBinding Background}"
                            Content="{TemplateBinding Icon}"
                            Focusable="False" />
        </StackPanel>
        <Popup x:Name="PART_Popup" 
               AllowsTransparency="true"
               Focusable="false"
               HorizontalOffset="1"
               IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}"
               PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}"
               Placement="Bottom"
               VerticalOffset="-1">
            <Border BorderThickness="2"
                    BorderBrush="White"
                    Background="{TemplateBinding Background}">
                <ScrollViewer x:Name="SubMenuScrollViewer"
                              CanContentScroll="true"
                              Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
                    <Grid RenderOptions.ClearTypeHint="Enabled">
                        <ItemsPresenter x:Name="ItemsPresenter"
                                        KeyboardNavigation.DirectionalNavigation="Cycle"
                                        Grid.IsSharedSizeScope="true"
                                        Margin="2"
                                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                        KeyboardNavigation.TabNavigation="Cycle"/>
                    </Grid>
                </ScrollViewer>
            </Border>
        </Popup>
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Foreground" Value="{DynamicResource AccentColorBrush}" TargetName="PART_Button"/>
            <Setter Property="Background" Value="{DynamicResource GrayBrush}" TargetName="PART_Button"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

最后,我用以下 XAML 声明菜单和子菜单:

<local:AMTMenu x:Name="MainMenu"
                   DockPanel.Dock="Top"
                   DataContext="{Binding CurrentModel}"
                   IsButton1Visible="True"
                   IsButton2Visible="True"
                   IsButton3Visible="True"
                   IsButton4Visible="True"
                   IsButton5Visible="False">
    <MenuItem Header="Item 1" />
    <Separator />
    <MenuItem Header="Item 2" />
    <Separator />
    <MenuItem Header="Item 3" />
</local:AMTMenu>

如何绑定菜单上的 Items 集合以显示在汉堡菜单项弹出窗口上?

【问题讨论】:

  • 您是否有一个视图模型来支持您的视图?在视图模型中,您可以定义一个 ObservableCollection,它可以在视图更新时通知视图
  • 我愿意,但这与我的问题有什么关系?

标签: c# wpf xaml


【解决方案1】:

所以我发现了问题,在这里发布以帮助有类似问题的任何人...问题是在模板上声明了汉堡包 MenuItem,因此,菜单没有得到任何子项,因此没有触发 IsSubmenuOpen MenuItem 上的属性。在我意识到这一点之后,解决方案非常简单,将 Template 上的 MenuItem 替换为 ItemsPresenter 并将 MenuItem 移动到 Menu 内容中。此外,由于 Menu 现在在其类中定义了 Items,我不能像以前那样声明子菜单,它只会替换我的默认项,所以我必须使用一个名为 SubMenuItems 的新 DependencyProperty。

这是最终代码:

AMTMenu.xaml

<Menu>
    <Menu.Template>
        <ControlTemplate>
            <Grid Name="ContentGrid"
                  Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Width}"
                  IsItemsHost="True">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition x:Name="HamburgerButtonColumn" Width="5*" />
                    <ColumnDefinition x:Name="ButtonsColumn" Width="90*" />
                    <ColumnDefinition x:Name="RefreshButtonColumn" Width="5*"/>
                </Grid.ColumnDefinitions>
                <ItemsPresenter x:Name="ItemsPresenter"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                KeyboardNavigation.DirectionalNavigation="Cycle"
                                Grid.IsSharedSizeScope="true"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                KeyboardNavigation.TabNavigation="Cycle" />
                <UniformGrid Name="ButtonsUniformGrid"
                             Grid.Column="1"
                             Columns="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:AMTMenu}}, Path=ButtonCount}"
                             Rows="1"
                             HorizontalAlignment="Stretch">
                    <MenuItem Grid.Column="0"
                              Template="{DynamicResource OiButtonsTemplate}"
                              Foreground="{Binding RelativeSource={RelativeSource Self}, Path=Tag, Converter={StaticResource OiMainMenuButtonsColorBrushConverter}}"
                              Focusable="False"
                              Command="{Binding ShowRefreshDataCommand}"
                              CommandParameter="Button1">
                        <MenuItem.Tag>
                            <MultiBinding Converter="{StaticResource MainMenuButtonsTextConverter}" ConverterParameter="INC">
                                [ ... MultiBinding logic ... ]
                            </MultiBinding>
                        </MenuItem.Tag>
                    </MenuItem>

                    [ ... XAML Code for the other 4 MenuItems ... ]

                </UniformGrid>
                <DockPanel Name="PART_Refresh"
                           Grid.Column="2"
                           HorizontalAlignment="Stretch"
                           VerticalAlignment="Stretch">

                    [ ... XAML Code for the refresh button ... ]

                </DockPanel>
            </Grid>
        </ControlTemplate>
    </Menu.Template>
    <MenuItem Foreground="{DynamicResource BlackBrush}"
              Focusable="False"
              Template="{DynamicResource MainMenuButtonTemplate}"
              AllowDrop="True"
              ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=local:AMTMenu}, Path=SubMenuItems}">
        <MenuItem.Icon>
            <iconPacks:PackIconMaterial Kind="Menu" MinHeight="20" />
        </MenuItem.Icon>
    </MenuItem>
</Menu>

父视图上的菜单声明:

<local:AMTMenu x:Name="MainMenu"
               DockPanel.Dock="Top"
               DataContext="{Binding CurrentModel}"
               IsButton1Visible="True"
               IsButton2Visible="True"
               IsButton3Visible="True"
               IsButton4Visible="True"
               IsButton5Visible="False">
    <local:AMTMenu.SubMenuItems>
        <local:SubMenuItemsCollection>
            <MenuItem Header="Item 1" />
            <Separator />
            <MenuItem Header="Item 2" />
            <Separator />
            <MenuItem Header="Item 3" />
        </local:SubMenuItemsCollection>
    </local:AMTMenu.SubMenuItems>
</local:AMTMenu>

SubMenuItemsCollection 只是一个派生自 ObservableCollection 的类

public class SubMenuItemsCollection : ObservableCollection<FrameworkElement> { }

希望这对将来的某人有所帮助;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-28
    • 2013-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多