Data Binding a Collection Dependency Property to a menu in a User Control
I have a user control with its own context menu, however I need to add additional items to that menu.
The approach I took was to have a dependency property called ContextMenuItems:
Public Shared ReadOnly ContextMenuItemsProperty As DependencyProperty = DependencyProperty.Register("ContextMenuItems", GetType(ObservableCollection(Of MenuItem)), GetType(SmartDataControl), New FrameworkPropertyMetadata(New ObservableCollection(Of MenuItem)))
Public Property ContextMenuItems As ObservableCollection(Of MenuItem)
Get
Return GetValue(ContextMenuItemsProperty)
End Get
Set(ByVal value As ObservableCollection(Of MenuItem))
SetValue(ContextMenuItemsProperty, value)
End Set
End Property
I then used a CompositeCollection to combine the static menu items from the control with the list provided by the host:
<CompositeCollection x:Key="MenuItemsCompositeCollection">
<MenuItem Header="TEST" />
<CollectionContainer Collection="{Binding RelativeSource={Relativ开发者_StackOverflow中文版eSource AncestorType=UserControl}, Path=ContextMenuItems, Converter={StaticResource TestConverter}}" />
<MenuItem Header="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ContextMenuItems}" />
</CompositeCollection>
What I see when I bind to that resource is:
- TEST
- (Collection)
The second menu item is bound to the collection to prove I can get to it. I have a test converter that I have added to menu item and it breaks in the converter method, but when I add the converter to the CollectionContainer it doesn't get called.
Finally, I get the following error in the output window:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''. BindingExpression:Path=ContextMenuItems; DataItem=null; target element is 'CollectionContainer' (HashCode=41005040); target property is 'Collection' (type 'IEnumerable')
That "proof" of yours does not work because the two objects compared are obviously not equal. You cannot use RelativeSource
or ElementName
bindings in a collection container because the necessary conditions are not met, i.e. there is no NameScope
and since the CollectionContainer is an abtract object which does not appear in the visual tree there also is not parent via which the ancestor could be found.
If you have access to the UserControl you can however use the Binding.Source
and a x:Reference
to the UserControl's name, to prevent a cyclical dependecy error the CompositeCollection
should be defined in the UserControl.Resources
and then referenced using StaticResource
.
e.g.
<UserControl Name="control">
<UserControl.Resources>
<CompositeCollection x:Key="collection">
<!-- ... -->
<CollectionContainer Collection="{Binding ContextMenuItems, Source={x:Reference control}, Converter=...}"/>
</CompositeCollection>
</UserControl.Resources>
<!-- ... -->
<MenuItem ItemsSource="{Binding Source={StaticResource collection}}"/>
</UserControl>
精彩评论