【问题标题】:Use Window DataContext in child element after overriding DataContext in parent在父元素中覆盖 DataContext 后在子元素中使用 Window DataContext
【发布时间】:2018-11-13 10:55:41
【问题描述】:

我有一个视图模型,其中包含一组对象和一堆命令。

public class MainWindowVM : NotifyPropertyChangedBase
{
    private CollectionViewSource employeeViewSource;

    private ICommand cmdOpenDetailEmployee;

    public MainWindowVM()
    {
        nsDataProviderEmployees = new NSDataProvider();

        employeeViewSource = new CollectionViewSource();

        cmdOpenDetailEmployee = new RelayCommand<object>((parameter) => {...});

        this.LoadData();
    }

    public CollectionViewSource EmployeeViewSource => employeeViewSource;
    public ICommand CmdOpenDetailEmployee => cmdOpenDetailEmployee;
}

在我的应用程序中,我想在显示员工的数据网格的上下文菜单中使用此命令。

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyApp.UI"
        xmlns:DataModel="clr-namespace:MyApp.DataModel;assembly=MyApp.DataModel" x:Class="MyApp.UI.MainWindow"
        xmlns:vm="clr-namespace:MyApp.UI.ViewModels"
        mc:Ignorable="d"
        Title="MyApp - Main" Height="751.826" Width="1111.005" Loaded="Window_Loaded" Icon="Resources/MyApp.ico">
    <Window.DataContext>
        <vm:MainWindowVM />
    </Window.DataContext>
    <Grid x:Name="grdMain">
        <DataGrid DataContext="{Binding Path=EmployeeViewSource}" x:Name="employeeDataGrid" EnableRowVirtualization="True" ItemsSource="{Binding}" Margin="10,77,10,0" RowDetailsVisibilityMode="VisibleWhenSelected">
            <DataGrid.ContextMenu>
                <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">
                    <MenuItem Header="OpenDetail..."
                              Command="{Binding CmdOpenDetailEmployee}"
                              CommandParameter="{Binding}"/>
                </ContextMenu>
            </DataGrid.ContextMenu>
            <DataGrid.Columns>...</DataGrid.Columns>

        </DataGrid>
    </Grid>
</Window>

问题是我无法想出一个绑定组合,既可以让我使用EmployeeViewSource 属性或我的 ViewModel 作为网格的 DataContext,又可以使用我的CmdOpenDetailEmployee 属性ViewModel 作为我的 ContextMenu 和 MenuItems 的 DataContext。

根据我找到的所有帖子,应该可以工作,但是当我单击菜单项时,该命令没有执行。

【问题讨论】:

  • 首先,看看问题到底出在绑定还是命令上。检查是否可以找到绑定错误(另请参阅此处:stackoverflow.com/questions/8850143/…)。如果实际调用了命令的 Execute 方法,还要检查调试器。从这个问题来看,真的不可能告诉更多......
  • 我收回我之前评论的最后一句话。 :-) 想一想,它可能是使用FindAncestor 的绑定。由于上下文菜单是一个弹出窗口,它可能没有主窗口作为祖先(我在这里不是 100% 确定)。绑定很可能只是找到上下文菜单的弹出窗口元素(如果有的话)。尝试使用 ElementName 的绑定来代替(当然,你需要给你的主窗口一个名字),看看会发生什么......
  • @elgonzo 这是来自输出的错误System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:(no path); DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand') 我的命令的执行方法没有被调用。而且我也没有设法与 ElementName 绑定工作:Command="{Binding ElementName=mainWindow, Path=CmdOpenDetailEmployee}"

标签: c# wpf data-binding


【解决方案1】:

绑定到PlacementTargetDataContextContextMenu,让DataGrid从窗口继承其DataContext

<DataGrid x:Name="employeeDataGrid" 
        EnableRowVirtualization="True"
        ItemsSource="{Binding EmployeeViewSource.View}" Margin="10,77,10,0" 
        RowDetailsVisibilityMode="VisibleWhenSelected">
    <DataGrid.ContextMenu>
        <ContextMenu>
            <MenuItem Header="OpenDetail..."
                              Command="{Binding PlacementTarget.DataContext.CmdOpenDetailEmployee, 
                                    RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                              CommandParameter="{Binding}"/>
        </ContextMenu>
    </DataGrid.ContextMenu>
    <!--<DataGrid.Columns>...</DataGrid.Columns>-->
</DataGrid>

【讨论】:

  • 如果我从 DataGrid 中删除 DataContext,那么我将不再显示任何数据...
  • 为什么要在视图模型中定义一个 CollectionViewSource?无论如何,您可以绑定到 EmployeeViewSource.View。查看我的编辑。
  • 我正在尝试迁移到 MVVM 的遗留代码。我自己对此很陌生。什么是更好的方法? --- 无论哪种方式:如果我删除 DataGrid DataContext 并将 ItemsSource 绑定到 View 网格工作,我可以将 MenuItem 直接绑定到命令 {Binding CmdOpenDetailEmployee} 谢谢!
猜你喜欢
  • 1970-01-01
  • 2018-11-14
  • 2011-09-29
  • 2020-08-11
  • 2011-04-20
  • 1970-01-01
  • 1970-01-01
  • 2014-02-02
  • 1970-01-01
相关资源
最近更新 更多