Search code examples
c#wpfdatacontext

Share DataContext between MainWindows and UserControl


I wonder if it is possible to shared a datacontext between a Windows and is UserControl in C#/WPF.

I have a main windows like this (not finished):

MainWindow.xaml:

<Window x:Class="MyProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyProject"
        xmlns:v="clr-namespace:MyProject.Views"
        mc:Ignorable="d"
        Title="MyProject" >
    <Window.DataContext>
        <local:MainViewModel/>        
    </Window.DataContext>
    <Grid>
        <v:GenerateView/>
        <v:ReadView/>
    </Grid>
</Window>

MainViewModel.cs:

public class MainViewModel : ViewModelBase
{
    #region Properties
    #endregion

    #region Fields
    #endregion

    #region Constructor
    public MainViewModel()
        : base()
    {
    }
    #endregion

    #region Methods
    #endregion

    #region Commands
    #endregion
}

Depending on a future parameter, I will display my view GenerateView or ReadView. Actually I'm developing the UserControl GenerateView, but I wonder if I can use the same Datacontext.

According to that post, I started by this :

<UserControl x:Class="MyProject.Views.GenerateView"
         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" 
         xmlns:local="clr-namespace:MyProject.Views"
         xmlns:p="clr-namespace:MyProject.Properties"
         xmlns:MyProject="clr-namespace:MyProject" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyProject:MainWindow}}}">
    <Grid>
    </Grid>
</UserControl>

But It doesn't work, when I try to access Datacontext in GenerateView, It is null.

Edit:

I forgot a part of my code:

public partial class GenerateView : UserControl
{
    private MainViewModel Context
    {
        get
        {
            return DataContext as MainViewModel;
        }
    }

    public GenerateView()
    {
        InitializeComponent();
        Context.PropertyChanged += Context_PropertyChanged;
    }

    private void Context_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        //Action to perform
    }
}

The line Context.PropertyChanged += Context_PropertyChanged; throw an Exception because Datacontext is null.


Solution

  • What is the main requirement behind reusing a view model for Window and it’s sub user control? it doesn’t make sense. Does both have everything in common?

    In my opinion create a MainWindowViewModel and create SubViewModel for user control. Create the instances of sub viewmodels in your MainWindowViewModel and access them using DataContext.SubViewModel.

    By doing so, you could maintain the code and application well as well as preserve coding standards and have a complication free viewmodel. If you mix up everything just for reusability, you may be violating the MVVM pattern. Let different views/windows have its own viewmodel since they are not at all alike.

    If both are alike, then you can create reusable controls using Dependency Properties.