通过 XAML 将数据库上下文传递给用户控件的 VM



我正在MVVM Light WPF应用程序中使用Entity Framework 6。我想将应用程序的DbContextMainWindow.xaml传递到用户控件的视图模型。

用户控件的视图模型是SearchEmployeeViewModel.cs,并具有以下构造函数:

public SearchEmployeeViewModel(MyEntities context)
{
    Context = context; 
    // Other code...
}       

MainWindow.xaml使用这个声明用户控件,这是我在尝试中所能达到的:

<usercontrol:SearchEmployeeControl>
    <ObjectDataProvider ObjectType="{x:Type data:MyEntities}">
        <ObjectDataProvider.ConstructorParameters>
            <data:MyEntities >
            </data:MyEntities>
        </ObjectDataProvider.ConstructorParameters>
    </ObjectDataProvider>
</usercontrol:SearchEmployeeControl>

应用程序的DbContextMainViewModel.cs构造函数中以这种方式实例化:

_context = new MyEntities();

如何通过MainWindow.xaml将此EF DbContext传递到SearchEmployeeViewModel.cs构造函数?我试图做一些类似的事情,但传递整个数据上下文对象:在哪里创建参数化ViewModel?

更新:我正在尝试将EF DbContext传递给用户控件。

您标记了这个MVVM,所以这个答案将基于使用MVVM。

视图不应创建对象或尝试分配值。。。它只是用户可以用来交互的ViewModel/Models的用户友好反映。

你现在看到的是:

  • AppStartup创建EF dbContext,并将其分配给View.DataContext
  • View创建ViewModel,并尝试将EF dbContext传递给它

这是不正确的,因为视图不应该负责创建对象或分配类似的值。

MVVM需要

  • 应用程序启动
    • 创建ViewModel和EF数据库上下文
    • 将dbContext设置为ViewModel
    • 创建视图,并将ViewModel指定给View.DataContext
  • 视图向用户显示ViewModel,并允许用户与其交互

所以你应该有这样的东西:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    var app = new MainWindow();
    var dbContext = new MyEntities();
    var context = new MyViewModel(dbContext);
    app.DataContext = context;
    app.Show();
}

AppStartup负责任何类型的应用程序初始化,例如创建EF DataContext或ViewModels。

从View,你可以写一些类似的东西

<DataTemplate DataType="{x:Type local:SearchEmployeeViewModel}">
    <userControl:SearchEmployeeControl />
</DataTemplate>

这将告诉WPF

每当在VisualTree中遇到SearchEmployeeViewModel类型的对象时,请使用SearchEmployeeControl绘制该对象,并将该控件的DataContext设置为SearchEmployeeViewModel

通常,ViewModels通过ContentItemsSource属性插入到UI中,如下所示:

<ContentControl Content="{Binding SearchEmployeeViewModel}" />
<TabControl Content="{Binding TabViewModels}" />

如果你有兴趣了解更多,或者我强烈建议你阅读你所说的"DataContext"是什么?如果您是WPF的新手,但仍然不清楚DataContext是什么或它是如何工作的。


也就是说,如果你想让你的视图像你的问题中那样分配ViewModel的值,你的选择是

  • 通过视图后面的代码分配属性
  • ViewModel.Context更改为DependencyProperty,并使用OneWayToSource绑定模式对其进行绑定,这意味着绑定只能通过将值从View传输到ViewModel来工作

我不推荐这两种方法,我更愿意在MVVM中重新设计以正确地做到这一点,但如果我被迫选择一种,我会选择使用代码隐藏。在这一点上,您已经违反了一系列规则,所以为什么不再违反一条呢:)

您想要这样的东西:

<usercontrol:SearchEmployeeControl>
    <usercontrol:SearchEmployeeControl.DataContext>
        <viewModel:SearchEmployeeViewModel>
            <ViewModel:SearchEmployeeViewModel Context={Binding RelativeSource={RelativeSource AncestorType={x:Type Window}} />
        </viewModel:SearchEmployeeViewModel>
    </usercontrol:SearchEmployeeControl.DataContext>
</usercontrol:SearchEmployeeControl>

需要注意的重要事项是,AncestorType={x:Type Window}应该是您的任何视图(即窗口、页面等)

此外,视图模型的声明必须在一个标记中。如果你有一个打开和关闭标签,我认为你需要使用Setter,但我没有测试

最新更新