将集合绑定到ContextMenu子菜单 [英] Binding collection to ContextMenu submenu

查看:85
本文介绍了将集合绑定到ContextMenu子菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在做一些看起来很简单但实际上并非如此的事情时遇到了麻烦。

I'm having trouble doing something that seemed really easy but which is not actually.

我有一个ListView,其中绑定了一个ObservableCollection,我想要一个当我右键单击该ListView的元素时,将显示ContextMenu。

I have a ListView in which i binded an ObservableCollection, and i want a ContextMenu to appear when i rightclick an element of that ListView.

在该ContextMenu中,我想要一个菜单​​项,上面写着添加到播放列表,并在其中列出所有列表我的播放列表。

In that ContextMenu, i want a MenuItem that says "Add to Playlist" and inside it, the list of all of my playlists.

所以我做到了,这对我来说很合适:

So i did this, which looks right to me:

<ListView Grid.Row="0" Grid.Column="1" x:Name="ListBoxSelectedFolder" ItemsSource="{Binding Path=SelectedFolder.PlayableElements}">
      <ListView.Resources>
        <ContextMenu x:Key="ContextMenu">
          <MenuItem Header="Add to" ItemsSource="{Binding Path=Playlists}">
            <MenuItem Header="{Binding Name}"/>
          </MenuItem>
          <MenuItem Header="Remove from All" />
        </ContextMenu>
      <Style TargetType="{x:Type ListViewItem}">
         <Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
    </Style>
      </ListView.Resources>
      <ListView.View>
        <GridView>
            <GridViewColumn Header="Type" DisplayMemberBinding="{Binding Extension}" />
            <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
        </GridView>
    </ListView.View>
</ListView>

问题是,我在子菜单中唯一得到的就是我单击的项目的名称:以某种方式,它与ListView的集合SelectedFolder.PlayableElements绑定,因为SelectedFolder.PlayableElements和播放列表都具有Name属性。

The thing is that the only thing i get in my submenu is the name of the item i clicked on: somehow, it's binding with the collection of the ListView, SelectedFolder.PlayableElements, because both SelectedFolder.PlayableElements and Playlists have a Name property.

因此两个绑定之间存在某种冲突,我不知道该如何解决。

So there is some sort of conflict between the two bindings, and i don't know how to solve it.

预先感谢您的答复。

推荐答案

ContextMenu 与可视树分离,因此使用 ElementName RelativeSource 无法以正常方式进行。您需要一些代理技术来桥接切割。在这里,我们有 Freezable 元素,该元素可以继承数据上下文,并且即使在这种情况下也可以绑定到视觉树。为了方便起见,我们应该使用 DiscreteObjectKeyFrame ,因为其Value可以接受所有类型的对象。如果您关心名称,则可以定义自己的自定义Freezable对象。

The ContextMenu is detached from the visual tree so Binding inside its scope with ElementName or RelativeSource is not possible in a normal way. You need some proxy technique to bridge the cutting. Here we have the Freezable element which can inherit data context as well as allow binding to walkup the visual tree even in this situation easily. For convenience we should use the DiscreteObjectKeyFrame because its Value can accept all kinds of object. If you care about the name, then you can define your own custom Freezable object.

<ListView Grid.Row="0" Grid.Column="1" x:Name="ListBoxSelectedFolder" ItemsSource="{Binding Path=SelectedFolder.PlayableElements}">
  <ListView.Resources>
    <DiscreteObjectKeyFrame x:Key="proxy" Value="{Binding Playlists, RelativeSource={RelativeSource AncestorType=Window}}"/>
    <ContextMenu x:Key="ContextMenu">
      <MenuItem Header="Add to" ItemsSource="{Binding Value, Source={StaticResource proxy}}">
         <MenuItem.ItemTemplate>
             <DataTemplate>
                 <TextBlock Text="{Binding Name}"/>
             </DataTemplate>
         </MenuItem.ItemTemplate>
      </MenuItem>
      <MenuItem Header="Remove from All" />
    </ContextMenu>
    <Style TargetType="{x:Type ListViewItem}">
     <Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
    </Style>
  </ListView.Resources>
  <!-- ... -->
</ListView>

编辑-这是为了帮助您了解如何混合使用信息从播放列表和SelectedFolder中获取:

Edit - this is to help you understand how you can mix the info from both Playlists and SelectedFolder:

<ListView Grid.Row="0" Grid.Column="1" x:Name="ListBoxSelectedFolder" ItemsSource="{Binding Path=SelectedFolder.PlayableElements}">
  <ListView.Resources>
    <DiscreteObjectKeyFrame x:Key="proxy" Value="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
    <ContextMenu x:Key="ContextMenu" DataContext="{Binding Value, Source={StaticResource proxy}}">
      <MenuItem Header="Add to" ItemsSource="{Binding Playlists}">
         <MenuItem.ItemTemplate>
             <DataTemplate>                     
                 <TextBlock Text="{Binding Name}"/>        
             </DataTemplate>
         </MenuItem.ItemTemplate>
      </MenuItem>
      <MenuItem Header="Playable elements" ItemsSource="{Binding SelectedFolder.PlayableElements}"/>
      <MenuItem Header="Remove from All" />
    </ContextMenu>
    <Style TargetType="{x:Type ListViewItem}">
     <Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
    </Style>
  </ListView.Resources>
  <!-- ... -->
</ListView>

您可以看到添加的菜单项(在上方,从所有位置删除)将其 ItemsSource 设置为 SelectedFolder.PlayableElements ContextMenu 现在将其 DataContext 设置为 Window 实例通过代理。因此,所有在其范围内使用的绑定都没有显式的 Source RelativeSource ElementName set将获得DataContext的解析源(您的窗口)。

As you can see the added menu item (right above the Remove from all) has its ItemsSource set to SelectedFolder.PlayableElements. The ContextMenu now has its DataContext set to the Window instance via proxy. So all the Bindings used inside its scope without explicit Source and RelativeSource and ElementName set will get a resolved source of the DataContext (your window).

这篇关于将集合绑定到ContextMenu子菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