CM / DataTemplates

Topics: UI Architecture
May 24, 2011 at 2:56 AM
Edited May 24, 2011 at 3:00 AM

How can I specify a DataTemplate to use for a contentcontrol on a View based on some contraints in the ViewModel e.g. (new, opening a record for edit)...  Still kinda new to CM.  I am navigating to a new page with INavigationService with an auto initialized property on the ViewModel for the View/VM in question, based on the Uri passed to the NavService.

I have 2 named datatemplates "AddFlightTemplate" / "EditFlightTemplate" each has a different layout.  The AddFlightTemplate will be based on the value of the Id passed in < 1 or null and we have a new record.  1 or greater we have an edit... Sterling is the datastore at present.

Thanks,

 

Morgan.

May 24, 2011 at 11:56 AM

Unfortunately, unlike WPF, there is no ContentTemplateSelector in WP7.
There is a possible solution, however, leveraging CM view location and, namely, the View.Context attached property (have a look here http://caliburnmicro.codeplex.com/wikipage?title=Screens%2c%20Conductors%20and%20Composition&referringTitle=Documentation, under "Multiple Views over the Same ViewModel").

You basically have to factor out the templates into two view whose names matches the Context naming convention:

VM: My.Namespace.XXXViewModel 
View: My.Namespace.XXXViewYYY

where YYY is the Context, specified in the ContentControl definition:

 <ContentControl cal:View.Model="{Binding}"
                        cal:View.Context="YYY" />

The View.Context could also be bound to some property of the VM as usual:

 <ContentControl cal:View.Model="{Binding}"
                        cal:View.Context="{Binding SomePropertySpecifyingContext}" />

Under these conditions, naming the views Flight.Add and Flight.Edit (i.e. under the Flight sub-namespace) and setting the property "SomePropertySpecifyingContext" to "Add" or "Edit" should work.

Let me know if you can get it working.
In order to help you to configure stuff properly, however, I should know the names of the name of the View and corresponding VM where the ContentControl lives.

May 24, 2011 at 8:40 PM
Edited May 25, 2011 at 12:09 AM

I see where you are going with this... what a p.i.t.a!  Hope they have the complete datatemplate model in mango tools that are due to drop today.

Just to solidify my thought pattern it would be something like

FlightsViewAdd and in the FlightsViewAdd is where I am setting up my controls for the add operation.  So this is just a way of "sub-reporting" (term used loosely), to inject the visuals and then bind the data accordingly?  ViewModel binding comes in from the Original Viewmodel doing the logic for the actual injection?

 

EDIT: Works like a charm!! Thanks... no only wish I hadn't installed the last Mango Tools... Found a bug in the XDE, I think

May 25, 2011 at 12:34 AM

Actually, there is no ContentTemplateSelector in SL4 either... so I don't think Mango tools will have it.
It's a WPF only feature, as far I know. 

You can achieve something similar to ContentTemplateSelector with an IValueConverter; the only drawback is obtaining DataTemplate instances.
In a project of mine I solved using a dedicated resource dictionary, while the bound value (with an optional prefix) was used as a key to identify the DataTemplate:

 

	public class TemplateSelectorConverter: IValueConverter
	{
		public Uri Source { get; set; }
		public string Prefix { get; set; }

	 
		#region IValueConverter Members

		object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			if (value == null) return null;
			if (Source == null) return null;
			
			var name = Prefix + value.ToString();

			var rd = new ResourceDictionary {  Source = Source };

			return rd[name];
		}

		object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			throw new NotSupportedException();
		}

		#endregion
 	 
	}

<ph:PhoneApplicationPage.Resources>
    <conv:TemplateSelectorConverter 
        x:Key="toTemplate"
		Prefix="XXX-"
		Source="/My.App.Assembly;component/Resources/DataTemplates.xaml" />
</ph:PhoneApplicationPage.Resources>
...
<ContentControl 
	ContentTemplate="{Binding SomeProperty, Converter={StaticResource toTemplate}}" 
	...
	/>

 

As for my previous post, I wanted to show a CM-only solution.
I think you got the tecnique: it is how UI composition is done in CM, so it's typically used to decompose complex screens in multiple VMs and Views.
In that sample I stretched the usual behavior to force a new composition of the same VM (cal:View.Model="{Binding}") with a different, dynamically chosen, View (cal:View.Context="{Binding SomePropertySpecifyingContext}")

There is no always-winning solution: choose the approach that best fits your needs.