MVVM绑定命令到contextmenu项

时间:2012-04-03 13:25:34

标签: wpf mvvm

我正在尝试将命令绑定到WPF中的menuitem。我正在使用与我所有其他命令绑定相同的方法,但我无法弄清楚为什么它在这里不起作用。

我目前正在绑定我的命令:

Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.MyCommand}"

这是它出错的地方(这是在UserControl中)

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
                        Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">

     <Button.ContextMenu>
         <ContextMenu>
             <MenuItem Header="Remove" CommandParameter="{Binding Name}"
                                      Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.RemoveCommand}"/>
         </ContextMenu>
     </Button.ContextMenu>
     ...

第一个命令绑定的工作原理应该如此,但第二个命令绑定拒绝执行任何操作。 我已经尝试更改祖先级别并命名我的控件通过ElementName而不是RelativeSource访问它,但仍然没有变化。它一直说“找不到参考资料的来源......”

我错过了什么?

4 个答案:

答案 0 :(得分:26)

(编辑)由于你提到这是在ItemsControl的模板中,所以情况有所不同:

1)从这个博客获取BindingProxy类(并阅读博客,因为这是有趣的信息):How to bind to data when the DataContext is not inherited

ItemsControl(或ContextMenu)中的元素基本上不是可视树或逻辑树的一部分,因此无法找到UserControl的DataContext。我很抱歉没有在这里写更多内容,但作者已经做好了一步一步的解释,所以我无法用几行完整解释。

2)做这样的事情:(你可能需要调整一下以使其在你的控制下工作):

一个。这将使您可以使用StaticResource:

访问UserControl DataContext
<UserControl.Resources>
<BindingProxy
  x:Key="DataContextProxy"
  Data="{Binding}" />
</UserControl.Resources>

湾这使用了(a)中定义的DataContextProxy:

<Button.ContextMenu>
 <ContextMenu>
     <MenuItem Header="Remove" CommandParameter="{Binding Name}"
         Command="{Binding Path=Data.RemoveCommand, Source={StaticResource DataContextProxy}}"/>
 </ContextMenu>

这对我们来说很有用,比如树和数据网格。

答案 1 :(得分:11)

ContextMenu位于不同的逻辑树中,这就是RelativeSource不起作用的原因。但是上下文菜单从其“容器”继承DataContext,在这种情况下它是Button。在通常情况下这是足够的,但在您的情况下,您需要两个“数据上下文”,ItemsControl项和ItemsControl本身。 我认为您别无选择,只能将您的视图模型合并为一个,实现自定义类以用作ItemsControl项数据上下文并包含“Name”和“Remove command”,或者您的项目视图模型可以定义RemoveCommand“proxy”,即会在内部调用父命令

编辑: 我略微改变了狒狒的代码,它必须以这种方式工作:

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
    Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
    Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">
            <Button.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Remove" 
                   CommandParameter="{Binding Name}"
                   Command="{Binding Path=PlacementTarget.Tag.DataContext.RemoveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
                </ContextMenu>
            </Button.ContextMenu>

答案 2 :(得分:5)

koshdim就是现场,它就像一个魅力!谢谢Koshdim

我修改了他的代码以适应我的上下文菜单

    <DataGrid 
        AutoGenerateColumns="False" 
        HeadersVisibility="Column"
        Name="dgLosses"
        SelectedItem="{Binding SelectedItem, Mode= TwoWay}"
        AllowDrop="True"
        ItemsSource="{Binding Losses}"
        Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}">


        <DataGrid.ContextMenu >
            <ContextMenu >
                <MenuItem Header="Move to Top     "   Command="{Binding PlacementTarget.Tag.MoveToTopCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
                <MenuItem Header="Move to Period 1"   Command="{Binding PlacementTarget.Tag.MoveToPeriod1Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
                <MenuItem Header="Move to Period 2"   Command="{Binding PlacementTarget.Tag.MoveToPeriod2Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
                <MenuItem Header="Move to Period 3"   Command="{Binding PlacementTarget.Tag.MoveToPeriod3Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>                    
            </ContextMenu>
        </DataGrid.ContextMenu>

答案 3 :(得分:3)

这是一个棘手的问题,你肯定会找到一个快速的解决方法,但这是一个无魔法解决方案:

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
        Tag={Binding}
        Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">    
     <Button.ContextMenu>
         <ContextMenu>
             <MenuItem Header="Remove" 
                       CommandParameter="{Binding Path=PlacementTarget.Tag.Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
                       Command="{Binding Path=PlacementTarget.Tag.RemoveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
         </ContextMenu>
     </Button.ContextMenu>
...

归结为使用Tag的{​​{1}}(此处为PlacementTarget)。