绑定到 List<> 的 WPF 上下文菜单依赖属性
我试图使作为依赖属性的列表的内容显示在 WPF 上下文菜单中。
我有一个具有以下依赖属性的类,即 Foo 的列表(数据保存类):
public List<Foo> FooList
{
get { return (List<Foo>)GetValue(FooListProperty); }
set { SetValue(FooListProperty, value); }
}
public static DependencyProperty FooListProperty =
DependencyProperty.Register("FooList", typeof(List<Foo>),
typeof(FooButton));
在 XAML 中,我设置了以下静态资源,我认为需要它,因为上下文菜单不是可视化树的一部分:
<UserControl.Resources>
<ResourceDictionary>
<CollectionViewSource
x:Key="FooListSource"
Source="{Binding FooList}"/>
<!-- ... -->
</ResourceDictionary>
</UserControl.Resources>
也是 ResourceDictionary 的一部分上面是一个 CompositeCollection,需要它才能使项目显示在实际的上下文菜单中。如果 UserControl CanStop 属性为 true,我们还会显示分隔符和停止命令。尽管菜单项本身会显示,但这些绑定也会失败。因此,如果我能找出这些失败的原因,那么列表可能会更容易。
<CompositeCollection x:Key="FooListItems">
<CollectionContainer
Collection="{Binding Source={StaticResource FooListSource}}"/>
<Separator
Visibility="{Binding CanStop,
Converter={StaticResource VisibleIfTrue}}" />
<MenuItem
Command="{x:Static Buttons:FooButton.Stop}"
Header="Stop"
Visibility="{Binding CanStop,
Converter={StaticResource VisibleIfTrue}}"/>
</CompositeCollection>
最后是上下文菜单本身,也在 ResourceDictionary 中:
<ContextMenu
x:Key="FooButtonMenu"
ItemsSource="{Binding Source={StaticResource FooListItems}}"
ItemTemplate="{StaticResource FooListTemplate}"
<ContextMenu.CommandBindings>
<CommandBinding
Command="{x:Static Buttons:FooButton.Stop}"
Executed="Stop_Executed" />
</ContextMenu.CommandBindings>
</ContextMenu>
我觉得我发布了很多代码,但我不确定我是否可以使这一部分变得更简单。仅显示分隔符和硬编码的菜单项。所以一定是绑定出了什么问题。绑定通常并不难,但现在当我想绑定不属于同一棵树的东西时,我感到有点迷失。
欢迎任何建议。 :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如您所怀疑的,您的问题似乎确实是由使用
List
而不是ObservableCollection
引起的。由于List
不会通知属性更改,因此让 WPF 识别您已添加或删除项目的唯一方法是将 FooList 属性临时设置为其他内容,然后再设置它后退。无需切换到 CLR 属性。只需将
List
更改为ObservableCollection
即可。CompositeCollection
中的绑定不起作用的原因是CompositeCollection
不是 DependencyObject,因此它无法继承DataContext
。As you suspected, your problem does seem to be caused by the use of
List<Foo>
instead ofObservableCollection<Foo>
. SinceList<Foo>
doesn't notify on property changes, the only way to get WPF to recognize you've added or removed an item is to temporarily set the FooList property to something else and then set it back.There is no need to switch to a CLR property. Just change
List<Foo>
toObservableCollection<Foo>
.The reason the bindings in your
CompositeCollection
aren't working is thatCompositeCollection
is not a DependencyObject, so it can't inherit aDataContext
.我不明白为什么您将 FooList 设置为依赖属性。您没有将其作为绑定的目标,这是创建依赖项属性的最常见原因。您尚未实现回调,因此它无法执行更改通知(创建依赖项属性的第二个最常见原因)。您没有将它用于值继承。那么为什么呢?
在我看来,您真正想要的是
FooList
成为ObservableCollection
类型的普通 CLR 属性(或任何实现INotifyCollectionChanged
的类)代码>)。这将完成您需要的所有更改通知 - 至少是您迄今为止发布的代码所需的。I don't see why you've made
FooList
a dependency property. You're not making it the target of a binding, which is the most common reason to create a dependency property. You haven't implemented a callback, so it can't do change notification (the second most common reason to create a dependency property). You're not using it for value inheritance. So why, then?It seems to me that what you really want is for
FooList
to be a normal CLR property of typeObservableCollection<Foo>
(or any class that implementsINotifyCollectionChanged
). That will do all the change notification that you need - at least, that you need for the code you've posted so far.