Search code examples
wpfxamlmvvmdatacontext

Set DataContext in the logic tree in WPF Blend


I have a question regarding the Data Context of a Window and how it is inherited by the children controls.

If I have a Window, whose DataContext property is set in XAML like such:

<Window.DataContext>
    <local:SomeViewModel />
</Window.DataContext>

By adding a user control to the window, I understand that the user control will have its data context inherited from the window (unless I specify otherwise).

<local:MyUserControl />

What about within the user control? Since it is a different XAML file, how can I strongly type the Data Context within the user control? So if I specify a data context within the control:

<UserControl.DataContext>
    <local:SomeViewModel />
</UserControl.DataContext>

Does that override the Window's instance of the view model, creating a new instance in memory? I assume it does and if so, how can I pass around a view model to children views via xaml? I know I can do it in code-behind with direct assignments but I want this to be handled in xaml.

We've segregated the majority of our UI and currently have to manually assign the context in code behind.

I tried using RelativeSource but it did not seem to work. Perhaps I was using it wrong, but the context was never passed around.

Any thoughts?

Update 1

To clarify, I present a simple Window with a DataContext set to a custom view model.

<Window x:Class="MyProject.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModels="clr-namespace:MyProject.ViewModels"
        xmlns:views="clr-namespace:MyProject.MyCustomView">

    <Window.DataContext>
        <viewModels:ProjectViewModel />
    </Window.DataContext>

    <StackPanel>
        <views:MyCustomView />
    </StackPanel>
<Window>

Now within my MyCustomView user control, the other developer working on it will not know what the Type of the Data Context is with out manually walking through all of the possible parent Window's to see where it is being used. What I would like, is within my UserControl, to do the following:

<UserControl x:Class="MyProject.Views.DiaryDetailsDescription"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" >

<UserControl.DataContext Type="viewModels:ProjectViewModel />

</UserControl>

So that the designer/developer working on that user control knows that the data context for that user control will be the ProjectViewModel type, inherited by the owning Window.

Update 2

So to further clarify, what I want to do in my User Control XAML is the equivalent to the following C# code.

return (SingleViewModel)this.DataContext;

So the Designer in Blend knows exactly what type the DataContext will be. To him, the DataContext is just an object in the user control, even though it inherits the SingleViewModel context from the Window.


Solution

  • Maybe you should try to use a bunch DataTemplate + UserControl? In Resources e.g. in Window create DataTemplate with your UserControl:

    <Window.Resources>
        <DataTemplate DataType="{x:Type vm:SingleViewModel}">
            <vw:SingleView /> <!-- Your UserControl -->
        </DataTemplate>
    </Window.Resources>
    

    And in root Panel add the ContentControl like this:

    <ContentControl Name="MyContent"  
                    Content="{Binding Path=CurrentViewModel}" />
    

    Where CurrentViewModel may be SingleViewModel type.

    In this case, we see immediately that for SingleView DataContext using vm:SingleViewModel type. For more info, see this and this.

    Edit: more suitable option

    You can also try use d:DesignInstance:

    Use d:DesignInstance for create data bindings at design time for a DataContext that is assigned at run time. To create the data binding, you use the data binding builder to create a special design-time data context and set the DesignInstance to a business object type. DesignInstance is a design-time property.

    It is used successfully in the Blend for assigning DataContext. d:DesignInstance provides a technique for creating a non-faux type, setting the property IsDesignTimeCreatable to True on the d:DesignInstance enables this.

    For more information, please see this:

    d:DesignInstance, d:DesignData in Visual Studio 2010 Beta2