如何在动态创建的ContextMenu中添加水平分隔符?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在动态创建的ContextMenu中添加水平分隔符?相关的知识,希望对你有一定的参考价值。

我在互联网上寻找解决方案,但无法在我的样本中找到它。我需要在从代码隐藏生成的Context菜单项之间添加一个分隔符。我尝试使用如下代码行添加它但没有成功。

this.Commands.Add(new ToolStripSeparator()); 

我想知道是否有人可以提供帮助。先感谢您。

上下文菜单XAML:

<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}">
    <Setter Property="ContextMenu">
        <Setter.Value>
            <ContextMenu ItemsSource="{Binding Commands}">
                <ContextMenu.ItemContainerStyle>
                    <Style TargetType="{x:Type MenuItem}">
                        <Setter Property="Command" Value="{Binding}" />
                        <Setter Property="Header" Value="{Binding Path=Text}" />
                        <Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />
                    </Style>
                </ContextMenu.ItemContainerStyle>
            </ContextMenu>
        </Setter.Value>
    </Setter>

在方法中添加的C#:

this.Commands = new ObservableCollection<ICommand>();
        this.Commands.Add(MainWindow.AddRole1);
        this.Commands.Add(MainWindow.AddRole2);
        this.Commands.Add(MainWindow.AddRole3);
        this.Commands.Add(MainWindow.AddRole4);
        //this.Add(new ToolStripSeparator()); 
        this.Commands.Add(MainWindow.AddRole5);
        this.Commands.Add(MainWindow.AddRole6);
        this.Commands.Add(MainWindow.AddRole7); 
答案

或者,不是将ContextMenu绑定到命令集合,而是将其绑定到FrameworkElements的集合,然后您可以将MenuItems或Separator直接添加到集合中,让Menu控件执行所有模板....

<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}">
    <Setter Property="ContextMenu">
        <Setter.Value>
            <ContextMenu ItemsSource="{Binding Commands}" />
        </Setter.Value>
    </Setter>
</Style>

C#:

this.Commands = new ObservableCollection<FrameworkElement>();

this.Commands.Add(new MenuItem {Header = "Menuitem 2", Command = MainWindow.AddRole1});
this.Commands.Add(new MenuItem {Header = "Menuitem 2", Command = MainWindow.AddRole2});
this.Commands.Add(new MenuItem {Header = "Menuitem 3", Command = MainWindow.AddRole3});
this.Commands.Add(new MenuItem {Header = "Menuitem 4", Command = MainWindow.AddRole4});

this.Commands.Add(new Separator);

this.Commands.Add(new MenuItem {Header = "Menuitem 5", Command = MainWindow.AddRole5});
this.Commands.Add(new MenuItem {Header = "Menuitem 6", Command = MainWindow.AddRole6});
this.Commands.Add(new MenuItem {Header = "Menuitem 7", Command = MainWindow.AddRole7});

刚刚在我的应用中使用了这种方法 - 分隔符看起来也更好。

另一答案

我这样做了一次并使用null作为我的分隔符。从XAML开始,如果datacontext为null,我将模板设置为使用分隔符

代码背后:

this.Commands.Add(MainWindow.AddRole4);
this.Add(null); 
this.Commands.Add(MainWindow.AddRole5);

XAML是这样的:

<ContextMenu.ItemContainerStyle>
    <Style TargetType="{x:Type MenuItem}">
        <Setter Property="Command" Value="{Binding}" />
        <Setter Property="Header" Value="{Binding Path=Text}" />
        <Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />

        <Style.Triggers>
            <DataTrigger Binding="{Binding }" Value="{x:Null}">
                <Setter Property="Template" Value="{StaticResource MenuSeparatorTemplate}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</ContextMenu.ItemContainerStyle>

希望我的语法正确 - 我在这台机器上没有IDE来验证代码

编辑

这是上下文菜单分隔符的示例模板。我将它放在ContextMenu.Resources中,尽管只要ContextMenu可以访问它,你就可以在应用程序中放置它。

<ContextMenu.Resources>
    <ControlTemplate x:Key="MenuSeparatorTemplate">
        <Separator />
    </ControlTemplate>
</ContextMenu.Resources>
另一答案

