2

I have a simple WPF application as below:

enter image description here

I also created 3 different views:

  • DetailType1.xaml
  • DetailType2.xaml
  • DetailType3.xaml

and each view has it's own ViewModel

ParentView.xaml

...
<!-- Detail Area -->
<GroupBox x:Name="groupDetails" Grid.Column="0" Header="Details"
                      HorizontalAlignment="Stretch"
                      Grid.Row="0" VerticalAlignment="Stretch">
   <GroupBox.Resources>
        <ResourceDictionary>
             <DataTemplate DataType="{x:Type vm:DetailType1ViewModel}">
                  <views:DetailType1View/>
             </DataTemplate>
             <DataTemplate DataType="{x:Type vm:DetailType2ViewModel}">
                  <views:DetailType2View/>
             </DataTemplate>
        </ResourceDictionary>
   </GroupBox.Resources>
   <ContentPresenter DataContext="{Binding}" Content="{Binding Path=BaseTypeViewModel}" />
</GroupBox>
...

ParentViewModel.cs

...
public BaseViewModel BaseTypeViewModel
{
    get { return GetValue<BaseViewModel>(); }
    set
    {
        SetValue(value);
    }
}

private void ShowDetailDialog()
{
    var vm = GetViewModelByID(SelectedID);
    BaseTypeViewModel = vm;
}

private BaseViewModel GetViewModelByID(int Id)
{
    switch (Id)
    {
        case 1:
            return IoC.Get<DetailType1ViewModel>();
        case 2:
            return IoC.Get<DetailType2ViewModel>();
    }
}
...

DetailType1ViewModel.cs

public class DetailType1ViewModel : BaseViewModel
{
    ...
}

My question is:

Everytime I double-click row of DataGrid on the left pane, I want to load one of above views into Details area depend on the selected ID. So what are the techniques can be used? It would be nice if you can show me a code sample.

Thanks to all for the help.

Quan Nguyen
  • 562
  • 1
  • 5
  • 20

1 Answers1

3
  1. Create a <DataTemplate> within a <ResourceDictionary> for each ViewModel that you want to display in the detail area (with the correct DataType={x:Type local:DetailTypeViewModelX}).
  2. Ensure that this <ResourceDictionary> is merged into an ancestor of the details area. A possible place would be <Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="..." />.
  3. Bind the DataContext of the details area to the instance of the ViewModel you want to display.
  4. Create a <ContentPresenter Content="{Binding}" /> in the details area where you want to display the contents of the <DataTemplate> from step 1.

This should work and follow the overall concept of MVVM.

haindl
  • 3,111
  • 2
  • 25
  • 31
  • At step 3, you mean I have to declare a DataContext property in each detail view? – Quan Nguyen Oct 12 '16 at 12:13
  • 1
    @QuanNguyen No. You have **one** detail area where you want to display the details of a `ViewModel`. Therein you have only **one** `` which has his `DataContext` bound to the **one** `ViewModel` instance you want to display. Then you have **three** ``s of your three `ViewModels` within a ``. This `` have set their `DataType` to the type of the `ViewModel` without a x:key. The contents of this **three** `` are your **three** `Views`. Within each `View` you then just bind to the properties of the `ViewModel`. – haindl Oct 12 '16 at 12:32
  • 1
    The proper `` type will get applied automatically by WPF. (See [here](https://msdn.microsoft.com/en-us/library/system.windows.datatemplate.datatype(v=vs.110).aspx) if you've never used that technique before.) – haindl Oct 12 '16 at 12:35
  • Thanks so much! Now I can make it work by your instructions, but I have to create one more ViewModel and let the VMs of those child views inherit it, so everytime the selected Id changed, I return an appropriate VM for rendering view. Do you have any idea? – Quan Nguyen Oct 13 '16 at 10:07
  • @QuanNguyen Glad I could help you! Regarding your question: It's absolutely okay if you have some kind of `BaseViewModel` from which the child VMs inherit. It's also perfectly fine to create a new instance of this child VM for the detail view every time the selected Id changed. Is this the information you've asked for? If not then please explain a bit more in detail to which subject area you need an idea. – haindl Oct 13 '16 at 10:32
  • As you mentioned ebove, the `DataContext` property is bound to the instance of a specific VM (e.g: `DetailType1ViewModel`) and not a base VM. So if I don't create a base VM, I can only display the content of DetailType1 regardless of the selected Id changed. Is it right? – Quan Nguyen Oct 13 '16 at 11:04
  • @QuanNguyen Ah, I just noticed that you've edited your question. I've checked the code you inserted and it looks perfectly fine for me. I think you can remove the `DataContext="{Binding}"` on the `ContentPresenter` without any side effects because the actual DataContext is inherited automatically. But aside from that, in my opinion you are absolutely good to go! And regarding your question: Yes, that's correct. It's crucial in your concrete case that you have a property `BaseTypeViewModel` of type `BaseViewModel` in the `ParentViewModel`. – haindl Oct 13 '16 at 11:53