在ContextMenu中访问ViewModel/DataContext

6

如何获取ContextMenu内部UserControl的原始DataContext。

下面的代码中,您可以看到DataTemplate中有一个Button,它正确地绑定了。然而,在尝试绑定上下文菜单的数据源时,我收到以下错误:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TreeView', AncestorLevel='1''. BindingExpression:Path=DataContext; DataItem=null; target element is 'ContextMenu' (Name=''); target property is 'DataContext' (type 'Object')

我需要做什么才能允许ContextMenu绑定到ViewModel?

===============================================================================

ViewModel在codebehind中分配给视图的datacontext:

视图:

<TreeView ItemsSource="{Binding Clients}"
          cmd:TreeViewSelect.Command="{Binding SelectionChangedCommand}"
          cmd:TreeViewSelect.CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=SelectedItem}">
    <TreeView.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Name}">
                    <TextBlock.ContextMenu>
                        <ContextMenu DataContext="{Binding DataContext, 
                            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}">
                            <MenuItem Header="{Binding TestString}" />
                        </ContextMenu>
                    </TextBlock.ContextMenu>
                </TextBlock>

                <Button  DataContext="{Binding DataContext, 
                            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}"
                         Content="{Binding TestString}" Command="{Binding EditSelectedClientCommand}" />
             </StackPanel>
        </DataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

ViewModel:

public class ClientListViewModel : ViewModelBase
{
    public String TestString { 
        get {
            return "TESTING";  
        }
    }

    private ClientList _clients = null;
    private readonly IClientService _clientService = null;
    private readonly IEventAggregator _eventAggregator = null;
    private Client _selectedClient = null;
    private ICommand _selectionChangedCommand = null;
    private ICommand _editSelectedClientCommand = null;
    ....
}
1个回答

10

ContextMenus无法出现在可视树中,这导致了RelativeSource绑定的失败,但你仍然可以通过某种方式获取DataContext。例如,你可以尝试以下方法:

<TextBlock Text="{Binding Name}"
           Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=TreeView}}">
    <TextBlock.ContextMenu>
        <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
            <MenuItem Header="{Binding TestString}" />
            <!-- ... --->

PlacementTarget 是 TextBlock,DataContext 通过 Tag 进行传递。这是一种实现方式(至少我希望它有效),我还看到过一些使用不同方式来桥接这个差距的库,但我不记得它们的来源了...


这个很好用!谢谢你!你提到了其他可能填补这个空缺的库,Prism是其中之一吗? - Michael G
很高兴能帮到你 :) 我不知道Prism是否支持这个,我又重新找了一下,这个是我之前遇到的其中一个库,但我不知道它是否适用于这种情况,因为我认为我从未真正使用过它。然而,我以前尝试过另一件事情,叫做DataContextSpy,但是对我来说没有什么用处,也许我使用方法不对... - H.B.
Tag 属性就是我所缺少的!谢谢! - Jarek Mitek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接