Как добавить горизонтальный разделитель в динамически создаваемый ContextMenu? - PullRequest
20 голосов
/ 28 января 2011

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

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

Ответы [ 5 ]

44 голосов
/ 28 января 2011

Я сделал это один раз и использовал null в качестве разделителя.Из XAML я затем стилизовал шаблон, чтобы использовать разделитель, если текст данных был нулевым

Код сзади:

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

XAML был примерно таким:* Надеюсь, я правильно понял синтаксис - у меня нет IDE на этом компьютере для проверки кода

EDIT

Вот пример шаблона для контекстного менюразделитель.Я помещаю его в ContextMenu.Resources, хотя вы можете поместить это в любое место в своем приложении, если только ContextMenu может получить к нему доступ.

<ContextMenu.Resources>
    <ControlTemplate x:Key="MenuSeparatorTemplate">
        <Separator />
    </ControlTemplate>
</ContextMenu.Resources>
12 голосов
/ 09 июня 2011

Или, вместо того чтобы привязать 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>

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

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

4 голосов
/ 22 декабря 2017

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

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

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

1 голос
/ 26 июля 2013

Использовать 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;
        }
    }
0 голосов
/ 30 января 2017

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

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

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

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

...