Handing down a DataContext to a DataTemplate driven child view model

2,303 views
Skip to first unread message

Brian Noyes

unread,
Feb 24, 2011, 9:16:41 AM2/24/11
to wpf-di...@googlegroups.com

Hi all,

Got another one of those little design brain teasers to see how you all handle this scenario:

 

·         Parent ViewModel contains a heterogeneous collection of data objects base on a common base class

·         DataTemplates supply the view that renders each of those data objects

·         The presentation for some of those data objects is complex enough that the data template just contains a view which has a view model backing it (created in the XAML of the view)

·         The child view model needs a portion of the overall data context that flows down to it from the parent view (i.e. parent view DataContext is a complex object graph and the child view is rendering a child object or collection)

 

How would you feed the current DataContext that flows down into the child view into its view model?

 

I realize a common answer here, and one I frequently use, is to have the parent view model contain the child view models so that it can push the relevant portion of the context down into the child view model. But I have an app where we are plugging in the views through MEF imported DataTemplates and would like to be able to pass the DataContext into the child view models without the parent view model needing to know they even exist.

 

Thanks

Brian

 

 

 

-----------------------------------------
Brian Noyes
Chief Architect, IDesign Inc
Microsoft Regional Director / MVP
http://www.idesign.net
+1 703-447-3712
-----------------------------------------

 

Peter O'Hanlon

unread,
Feb 24, 2011, 9:24:03 AM2/24/11
to wpf-di...@googlegroups.com
Perhaps I'm missing something here, but why bother passing the data context in at all? Is it the same context? Is this child view inside the tree of the parent view?

What am I missing (apart from the fact that the datacontext sounds like it's going to be massive)?
--
Peter O'Hanlon

Marlon Grech

unread,
Feb 24, 2011, 9:29:57 AM2/24/11
to wpf-di...@googlegroups.com
not sure I understand... 

So you have a ViewModel that exposes a model and then you have a data template that renders that model?

class ParentVM
{
  public Person SomePerson {get}
}

<DataTemplate x:DataType={x:Type Person}>
 <DataTemplate.Resources>
  <local:PersonViewModel x:key="personVM" />
</DataTemplate.Resources>
  <Grid DataContext={StaticResource PersonVM}>

  </Grid>
</DataTemplate>

if this is the case how is the ViewModel you create in XAMl getting the Person object?

Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/
Microsoft MVP for Client App

Brian Noyes

unread,
Feb 24, 2011, 10:17:14 AM2/24/11
to wpf-di...@googlegroups.com

That is the conundrum.

 

The specific set up I have is a parent view that is a container for a collection of Device objects (presented in tabs in a TabControl). For each Device object, a view needs to get plugged in to the tab that allows you to configure certain parameters for that device that dictates how the software will control that device. Want to be able to extend the system by adding new device types over time without having to open up the core code where the parent view lives, and are using MEF to Import the device specific views and objects.

 

So the parent view has a collection of Device objects exposed on its view model.

public ObservableCollection<Device> Devices { getset; }

 

The code behind of the parent view uses MEF to import Device-type specific DataTemplates (i.e. DataType=DeviceA, DataType=DeviceB).

[ImportMany(MefContractName.DevicesDataTemplate, typeof(ResourceDictionary), AllowRecomposition = true)]
IEnumerable<ResourceDictionary> DataTemplates { getset; }
        
void IPartImportsSatisfiedNotification.OnImportsSatisfied()
{
    foreach (ResourceDictionary rd in DataTemplates)
        Resources.MergedDictionaries.Add(rd);
}

 

So each child view inherits a DataContext from the visual tree that is a Device derived object. Many of these views can just bind directly to the properties on that Device object. But some need ViewModel support in a device-specific way for things like drop down select values to set the properties they are bound to.

 

I’ll probably switch to just importing the view models into the parent view model based on their base type, injecting the data object they are responsible for, and then let the view data templates marry up based on the view model type instead.

 

But I was just pondering if there was a clean way to let the DataContext flow down to the child view and then hand that DataContext back to the view model, then replace the DataContext with the view model. I may have many views that don’t need any view model support.

Was currently doing it like so, but this just feels kind of wrong.

public partial class DeviceAConfigView : UserControl
{
    public DeviceAConfigView()
    {
        InitializeComponent();
        Loaded += OnLoaded;
    }
    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        Device device = DataContext as Device;
        DeviceAConfigViewModel viewModel = new DeviceAConfigViewModel(device);
    }
}

 

If I stick with this approach, would prefer a XAML-based swap.

 

Or maybe I am just smoking crack trying to attack it this way…

Brian

Peter O'Hanlon

