简体   繁体   English

在WPF MVVM项目中绑定上下文菜单

[英]Binding a context menu in a WPF MVVM project

I am struggling to understand where I'm going wrong with my MVVM WPF project. 我正在努力了解MVVM WPF项目出了哪些问题。 I am trying to create a custom contextmenu command. 我正在尝试创建一个自定义contextmenu命令。 I have a workspace, which is a view, within a HCC in my MainWindow. 我在MainWindow的HCC中有一个工作区,它是一个视图。 The workspace (ProductRecordView) contains a listview populated by an observable collection by the viewmodel (ProductRecordViewModel). 工作区(ProductRecordView)包含一个由viewmodel(ProductRecordViewModel)的可观察集合填充的列表视图。 The data context is set by Option 8 , in the MainWindowResources XAML. 数据上下文由MainWindowResources XAML中的Option 8设置。 So I have created the contextmenu in the PRV as follows: 因此,我在PRV中创建了上下文菜单,如下所示:

<ListView.ContextMenu>
  <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
    <MenuItem Header="Delete" Command="{Binding Path=DeleteRecord}"/>
  </ContextMenu>
</ListView.ContextMenu>

and in the PRVM I have the following things: 在PRVM中,我具有以下内容:

#region Presentation Properties

public ICommand DeleteRecord
{
    get
    {
        if (_deleteMe == null)
        {
            _deleteMe = new RelayCommand(
                param => this.Delete(),
                param => this.CanDelete
                );
        }

        return _deleteMe;
    }
}

#endregion Presentation Properties

#region Public Methods

public void Delete()
{
    MessageBox.Show("Test Execute");//this is just for testing the binding of Delete
}

#endregion Public Methods

#region Private Helpers

bool CanDelete = false; //this is just for testing the binding of CanDelete

#endregion Private Helpers

When I run the application and right click on an item in the list view, I am presented with the context menu as described in the first snippet, however it is not binding as intended as neither of the bound outcomes occur. 当我运行该应用程序并右键单击列表视图中的一个项目时,将显示如第一段中所述的上下文菜单,但是它没有按预期的方式绑定,因为没有绑定结果。 How do I properly bind in this case, what am I doing wrong? 在这种情况下,我该如何正确绑定,我在做什么错?

The DataContext of ProductRecordView is set in MainWindowResources as follows: ProductRecordView的DataContext在MainWindowResources中设置如下:

  <DataTemplate DataType="{x:Type vm:ProductRecordViewModel}">
  <vw:ProductRecordView />
</DataTemplate>

I know that this DataContext is working as intended as if I try to create a button in the view and assign a data binding to it, the binding works perfectly and executes the command in the ProductRecordViewModel 我知道这个DataContext可以按预期工作,就像我尝试在视图中创建一个按钮并为其分配数据绑定一样,该绑定可以完美工作并在ProductRecordViewModel中执行命令

Let's look at the error message more precisely. 让我们更准确地查看错误消息。

BindingExpression path error: 'DeleteRecord' property not found on 'object' ''ListCollectionView' (HashCode=12713695)'. BindingExpression路径错误:在“对象”“ ListCollectionView”(HashCode = 12713695)”上找不到“ DeleteRecord”属性。 BindingExpression:Path=DeleteRecord; BindingExpression:Path = DeleteRecord; DataItem='ListCollectionView' (HashCode=12713695); DataItem ='ListCollectionView'(HashCode = 12713695); target element is 'MenuItem' (Name=''); 目标元素是'MenuItem'(Name =''); target property is 'Command' (type 'ICommand') 目标属性为“命令”(类型为“ ICommand”)

This states, that the data binding system tries to find a DeleteRecord property in the MenuItem 's DataContext which is of type ListCollectionView . 这表明,数据绑定系统试图在MenuItemDataContext中找到类型为ListCollectionViewDeleteRecord属性。

So, considering your expression 所以,考虑你的表情

DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}

it's clear that the PlacementTarget.DataContext is of type ListCollectionView too. 很明显, PlacementTarget.DataContext也属于ListCollectionView类型。 Since PlacementTarget is the ListView itself, it's obvious that the ListView 's DataContext is this ListCollectionView object. 由于PlacementTargetListView本身,因此显然ListViewDataContext就是此ListCollectionView对象。

I suppose, you define your ListView 's DataContext somehow like this: 我想,您可以这样定义ListViewDataContext

<ListView DataContext="{Binding Items}" ItemsSource="{Binding}"/>

The better solution would be to leave the ListView 's DataContext alone so that it "inherits" it's value from your UserControl (thus will be of type ProductRecordViewModel ) while changing the binding for the ItemsSource : 更好的解决方案是将ListViewDataContext保留下来,以便它在更改ItemsSource的绑定时从UserControl “继承”它的值(因此,其类型为ProductRecordViewModel ):

<ListView ItemsSource="{Binding Items}"/>

Why is the ProductRecordView in a datatemplate? 为什么ProductRecordView在数据模板中? I get the suspicion that the list items are PRV which is each bound to a PRVM - is that correct? 我怀疑列表项是PRV,每个PRV都绑定到PRVM-正确吗? Something like this 像这样

<ListView>
    <ListView.ContextMenu>
            <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
                <MenuItem Header="Delete" Command="{Binding Path=DeleteRecord}"/>
            </ContextMenu>
        </ListView.ContextMenu>
    <ListView.ItemTemplate>
        <DataTemplate DataType="{x:Type vm:ProductRecordViewModel}">
            <vw:ProductRecordView /> <!-- each PRV is bound to a PRVM - which as the delete record command -->
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

If that is the case, then the problem is that datacontext of the listviewitems is not the same as the listview itself. 如果真是这样,那么问题是listviewitems的数据上下文与listview本身不同。 Instead you probably want the context menu on the listviewitems directly: 相反,您可能希望直接在listviewitems上使用上下文菜单:

<ListView>        
        <ListView.ItemTemplate>
            <DataTemplate DataType="{x:Type vm:ProductRecordViewModel}">
                <vw:ProductRecordView>
                    <vw:ProductRecordView.ContextMenu>
                        <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
                            <MenuItem Header="Delete" Command="{Binding Path=DeleteRecord}"/>
                        </ContextMenu>
                    <vw:ProductRecordView.ContextMenu>
                </vw:vw:ProductRecordView>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM