上下文菜单项命令使用MVVM绑定WPF

时间:2010-10-01 08:26:15

标签: wpf data-binding mvvm command contextmenu

我知道在许多网站和StackOverFlow中已经多次以不同的方式询问过这个问题,但我发现的所有答案并没有帮助我确切地说我无法理解它们并在我的应用程序中实现。所以我想从我的应用程序中添加一些代码,以便人们可以更好地帮助我。

问题陈述:我正在使用WPF DataGrid。我添加了上下文菜单,我有3个选项剪切,复制,粘贴。我正在使用MVVM进行开发。我想在ViewModel中将这些选项DataBind到命令。但我无法做同样的事情。上下文菜单选项根本没有获取数据!

这是我在XAML中的网格代码:

<custom:DataGrid  
      x:Name="DataGrid_Standard"   
      Grid.Row="1" Grid.Column="1"   
      AutoGenerateColumns="False"                                                           
      IsSynchronizedWithCurrentItem="True"   
      Background="Transparent"
      ItemsSource="{Binding FullGridData}" 
      ItemContainerStyle="{StaticResource defaultRowStyle}"
      ColumnHeaderStyle="{StaticResource DefaultColumnHeaderStyle}"                         
      Grid.ColumnSpan="2">

然后我有一个ContextMenu和一个样式标题元素

<ContextMenu x:Key="columnHeaderMenu">
   <MenuItem Command="{Binding CutCommand}"
             Header="Test" />
   <MenuItem Header="Copy"/>
   <MenuItem Header="Paste"/>
</ContextMenu>
<Style TargetType="{x:Type custom:DataGridColumnHeader}" x:Key="DefaultColumnHeaderStyle">
    <Setter Property="ContextMenu" Value="{DynamicResource columnHeaderMenu}" >
</Style>

这一行在我的构造函数

public Window1()
{            
   this.DataContext = new AppData();
}

此代码位于我的AppData类中:

public class AppData  
{ 
    private IList<GridData> fullGridData = new ObservableCollection<GridData>();<br> 
    public IList<GridData> FullGridData
    {
        get { return fullGridData; }
        set { fullGridData = value; }
    }

    private DelegateCommand<object> cutCommand;
    public DelegateCommand<object> CutCommand
    {
        get
        {
            if (cutCommand == null)
            {
                cutCommand = new DelegateCommand<object>(CutColumn);
            }
            return cutCommand;
        }
    }

    private void CutColumn(object obj)
    {
        //some code goes here
    }   
}

**我想确切地知道我在哪里做错了?为什么DataBinding没有发生? 请帮我解决这个问题。请提供我现有代码中的示例代码或修改,以便我实现它。 **

5 个答案:

答案 0 :(得分:1)

我有同样的问题。一旦我从后面的代码移动到ViewModel,命令绑定就停止了工作。在viewmodel中,我不得不将ICommand从RoutedCommand更改为DelegateCommand。我能够通过以下方式使其工作 -

将Opened eventhandler添加到上下文菜单 -

<ContextMenu x:Key="columnHeaderMenu" Opened="ContextMenu_Opened">
    <MenuItem Command="{Binding CutCommand}" Header="Test" />
    <MenuItem Header="Copy"/>
    <MenuItem Header="Paste"/>
</ContextMenu>

在后面的代码中,您将ViewModel分配给上下文菜单的DataContext -

private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
    ContextMenu menu = sender as ContextMenu;
    menu.DataContext = _vm;
}

答案 1 :(得分:1)

我通常在视图中将我的视图模型实例化为静态资源:

<UserControl x:Class="My.Namespace.MySampleView" ...> 
    <UserControl.Resources> 
        <viewModels:MySampleViewModel x:Key="ViewModel" /> 
    </UserControl.Resources> 

然后,即使当前绑定上下文不是视图模型,您也可以轻松引用视图模型的任何属性:

<ContextMenu x:Key="columnHeaderMenu">
    <MenuItem Command="{Binding MyCommand, Source={StaticResource ViewModel}}" />
</ContextMenu>

有关详细信息,请查看我的文章Recommendations and best practices for implementing MVVM and XAML/.NET applications

答案 2 :(得分:1)

代码中的某些东西(或当时使用的WPF版本(?))过于复杂。我能够绑定诸如

<DataGrid AutoGenerateColumns="True"
        Name="myGrid"
        ItemsSource="{Binding Orders}">
    <DataGrid.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Copy" Command="{Binding CopyItem}" />
            <MenuItem Header="Delete" Command="{Binding DeleteItem}" />
        </ContextMenu>
    </DataGrid.ContextMenu>
</DataGrid>

命令设置如下:

VM.DeleteItem 
     = new OperationCommand((o) => MessageBox.Show("Delete Me"),
                            (o) => (myGrid.SelectedItem as Order)?.InProgress == false );

enter image description here

答案 3 :(得分:0)

<MenuItem Header="Cut" Command="{Binding Path=PlacementTarget.DataContext.CutCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />

答案 4 :(得分:-1)

您有两种选择 注意:我在这里添加的代码示例与您的示例类似但不相同。

在DataGrid定义中移动ContextMenu的定义,如下所示:

<WpfToolkit:DataGrid
   x:Name="DataGrid_Standard"
   IsSynchronizedWithCurrentItem="True"
   Background="Transparent" 
   ItemsSource="{Binding FullGridData}" 
   ColumnHeaderStyle="{StaticResource DefaultColumnHeaderStyle}">
   <WpfToolkit:DataGrid.ContextMenu>
       <ContextMenu>
           <MenuItem Command="{Binding CutCommand}" Header="Test" />
           <MenuItem Header="Copy"/>
           <MenuItem Header="Paste"/>
       </ContextMenu>
   </WpfToolkit:DataGrid.ContextMenu>
</WpfToolkit:DataGrid>

或者更好地将CommandReference添加到您的资源并将MenuItem中的Command设置为StaticResource,如下所示:

<Window.Resources>
    <c:CommandReference x:Key="MyCutCommandReference" Command="{Binding CutCommand}" />

    <ContextMenu x:Key="columnHeaderMenu">
        <MenuItem Command="{StaticResource MyCutCommandReference}" Header="Test" />
        <MenuItem Header="Copy"/>
        <MenuItem Header="Paste"/>
    </ContextMenu>

    <Style TargetType="{x:Type Primitives:DataGridColumnHeader}" x:Key="DefaultColumnHeaderStyle">
        <Setter Property="ContextMenu" Value="{DynamicResource columnHeaderMenu}" />
    </Style>

</Window.Resources>

<WpfToolkit:DataGrid
   x:Name="DataGrid_Standard"
   IsSynchronizedWithCurrentItem="True"
   Background="Transparent" 
   ItemsSource="{Binding FullGridData}" 
   ColumnHeaderStyle="{StaticResource DefaultColumnHeaderStyle}"/>