unread,
Feb 24, 2011, 10:18:28 AM2/24/11
to wpf-di...@googlegroups.com
Ah sorry. I was misreading your question. Ignore my last reply as it's complete gibberish.

On 24 February 2011 14:16, Brian Noyes <brian...@softinsight.com> wrote:



--
Peter O'Hanlon

Marlon Grech

unread,
Feb 24, 2011, 10:34:25 AM2/24/11
to wpf-di...@googlegroups.com, Peter O'Hanlon
well you can use RelativeSource binding to walk the tree and get the value...

sounds a bit hacky but it would work... 

<DataTemplate>
  <Grid Tag={Binding RelativeSource={RelativeSource AncestorType={x:Type TabControl}}, Path=DataContext}


then in the code you can 


private void OnLoaded(object sender, RoutedEventArgs e)

    {

        Device device = DataContext as Device;

        DeviceAConfigViewModel viewModel = new DeviceAConfigViewModel(device);

        viewModel.Parent = this.Tag;

    }
again... its a bit hacky.... 

Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/
Microsoft MVP for Client App



Peter O'Hanlon

unread,
Feb 24, 2011, 10:37:39 AM2/24/11
to Brian Noyes, wpf-di...@googlegroups.com
Have a look at MefedMVVM. It seems to me that you could use a version of the context location functionality in there.

From: Brian Noyes
Sent: 24 February 2011 15:18
To: wpf-di...@googlegroups.com
Subject: RE: [WPF Disciples] Handing down a DataContext to a DataTemplate driven child view model

That is the conundrum.

 

The specific set up I have is a parent view that is a container for a collection of Device objects (presented in tabs in a TabControl). For each Device object, a view needs to get plugged in to the tab that allows you to configure certain parameters for that device that dictates how the software will control that device. Want to be able to extend the system by adding new device types over time without having to open up the core code where the parent view lives, and are using MEF to Import the device specific views and objects.

 

So the parent view has a collection of Device objects exposed on its view model.

public ObservableCollection<Device> Devices { getset; }

 

The code behind of the parent view uses MEF to import Device-type specific DataTemplates (i.e. DataType=DeviceA, DataType=DeviceB).

[ImportMany(MefContractName.DevicesDataTemplate, typeof(ResourceDictionary), AllowRecomposition = true)]
IEnumerable<ResourceDictionary> DataTemplates { getset; }
        
void IPartImportsSatisfiedNotification.OnImportsSatisfied()
{
    foreach (ResourceDictionary rd in DataTemplates)
        Resources.MergedDictionaries.Add(rd);
}

 

So each child view inherits a DataContext from the visual tree that is a Device derived object. Many of these views can just bind directly to the properties on that Device object. But some need ViewModel support in a device-specific way for things like drop down select values to set the properties they are bound to.

 

I’ll probably switch to just importing the view models into the parent view model based on their base type, injecting the data object they are responsible for, and then let the view data templates marry up based on the view model type instead.

 

But I was just pondering if there was a clean way to let the DataContext flow down to the child view and then hand that DataContext back to the view model, then replace the DataContext with the view model. I may have many views that don’t need any view model support.

Was currently doing it like so, but this just feels kind of wrong.


public partial class DeviceAConfigView : UserControl
{
    public DeviceAConfigView()
    {
        InitializeComponent();
        Loaded += OnLoaded;
    }
    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        Device device = DataContext as Device;
        DeviceAConfigViewModel viewModel = new DeviceAConfigViewModel(device);
    }
}

 

If I stick with this approach, would prefer a XAML-based swap.

 

Or maybe I am just smoking crack trying to attack it this way…

Brian

From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com] On Behalf Of Marlon Grech
Sent: Thursday, February 24, 2011 9:30 AM
To: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] Handing down a DataContext to a DataTemplate driven child view model

 

not sure I understand... 

 

So you have a ViewModel that exposes a model and then you have a data template that renders that model?

 

class ParentVM

{

  public Person SomePerson {get}

}

 

<DataTemplate x:DataType={x:Type Person}>

 <DataTemplate.Resources>

  <local:PersonViewModel x:key="personVM" />

</DataTemplate.Resources>

  <Grid DataContext={StaticResource PersonVM}>

 

  </Grid>

</DataTemplate>

 

if this is the case how is the ViewModel you create in XAMl getting the Person object?

Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/
Microsoft MVP for Client App


Michael Brown

unread,
Feb 24, 2011, 1:47:33 PM2/24/11
to wpf-di...@googlegroups.com

Wrap the datatemplate in a UserControl and expose dependency properties on the UC that can be set by the parent.

Reply all
Reply to author
Forward
0 new messages