MVVM binding command to contextmenu item

前端 未结 4 934
执念已碎
执念已碎 2020-12-03 03:45

I\'m trying to bind a command to a menuitem in WPF. I\'m using the same method that\'s been working for all my other command bindings, but I can\'t figure out why it doesn\'

相关标签:
4条回答
  • 2020-12-03 03:52

    koshdim is spot on, it works like a charm!! Thanks Koshdim

    I modified his code to fit in my context menu

        <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>
    
    0 讨论(0)
  • 2020-12-03 04:07

    That's a tricky issue, sure marginally you will find a quick workaround, but here is a no-magic-solution:

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

    It boils down to using the Tag of the PlacementTarget (the Button here).

    0 讨论(0)
  • 2020-12-03 04:16

    (Edit) Since you mentioned this is in an ItemsControl's template, things are different:

    1) Get the BindingProxy class from this blog (and read the blog, as this is interesting information): How to bind to data when the DataContext is not inherited.

    Basically the elements in the ItemsControl (or ContextMenu) are not part of the visual or logical tree, and therefore cannot find the DataContext of your UserControl. My apologies for not writing more on this here, but the author has done a good job explaining it step by step, so there's no way I could give a complete explanation in just a few lines.

    2) Do something like this: (you may have to adapt it a bit to make it work in your control):

    a. This will give you access to the UserControl DataContext using a StaticResource:

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

    b. This uses the DataContextProxy defined in (a):

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

    This has worked for us in things like trees and datagrids.

    0 讨论(0)
  • 2020-12-03 04:18

    ContextMenu is in different logical tree, that's why RelativeSource doesnt work. But context menu inherit DataContext from its "container", in this case it is Button. It is enough in common case but in your case you need two "data contexts", of ItemsControl item and of ItemsControl itself. I think you have no other choice but combine your view models into one, implement custom class to be used as ItemsControl item data context and contain both "Name" and "Remove command" or your item's view model can define RemoveCommand "proxy", that would call parent command internally

    EDIT: I slightly changed Baboon's code, it must work this way:

    <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>
    
    0 讨论(0)
提交回复
热议问题