WPF绑定CompositeCollection中的MenuItem不起作用

时间:2012-07-24 07:31:16

标签: wpf xaml binding compositecollection

我在复合集合中将命令绑定到menuitem时遇到问题。 MenuItemContextMenu的一部分,UserControl.Resources中定义了<UserControl.Resources> <ContextMenu x:Key="DataGridRowContextMenu"> <MenuItem Header=" Set label"/> <MenuItem.ItemsSource> <CompositeCollection> <CollectionContainer Collection="{Binding Source={StaticResource labelsSelectSource}}" /> <MenuItem Header=" New label..." Command="{Binding DataContext.NewLabel, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"/> </CompositeCollection> </MenuItem.ItemsSource> </MenuItem> <UserControl.Resources/>

问题是新标签的绑定无效。当我将MenuItem放在复合集合之外时,它将起作用。有什么想法吗?

{{1}}

3 个答案:

答案 0 :(得分:1)

这是因为ContextMenu与其包含父项不在同一visual tree这一事实,导致数据绑定问题。由于ContextMenu不在同一个可视树中,ElementNameRelativeSouceFindAncestor)等等绑定不起作用。

你可以通过

解决这个问题
  1. 在UserControl背后的代码中:

    NameScope.SetNameScope(DataGridRowContextMenu, NameScope.GetNameScope(this)); 
    
  2. 使用PlacementTarget这样的属性 -

    <ContextMenu 
        x:Key="DataGridRowContextMenu">   
        DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
        .
        .  
        .
        <MenuItem 
            Header=" New label..."     
            Command="{Binding DataContext.NewLabel}"/> 
    
  3. 或使用其他解决方案 -

    ElementName Binding from MenuItem in ContextMenu

    WPF: DataContext for ContextMenu

答案 1 :(得分:1)

我一直在努力解决这个疯狂的ContextMenu及其MenuItems很长一段时间。但我发现了一个解决方案,可以使用名为“Data”的dependancyproperty创建自定义行为“BindingProxyBehaviour”。此属性包含一个对象,例如您的DataContext(如果您使用MVVM模式,则可能是您的ViewModel)。

public class BindingProxyDataBehavior : Freezable
{
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxyDataBehavior), new UIPropertyMetadata(null));

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxyDataBehavior();
    }

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }
}

只需在您的xaml文件中添加BindingProxy作为资源。

<UserControl.Resources>
    <ResourceDictionary>
        <behaviors:BindingProxyDataBehavior x:Key="BindingProxyViewModel" Data="{Binding}"/>
        <behaviors:BindingProxyDataBehavior x:Key="BindingProxyViewModelDynamicDataList" Data="{Binding DynamicDataListObject}"/>
    </ResourceDictionary>
</UserControl.Resources>

在我的情况下,我使用CompositeCollection来混合静态和动态MenuItems。因此第二个资源具有键“BindingProxyViewModelDynamicDataList”。

Voilà现在无论您的ContextMenu在哪里,您都可以轻松访问您的数据。 我的ContexMenu在xaml树中的位置是UserControl-&gt; Grid-&gt; DataGrid-&gt; DataGridTemplateColumn-&gt; CellTemplate-&gt; DataTemplate-&gt; TextBox.Template-&gt; Grid-&gt; TextBlock-&gt;控件:IconButton(简单customButton控件派生自button),这里我们在IconButton中:

<controls:IconButton.ContextMenu>
<ContextMenu x:Name="AnyContextMenuName">
    <ContextMenu.Resources>
        <HierarchicalDataTemplate DataType="{x:Type DynamicDataListItemType}">
            <TextBlock Text="{Binding DynamicDataListItemProperty}"/>
        </HierarchicalDataTemplate>
    </ContextMenu.Resources>
    <ContextMenu.ItemsSource>
        <CompositeCollection>
            <CollectionContainer Collection="{Binding Source={StaticResource BindingProxyViewModelDynamicDataList}, Path=Data}"/>
            <Separator/>
            <MenuItem Header="Your static header" Command="{Binding Source={StaticResource BindingProxyViewModel}, Path=Data.ViewModelCommandForYourStaticMenuItem}"/>
        </CompositeCollection>
    </ContextMenu.ItemsSource>
    <ContextMenu.ItemContainerStyle>
        <Style>
            <Setter Property="MenuItem.Foreground" Value="{DynamicResource DefaultForegroundBrush}"/>
            <Setter Property="MenuItem.Command" Value="{Binding Source={StaticResource BindingProxyViewModel}, Path=Data.ViewModelCommandForDynamicMenuItems}"/>
            <Setter Property="MenuItem.CommandParameter" Value="{Binding}"/>
        </Style>
    </ContextMenu.ItemContainerStyle>
</ContextMenu>
</controls:IconButton.ContextMenu>

我希望我能用这篇简短的文章来帮助你做个傻瓜。

答案 2 :(得分:0)

使用CommandTarget属性或创建datacontext的staticRessource,如

<MenuItem Header=" New label..." 
          Command="{Binding Path=NewLabel,Source={StaticResource viewModel}}"/>