Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize nested View (and ViewModel) without using of dependency resolver in WPF/MVVM

Tags:

mvvm

wpf

I am designing a WPF application following MVVM pattern. In one UserControl (and in fact this situation happens many times), since it is quite complex, which includes for example, TabControl, I'd like to divide them into several sub UserControl. For example, in the "main" View, let's call it MainUC, I have a TabControl, which has two TabItem. Since both TabItem actually includes many UI elements, I design two UserControl, SubUCA and SubUCB, so the XAML of MainUC looks like this:

<TabControl Name="mainUC" Grid.Row="0" >   
    <TabItem Header="Sub UC A" Name="SubUC1">
        <local:SubUCA />
    </TabItem>
    <TabItem Header="Sub UC B" Name="SubUC2">
        <local:SubUCB />
    </TabItem>
</TabControl > 

But now my question is: how should I arrange the ViewModel(s) for these UserControl ? One way, which I am currently using, is only having one ViewModel class (called MainUC_VM), and the DataContext of MainUC is set to this class instance (note that I am not using dependency injection so I just create an instance in the code-behind of MainUC). But in this way the MainUC_VM class would become really complicated, just like the MainUC. So I would also like to divide the ViewModel into several classes too. For example, in the MainUC_VM class, I can have such properties

public SubUCA_VM SubVM1 { get; set; }
public SubUCB_VM SubVM2 { get; set; }

However, since I am not using dependency injection (because our team hasn't decided to use it), how I can make the SubVM1 and SubVM2 become the DataContext of SubUC1 and SubUC2 respectively? I can't instantiate one in the code-behind of SubUCA and SubUCB, since they would be different ones than the property members in the MainUC_VM.

Some ways I can think of are, 1) make the SubUCA_VM and SubUCB_VM classes singleton (which is like the same behavior of dependency injection using e.g., MEF by default), or 2) using EvengAggregator to notify the instantiate of the object. But either way seems to be adding unnecessary complexity in my opinion. Does it mean that dependency injection is almost a must in order to use MVVM? Is there ever a way to achieve it without using of DI?

like image 447
tete Avatar asked Oct 21 '13 10:10

tete


1 Answers

You can use implicit data templates to link your data (VM) to your views. First, define the data templates in a resource dictionary available to your MainUC. This can be either in the user control itself or even in the application resources. These data templates instruct WPF which controls to use whenever it needs to present data of a certain type.

<UserControl.Resources>
    <DataTemplate TargetType="{x:Type local:SubUCA_VM}">
       <local:SubUCA />
    </DataTemplate>
    <DataTemplate TargetType="{x:Type local:SubUCB_VM}">
       <local:SubUCB />
    </DataTemplate>
</UserControl.Resources>

Then bind the content of the tabs to the child VMs:

<TabControl Name="mainUC" Grid.Row="0" >   
    <TabItem Header="Sub UC A" Content="{Binding SubVM1}" />
    <TabItem Header="Sub UC B" Content="{Binding SubVM2}" />
</TabControl>

Alternatively, you can have a list of child VMs in your main VM. Each child VM should have a Title property so the tab control can use it for the header. This way the main VM can dynamically build the UI. You'd still need the data templates defined above.

<TabControl ItemsSource="{Binding Children}" DisplayMemberPath="Title" />
like image 143
Eli Arbel Avatar answered Sep 20 '22 20:09

Eli Arbel