2

I am using Entity Framework 6 in an MVVM Light WPF app. I'd like to pass the app's DbContext to the view model of a user control from the MainWindow.xaml.

The user control's view model is SearchEmployeeViewModel.cs and has the following constructor:

public SearchEmployeeViewModel(MyEntities context)
{
    Context = context; 

    // Other code...
}       

The MainWindow.xaml declares the user control using this, and that's as far as I could go in my attempt:

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

            </data:MyEntities>
        </ObjectDataProvider.ConstructorParameters>
    </ObjectDataProvider>
</usercontrol:SearchEmployeeControl>

The app's DbContext is instantiated in the MainViewModel.cs constructor this way:

_context = new MyEntities();

How do I pass this EF DbContext into SearchEmployeeViewModel.cs constructor via the MainWindow.xaml? I'm trying to do something similar to this, but passing the entire data context object: Where to create parametrized ViewModel?

Update: I'm trying to pass the EF DbContext to the user control.

Community
  • 1
  • 1
Alex
  • 34,699
  • 13
  • 75
  • 158
  • 1
    I think the property injection answer of that question would apply well to your question unless your other code in your constructor uses the initialized context – Gordon Allocman Mar 31 '16 at 13:18
  • Thanks, @GordonAllocman. I didn't even notice that answer! – Alex Mar 31 '16 at 13:20
  • What would the syntax be for that, @GordonAllocman? In MainWindow.xaml, I have this inside of the user control declaration: ``. It won't let me bind the `Context` property to anything. So how do I pass the data object into that? – Alex Mar 31 '16 at 13:33
  • 1
    Personally I don't think Views should ever be responsible for creating anything... they are only supposed to be a user-friendly reflection of your ViewModels and Models, and are not responsible for anything beyond accepting user input. That said, you might be able to accomplish what you're asking by using the XAML version of the code... something like `` – Rachel Mar 31 '16 at 13:44

2 Answers2

7

You tagged with this MVVM, so this answer is going to be based on using MVVM.

The View should not ever create objects or try to assign values... it is only meant to be a user-friendly reflection of the ViewModel/Models that users can use to interact with.

What you have now appears to be :

  • AppStartup creates EF dbContext, and assign it to View.DataContext
  • View creates ViewModel, and tries to pass it the EF dbContext

This is incorrect, because the View should not be responsible for creating objects or assigning values like this.

What you want for MVVM is

  • AppStartup
    • Creates ViewModel and EF dbContext
    • Sets dbContext to ViewModel
    • Creates View, and assigns ViewModel to View.DataContext
  • View displays ViewModel to user and allows them to interact with it

So what you should have is something like this :

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 is responsible for any kind of application initialization, such as creating the EF DataContext or ViewModels.

From the View, you could write something like

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

and this will tell WPF

Anytime you encounter an object of type SearchEmployeeViewModel in the VisualTree, draw it using SearchEmployeeControl, and set the DataContext of that control to SearchEmployeeViewModel.

Typically ViewModels are inserted into the UI via the Content or ItemsSource property, like this :

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

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

I also have a Simple MVVM Example on my blog if you're interested in learning more, or I'd highly recommend reading What is this "DataContext" you speak of? if you are very new to WPF and still don't have a firm understanding of what the DataContext is or how it works.


That said, if you wanted to have your View assign the value of the ViewModel as you have in your question, your options are either

  • Assign the property via Code Behind the View
  • Change ViewModel.Context to a DependencyProperty, and bind it using OneWayToSource binding mode, meaning the binding will only work by transferring values from the View to the ViewModel.

I do not recommend either of these and would rather redesign to do this properly in MVVM, however if I were forced to pick one I would choose to use code behind. You're already breaking a bunch of rules at this point, so why not one more :)

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Thanks, @Rachel. Do you mind chatting in the WPF room? https://chat.stackoverflow.com/rooms/18165/wpf – Alex Mar 31 '16 at 14:35
  • 2
    @Alex I'd love to, but that is blocked from my office so it would have to be another day. Feel free to ping me tomorrow if you have any questions, or just post them in comments :) – Rachel Mar 31 '16 at 14:43
  • 2
    @Rachel Sounds like you need a new office. – Lynn Crumbling Mar 31 '16 at 14:45
0

You want something like this:

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

Important things to note, AncestorType={x:Type Window} should be whatever your view is (i.e. Window, Page, etc..).

Also your declaration of your viewmodel has to be in a single tag. If you have an opening and closing tag I think you need to use a Setter but I didn't test that

Gordon Allocman
  • 768
  • 7
  • 23
  • In this case, `Context` is referring to the `SearchEmployeeViewModel.Context` property, which is not a dependency property and so does not accept databinding, and this will not work. I believe the OP is looking to initialize that property via the XAML, which is not generally recommended when using WPF/MVVM – Rachel Mar 31 '16 at 13:47
  • While I agree this probably isn't good mvvm practice, we can't tell whether Context is a property or not from only the code he gave us. I tried this with a viewmodel in some of my own code and I was able to set properties like this. My answer does exactly what OP asked which is to send the DataContext into the viewmodel – Gordon Allocman Mar 31 '16 at 13:53
  • I'm trying to pass the EF DbContext to the child user control. Please see my update above. Thanks. – Alex Mar 31 '16 at 14:01