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
-----------------------------------------
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 { get; set; }
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 { get; set; }
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
private void OnLoaded(object sender, RoutedEventArgs e)
{Device device = DataContext as Device;
DeviceAConfigViewModel viewModel = new DeviceAConfigViewModel(device);
viewModel.Parent = this.Tag;
}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 { get; set; }
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 { get; set; }
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
Wrap the datatemplate in a UserControl and expose dependency properties on the UC that can be set by the parent.