Подтвердить что ты не робот

Как добавить горизонтальный разделитель в динамически созданный ContextMenu?

Я искал решение в Интернете, но не смог найти его в своем примере. Мне нужно добавить разделитель между элементом контекстного меню, которые генерируются из кода позади. Я попытался добавить его с такими строками кода, как показано ниже, но без успеха.

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>

С#, добавленный в методе:

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); 
4b9b3361

Ответ 1

Или вместо того, чтобы связать ContextMenu с коллекцией команд, привязать его к коллекции FrameworkElements, вы можете добавить либо элементы MenuItems или Separators непосредственно в коллекцию, либо позволить элементу управления Menu делать все шаблоны....

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

С#:

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

Просто использовал этот подход в моем приложении - разделитель также выглядит лучше.

Ответ 2

Я сделал это один раз и использовал 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>

Ответ 3

Использовать 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;
        }
    }

Ответ 4

Чтобы сделать это правильно для MVVM, вы должны определить свой собственный интерфейс элемента (fe IMenuItem), создать производные классы для Меню/ ContextMenu и для MenuItem, в этих классах переопределяются следующие виртуальные защищенные методы:

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

Убедитесь, что эти методы создают для элементов контейнера типа IMenuItem вашего нового, полученного из типа MenuItem, связывая все необходимые свойства, здесь вы можете различать различные типы IMenuItem для отображения обычных элементов, разделителей или некоторых thins else. Для неизвестных типов вызывать базовую реализацию.

Теперь, если вы свяжете свойство ItemsSource вашего нового, полученного из элемента Меню/ КонтекстMenu с коллекцией IMenuItem, оно покажет ожидаемый результат без необходимости просмотра -материал на стороне ViewModel.

Ответ 5

Я изменил решение, предоставленное Rachel выше, чтобы исправить стиль Separator. Я понимаю, что этот пост старый, но все же один из лучших результатов в Google. В моей ситуации я использовал его для меню и 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>

Без изменения стиля разделителя

С изменением стиля разделителя