开发者

Data Binding a Collection Dependency Property to a menu in a User Control

开发者 https://www.devze.com 2023-03-23 10:49 出处:网络
I have a user control with its own context menu, however I need to add additional items to that menu.

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>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号