无法将WPF菜单绑定到ItemsSource

时间:2021-09-27 17:02:41

I would like to avoid having to build a menu manually in XAML or code, by binding to a list of ICommand-derived objects. However, I'm experiencing a bit of a problem where the resulting menu has two levels of menu-items (i.e. each MenuItem is contained in a MenuItem):

我想通过绑定到ICommand派生对象列表来避免在XAML或代码中手动构建菜单。但是,我遇到了一个问题,结果菜单有两级菜单项(即每个MenuItem包含在MenuItem中):

alt text http://i47.tinypic.com/j63lg2.png

替代文字http://i47.tinypic.com/j63lg2.png

My guess is that this is happening because WPF is automatically generating a MenuItem for my binding, but the "viewer" I'm using actually already is a MenuItem (it's derived from MenuItem):

我的猜测是这种情况正在发生,因为WPF会自动为我的绑定生成一个MenuItem,但我实际使用的“viewer”是一个MenuItem(它是从MenuItem派生的):

<ContextMenu
    x:Name="selectionContextMenu"
    ItemsSource="{Binding Source={x:Static OrangeNote:Note.MultiCommands}}"
    ItemContainerStyleSelector="{StaticResource separatorStyleSelector}">
    <ContextMenu.ItemTemplate>
        <DataTemplate>
            <Viewers:NoteCommandMenuItemViewer
                CommandParameter="{Binding Source={x:Static OrangeNote:App.Screen}, Path=SelectedNotes}" />
        </DataTemplate>
    </ContextMenu.ItemTemplate>
</ContextMenu>

(The ItemContainerStyleSelector is from http://bea.stollnitz.com/blog/?p=23, which allows me to have Separator elements inside my bound source.)

(ItemContainerStyleSelector来自http://bea.stollnitz.com/blog/?p=23,它允许我在绑定源中包含Separator元素。)

So, the menu is bound to a collection of ICommands, and each item's CommandParameter is set to the same global target (which happens to be a collection, but that's not important).

因此,菜单绑定到ICommands的集合,并且每个项的CommandParameter都设置为相同的全局目标(恰好是一个集合,但这并不重要)。

My question is, is there any way I can bind this such that WPF doesn't automatically wrap each item in a MenuItem?

我的问题是,有什么方法可以绑定它,以便WPF不会自动包装MenuItem中的每个项目?

2 个解决方案

#1


2  

I would be inclined to subclass ContextMenu and override GetContainerForItemOverride:

我倾向于继承ContextMenu并重写GetContainerForItemOverride:

public class ContextMenuWithNoteCommands : ContextMenu
{
  protected virtual DependencyObject GetContainerForItemOverride()
  {
    return new NoteCommandMenuItemViewer();
  }
}

Then set the CommandParameter binding in the NoteCommandMenuItemViewer style, or in ContextMenu.ItemContainerStyle, whichever is more appropriate.

然后在NoteCommandMenuItemViewer样式或ContextMenu.ItemContainerStyle中设置CommandParameter绑定,以更合适的方式。

This presumes you can't simply use ItemContainerStyle on a regular MenuItem to get the effect you want:

这假设你不能简单地在常规MenuItem上使用ItemContainerStyle来获得你想要的效果:

<ContextMenu ...>
  <ContextMenu.ItemContainerStyle>
    <Style>
      ...
    </Style>
  </ContextMenu.ItemContainerStyle>
</ContextMenu>

#2


3  

Unfortunately, the best way I've found to work around this issue is to use a style for the MenuItems, rather than an ItemTemplate. Then each property in the style can be bound to properties on your object. Something like this, for example:

不幸的是,我发现解决这个问题的最好方法是使用MenuItems的样式,而不是ItemTemplate。然后,样式中的每个属性都可以绑定到对象上的属性。像这样的东西,例如:

<Style x:Key="SelectionContextMenuStyle" TargetType="MenuItem">
    <Setter Property="Header" Value="{Binding Path=Text}" />
    <Setter Property="Command" Value="{Binding Path=Command}" />
    <Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />
</Style>

It really seems like an ItemTemplate should work, and it would be the better way to go, but this is the only way I've found that actually works properly.

它看起来好像是一个ItemTemplate应该工作,这将是更好的方式,但这是我发现实际上正常工作的唯一方法。

#1


2  

I would be inclined to subclass ContextMenu and override GetContainerForItemOverride:

我倾向于继承ContextMenu并重写GetContainerForItemOverride:

public class ContextMenuWithNoteCommands : ContextMenu
{
  protected virtual DependencyObject GetContainerForItemOverride()
  {
    return new NoteCommandMenuItemViewer();
  }
}

Then set the CommandParameter binding in the NoteCommandMenuItemViewer style, or in ContextMenu.ItemContainerStyle, whichever is more appropriate.

然后在NoteCommandMenuItemViewer样式或ContextMenu.ItemContainerStyle中设置CommandParameter绑定,以更合适的方式。

This presumes you can't simply use ItemContainerStyle on a regular MenuItem to get the effect you want:

这假设你不能简单地在常规MenuItem上使用ItemContainerStyle来获得你想要的效果:

<ContextMenu ...>
  <ContextMenu.ItemContainerStyle>
    <Style>
      ...
    </Style>
  </ContextMenu.ItemContainerStyle>
</ContextMenu>

#2


3  

Unfortunately, the best way I've found to work around this issue is to use a style for the MenuItems, rather than an ItemTemplate. Then each property in the style can be bound to properties on your object. Something like this, for example:

不幸的是,我发现解决这个问题的最好方法是使用MenuItems的样式,而不是ItemTemplate。然后,样式中的每个属性都可以绑定到对象上的属性。像这样的东西,例如:

<Style x:Key="SelectionContextMenuStyle" TargetType="MenuItem">
    <Setter Property="Header" Value="{Binding Path=Text}" />
    <Setter Property="Command" Value="{Binding Path=Command}" />
    <Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />
</Style>

It really seems like an ItemTemplate should work, and it would be the better way to go, but this is the only way I've found that actually works properly.

它看起来好像是一个ItemTemplate应该工作,这将是更好的方式,但这是我发现实际上正常工作的唯一方法。