我修改了上面Rachel提供的解决方案来纠正Separator样式。我意识到这篇文章很老,但仍然是谷歌的最佳成绩之一。在我的情况下,我使用它作为菜单与ContextMenu,但同样应该工作。

XAML

<Menu ItemsSource="{Binding MenuItems}">
    <Menu.Resources>
        <ControlTemplate x:Key="MenuSeparatorTemplate">
            <Separator>
                <Separator.Style>
                    <Style TargetType="{x:Type Separator}" BasedOn="{StaticResource ResourceKey={x:Static MenuItem.SeparatorStyleKey}}"/>
                </Separator.Style>
            </Separator>
        </ControlTemplate>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Header" Value="{Binding MenuItemHeader}" />
            <Setter Property="Command" Value="{Binding MenuItemCommand}" />
            <Setter Property="CommandParameter" Value="{Binding MenuItemCommandParameter}" />
            <Setter Property="ItemsSource" Value="{Binding MenuItemCollection}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding }" Value="{x:Null}">
                    <Setter Property="Template" Value="{StaticResource MenuSeparatorTemplate}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Menu.Resources>
</Menu>

Without Separator Style Change

With Separator Style Change

另一答案

使用ItemTemplateSelector:

public class MenuItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate SeparatorTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var menuItem = container.GetVisualParent<MenuItem>();
        if (menuItem == null)
        {
            throw new Exception("Unknown MenuItem type");
        }

        if (menuItem.DataContext == null)
        {
            return SeparatorTemplate;
        }

        return menuItem.ItemTemplate;
    }
}

XAML:

<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"

                                ItemsSource="{Binding Path=ViewContentMenuItems}" >
                                <ContextMenu.ItemTemplateSelector>
                                    <templateSelectors:MenuItemTemplateSelector>
                                        <templateSelectors:MenuItemTemplateSelector.SeparatorTemplate>
                                            <DataTemplate>
                                                <Separator />
                                            </DataTemplate>
                                        </templateSelectors:MenuItemTemplateSelector.SeparatorTemplate>
                                    </templateSelectors:MenuItemTemplateSelector>
                                </ContextMenu.ItemTemplateSelector>
                            </ContextMenu>

在模型中:

public ObservableCollection<MenuItem> ViewContentMenuItems
    {
        get
        {
            var temp = new ObservableCollection<MenuItem>();
            temp.Add(null);
            temp.Add(CreateFolderMenuItem);
            return temp;
        }
    }
private MenuItem CreateFolderMenuItem
    {
        get
        {
            var createFolderMenuItem = new MenuItem()
            {
                Header = "New Folder",
                Icon = new Image
                {
                    Source = new BitmapImage(new Uri("/icons/folderWinCreate.png", UriKind.Relative)),
                    Height = 16,
                    Width = 16
                }
            };

            Message.SetAttach(createFolderMenuItem, "CreateDocumentsFolder");//Caliburn example
            return createFolderMenuItem;
        }
    }
另一答案

要为MVVM正确执行此操作,您必须定义自己的项目接口(f.e. IMenuItem),为Menu / ContextMenu和MenuItem创建派生类,在这些类中覆盖以下虚拟保护方法:

ItemsControl.PrepareContainerForItemOverride
ItemsControl.ClearContainerForItemOverride
ItemsControl.GetContainerForItemOverride
ItemsControl.IsItemItsOwnContainerOverride

确保此方法为从MenuItem类型派生的新类型的IMenuItem容器创建具有绑定所有需要属性的项目,在这里您可以区分不同类型的IMenuItem以显示正常项目,分隔符或其他一些其他项目。对于未知类型,调用基础实现。

现在,如果你将从Menu / ContextMenu控件派生的新的ItemsSource属性与IMenuItem的集合绑定,它将显示你想要的结果,而不需要现在在ViewModel端查看东西。

以上是关于如何在动态创建的ContextMenu中添加水平分隔符?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式在 UIScrollview 水平分页中的 UITableView

如何在 UITableView 中为每个 Section 启用水平分页

UICollectionView 水平分页布局

如何将水平分页捕捉到 App Store 等多行集合视图?

具有水平分页的 UIScrollView 不居中子视图

带有 TabView、SwiftUI 的水平分页滚动视图