动态创建ContextMenu

时间:2015-11-13 08:18:49

标签: c# wpf xaml contextmenu menuitem

在我的应用程序中,我想动态构建一个上下文菜单。第一个MenuItem是静态的,第二个应该是SeparatorSeparator之后的所有项都是在运行时动态创建的。

我不想使用代码隐藏,因为我正在使用MVVM-Pattern。 我现在的想法是使用以下三个实现来创建一个名为interface的{​​{1}}

  • ModifyMenuItem(静态IAppMenuItem
  • SeparatorMenuItem
  • ExecuteMenuItem(动态MenuItem

在我的应用程序的viewmodel中,我创建了一个MenuItem,其中包含ObservableCollection<IAppMenuItem> - 项目。

直到这里一切正常。我的问题是在UI中显示ContextMenu - 项目。

我尝试在视图的参考资料中使用以下ContextMenu设置正确的控件。

DataTemplate

<DataTemplate DataType="{x:Type model:SeparatorMenuItem}"> <Separator/> </DataTemplate> <DataTemplate DataType="{x:Type model:ModifyMenuItem}"> <MenuItem Header="Edit items"/> </DataTemplate> <DataTemplate DataType="{x:Type model:ExecuteMenuItem}"> <MenuItem Header="{Binding DisplayText}"/> </DataTemplate> 的定义只是:

ContextMenu

<ContextMenu ItemsSource="{Binding MenuItemsCollection}"/> 工作正常,但控件是在DataTemplate内绘制的。例如,对于MenuItem我在UI中看到Separator - 控制Separator - 控件。但我需要MenuItem作为控制。

任何人都知道如何将Separator内的控件直接设置到上下文菜单中?

更新

完整的DataTemplate看起来像:

ContextMenu

GenericToggleButtonStyle只是:

<ToggleButton Margin="0,0,10,0"
              AutomationProperties.Name="Update"
              AutomationProperties.AutomationId="Update_List"
              Content="Update"
              AttachedProperties:ButtonExtensions.IsDropDownButton="True"
              Style="{StaticResource GenericToggleButtonStyle}">
    <ToggleButton.ContextMenu>
        <controls:CustomContextMenu ItemsSource="{Binding MenuItemsCollection}">
            <ContextMenu.Resources>
                <ResourceDictionary>
                    <DataTemplate DataType="{x:Type model:ExecuteMenuItem}">
                        <MenuItem Header="{Binding DisplayText}"/>
                    </DataTemplate>
                    <DataTemplate DataType="{x:Type model:ModifyMenuItem}">
                        <MenuItem Header="Edit items"/>
                    </DataTemplate>
                </ResourceDictionary>
            </ContextMenu.Resources>
        </controls:CustomContextMenu>       
    </ToggleButton.ContextMenu>
</ToggleButton>

以下是<Style x:Key="GenericToggleButtonStyle" TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}"> <Setter Property="MinWidth" Value="80" /> <Setter Property="Height" Value="22" /> <Setter Property="Padding" Value="3,1" /> </Style> s

的屏幕截图

MenuItems

1 个答案:

答案 0 :(得分:1)

似乎当您在ItemSource上设置ContextMenu属性时,使用的默认ItemContainerMenuItem。这就是Separator呈现为MenuItem的原因。

您可以通过实施从ContextMenu继承的自己的ContextMenu控件来解决此问题。

您需要覆盖IsItemItsOwnContainerOverrideGetContainerForItemOverride方法。

请参阅下面的示例:

public class CustomContextMenu 
    : ContextMenu
{
    private bool _mustGenerateAsSeparator = false;

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
         _mustGenerateAsSeparator = (item is SeparatorMenuItem);

         return base.IsItemItsOwnContainerOverride(item);            
    }

    protected override System.Windows.DependencyObject GetContainerForItemOverride()
    {
        if (_mustGenerateAsSeparator)
        {
            return new Separator { Style = this.FindResource(MenuItem.SeparatorStyleKey) as System.Windows.Style };
        }
        else 
        {
            return base.GetContainerForItemOverride();                      
        }            
    }
}
需要

Style = this.FindResource(MenuItem.SeparatorStyleKey) as System.Windows.Style,因为您必须应用默认的MenuItem.SeparatorStyleKey样式才能获得默认的分隔符样式。

此链接指向正确的方向http://drwpf.com/blog/category/item-containers/

如何在XAML中使用自定义控件:

窗口声明:xmlns:cnt="your namespace"

<Label Content="Dynamic Menu">
        <Label.ContextMenu>                
            <cnt:CustomContextMenu x:Name="contextMenu" ItemsSource="{Binding MenuItemsCollection}">                    
                <ContextMenu.Resources>
                    <ResourceDictionary>                            
                        <DataTemplate DataType="{x:Type model:ExecuteMenuItem}">
                            <MenuItem Header="{Binding DisplayText}"></MenuItem>
                        </DataTemplate>
                        <DataTemplate DataType="{x:Type model:ModifyMenuItem}">
                            <MenuItem Header="{Binding DisplayText}"></MenuItem>
                        </DataTemplate>                            
                    </ResourceDictionary>
                </ContextMenu.Resources>
            </model:CustomContextMenu>                            
        </Label.ContextMenu>
    </Label> 

问题的第二部分:

更新您的数据模板以使用TextBlock,因为它们将在MenuItem内呈现,请参阅以下内容:

<DataTemplate DataType="{x:Type model:ModifyMenuItem}">
    <TextBlock Header="Edit items"/>
</DataTemplate>

<DataTemplate DataType="{x:Type model:ExecuteMenuItem}">
    <TextBlock Header="{Binding DisplayText}"/>
</DataTemplate>