C# 将集合绑定到ContextMenu子菜单
我在做一些看起来很容易但实际上并不容易的事情时遇到了困难 我有一个ListView,其中绑定了一个ObservableCollection,我希望在右键单击该ListView的元素时显示一个ContextMenu 在这个上下文菜单中,我想要一个菜单项,上面写着“添加到播放列表”,里面是我所有播放列表的列表 所以我做了这个,在我看来是对的:C# 将集合绑定到ContextMenu子菜单,c#,wpf,data-binding,C#,Wpf,Data Binding,我在做一些看起来很容易但实际上并不容易的事情时遇到了困难 我有一个ListView,其中绑定了一个ObservableCollection,我希望在右键单击该ListView的元素时显示一个ContextMenu 在这个上下文菜单中,我想要一个菜单项,上面写着“添加到播放列表”,里面是我所有播放列表的列表 所以我做了这个,在我看来是对的: <ListView Grid.Row="0" Grid.Column="1" x:Name="ListBoxSelectedFolder" ItemsS
<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和Playlists都有name属性
因此,这两个绑定之间存在某种冲突,我不知道如何解决它
提前感谢您的回复。使用您显示的代码,您刚刚将另一个菜单项绑定到name属性。我猜您正在寻找的是MenuItem的ItemTemplate属性。通过这种方式,您可以定义应该为此菜单项的每个子项显示哪些数据。 检查以下标记:
<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.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Path=Name}" />
</DataTemplate>
</MenuItem.ItemTemplate>
<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>
将
上下文菜单
与可视树分离,因此无法以正常方式在其作用域内与元素名称
或相对资源
绑定。您需要一些代理技术来桥接切割。这里我们有Freezable
元素,它可以继承数据上下文,并允许绑定在可视树上漫游,即使在这种情况下也很容易。为了方便起见,我们应该使用离散对象关键帧,因为它的值可以接受所有类型的对象。如果您关心名称,那么您可以定义自己的自定义Freezable对象
<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>
编辑-这有助于您了解如何混合播放列表和选定文件夹中的信息:
<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>
如您所见,添加的菜单项(位于
全部删除
的正上方)将其项资源设置为SelectedFolder.playableements
。ContextMenu
现在通过proxy
将其DataContext
设置为窗口
实例。因此,在其范围内使用的所有绑定,如果没有显式的Source
和RelativeSource
和ElementName
集,都将获得DataContext(您的窗口)的解析源。
-这意味着您可以设置项源
并将项添加到父菜单项的项
,它应该在运行时引发一些异常。它不会引发异常以供您查看,因为绑定
以静默方式失败ContextMenu
与可视树分离,因此您需要以某种方式显式设置绑定源。@KingKing我该怎么做?不清楚您的播放列表
来自何处?例如从列表视图的DataContext或某个显式子viewmodel?@KingKing实际上它是我的主窗口类的一个属性绑定路径和简单绑定有什么区别?我不熟悉.NET的特性:(嗯,稍后会检查它。绑定和绑定路径之间没有区别。我只是觉得用“路径”更具描述性它是有效的!我不明白为什么它一开始就不起作用,为什么它听起来如此逻辑,却又如此复杂?无论如何,谢谢。你有一些资源来了解更多关于wpf、c#和.net的信息吗?我真的很困惑。另外,如果我想混合SelectedFolder.PlayableElements
和播放列表中的属性呢
在我的菜单项中
?@Devz是的,我认为它不应该如此复杂,WPF本身存在一些许多人根本不喜欢的问题(事实上,它可以完全改进,但不知何故它们没有)。我在这里写的是从使用ContextMenu(和其他一些)的经验中获得的因此,你当然应该有更多的经验来了解WPF。我建议你阅读WPF Unreleased-这是一本对初学者来说很有价值的书,只是浏览一下它的示例和指南。当然,这还不够,所以需要时间来体验更多,WPF有一个陡峭的学习曲线。对于你的附加问题,我真的不明白你想要什么要混合它们,可以使用一些示例。例如,我想在我的子菜单中使用的示例,除了播放列表中的元素
,我还需要SelectedFolder中的元素。SomeObservableCollection
。我应该怎么做?