Bind to a DataTemplate dynamically - c#

I have a ListBox and multiple DataTemplates, in separate files.
<ListBox ItemTemplate="{StaticResource ItemTemplate1}"/>
In the Styles.xaml file:
<DataTemplate x:Key="ItemTemplate1">...</DataTemplate>
<DataTemplate x:Key="ItemTemplate2">...</DataTemplate>
I want to change the ItemTemplate of the ListBox depending on the type of object that's in its list.
Is there a way to access the separate DataTemplates in the code-behind, so that I can bind to a property of my Page?

The way to do that without TemplateSelector is to specify DataType property and don't specify x:Key.
<DataTemplate DataType="{x:Type Type1}">...</DataTemplate>
<DataTemplate DataType="{x:Type Type2}">...</DataTemplate>
In this case appropriate DataTemplate will be automaticly applied in all places where property of specified type have been bound.
But I'd prefer to use TemplateSelector.
To access separated DataTemplate in code-behind you should first get resource dictionary:
var dict = new ResourceDictionary
{Source = new Uri("/ProjectNamespace;component/Styles.xaml", UriKind.Relative)};
Then you can get template:
var dataTemplate = (DataTemplate) dict["ItemTemplate1"];

Try this solution does pretty much what your trying to achieve:
Applying Data Templates Dynamically by Type in WP7
http://www.codeproject.com/Articles/113152/Applying-Data-Templates-Dynamically-by-Type-in-WP7
Its based on WP7 but should work for you too.

There is inbuilt support in WPF for your requirement. Start reading on DataTemplateSelector to select the template at runtime based on certain criteria.

Related

Content Control + DataTemplate dynamically changing UserControl DevExpress wpf

I want to dynamically load user control to a content control,so i used the "Good Old Method" of changing usercontrol based on DataTemplate.
But on setting the ViewModel property i.e binded to ContentControl content property, ContentControl is displaying "text" conatining the respective viewmodel`s name , instead of loading the respective Usercontrol.
Window`s Resources
<dxr:DXRibbonWindow.Resources>
<DataTemplate x:Key="TYRVM" DataType="{x:Type VM:ProductTYRViewModel}">
<views:TYRUserControl/>
</DataTemplate>
<DataTemplate x:Key="THORVM" DataType="{x:Type VM:ProductTHORViewModel}">
<views:THORUserControl/>
</DataTemplate>
<dxr:DXRibbonWindow.Resources>
Window`s code
<ContentControl Name="content" Content="{Binding Path=VMs,Mode=TwoWay}"/>
Now i don`t know what exactly the problem is!!
You have specified a Key on the DataTemplate so the DataTemplate is not automatically applied based on the Type.
This from MSDN:
This property that is very similar to the TargetType property of the Style class. When you set this property to the data type without specifying an x:Key, the DataTemplate gets applied automatically to data objects of that type. Note that when you do that the x:Key is set implicitly. Therefore, if you assign this DataTemplate an x:Key value, you are overriding the implicit x:Key and the DataTemplate would not be applied automatically.
Link to MSDN : DataTemplate.DataType

Adding Static Resources inside Contol.Resources Tag?

I am writing an application that allows me to leverage the default template selector provided by a ListBox. Currently, I am defining the DataTemplates within the Listbox.Resources tag like so:
<ListBox.Resources>
<DataTemplate DataType="{x:Type Dog}">
// Some XAML here
</DataTemplate>
<DataTemplate DataType="{x:Type Cat}">
// Some XAML here
</DataTemplate>
</ListBox.Resources>
The problem is that these Templates can get rather lengthy. I know this is probably trivial, but how can I reference these Datatemplates from a ResourceDictionary that has been added to the XAML file without writing a template selector? I can't seem to find documentation for doing this anywhere online.
Instead of placing it in a resource dictionary, why not create a composite control(s) which would achieve easier reading in the datatemplates as well as centralize the xaml into a named entity control. Plus one could add any dependency properties which would help with the data transfer.

How to create DataTemplate from UserControl instance?

Question
Basically I would like to do the following but it seems that I cannot:
UserControl myControl = new UserControl();
DataTemplate template = new DataTemplate(myControl);
The question: Is it possible to construct a DataTemplate from UserControl instance? If not, are there any other possible solutions?
Real problem
I'm working on a project where majority of UI views are simple static Word-like documents (e.g some text fields and maybe some images, nothing too fancy). Because most of persons working on this project are not coders we have designed very simple in-house markup language for UI generation. An example of markup of simple view is following:
First name: [Person.FirstName]
Last name: [Person.LastName]
Address: [Person.Address.Street], [Person.Address.City]
Now these templates are loaded at runtime and usercontrols are created based on them. In this case one usercontrol would be created and it would contain simply couple of stack panels and text blocks so that resulting control would look a bit like text document. XAML equivalent would be something like:
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="First name: "/>
<TextBlock Text={Binding Person.FirstName}
</StackPanel>
<StackPanel>
...
</StackPanel>
...
</StackPanel>
Then, I started to implement support for lists but couldn't think of a way how to do that. In theory it is simple and I came up with following syntax (+ XAML equivalent):
[List Customers]
First name: [Person.FirstName]
Last name: [Person.LastName]
Address: [Person.Address.Street], [Person.Address.City]
[EndList]
->
<StackPanel>
<ItemsControl ItemsSource="{Binding Customers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
[Insert code from previous XAML example here]
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
But I can't do that because it seems that I cannot construct DataTemplate directly from UserControl instance. There would be no problems if my UserControls were types, but they are not.
One possible solution is that I could bind ItemsControl.Items directly to list of UserControls (instead of binding to ItemsSource and ItemTemplate) but this is sub-optimal in our case for couple of reasons. I would be willing to try some other solutions first!
Update
For clarification: all I have is plain instance of UserControl class which contains the content I need. E.g.
UserControl control = new UserControl();
var panel = new StackPanel();
panel.Children.Add(...);
panel.Children.Add(...);
control.Content = panel;
// How to use that control as ItemTemplate for ItemsControl?
// It seems that it is not possible directly but I want to
// know what my options are.
I don't have class for it because I'm constructing it at run-time and I don't want to create new type dynamically by emiting IL code because it is way too painful.
Creating a datatemplate from Code behind goes like this:
FrameworkElementFactory factory = new FrameworkElementFactory(MyUserControl.GetType());
DataTemplate dt = new DataTemplate();
dt.VisualTree = factory;
yourItemsControlInstance.ItemTemplate = dt;
A datatemplate is a definition of controls to be built at runtime, that is way this construction with a ElementFactory. You do not want the same instance of the UserControl for every item in your ItemsControl.
Ah I understand your problem now. I don't think there is an easy way (one or two lines of code) to create a datatemplate from a UserControl instance.
But to solve your problem I see two directions:
At the point where an usercontrol is created, create a datatemplate instead and use that. It will be cumbersome, with nested FrameworkElementFactories. I have never done that, and the MSDN documentation says that you may encounter some limitations you cannnot do compared to datatemplates in Xaml. But if it is simple it must be doable. There used to be a codeproject article by Sacha Barber you could use as a guidance (if needed).
You pack the creation of the UserControl in a method called private UserControl createMyUserControl(){}
And do something like this:
ItemsControl itemsControl = new ItemsControl();
foreach (var customer in Customers)
{
var usercontrol = createMyUserControl(...);
usercontrol.DataContext = customer;
itemsControl.Items.Add(usercontrol);
}
Second option is less elegant in my opinion, so I would check out the option 1 first.
WPF: How to create Styles in code/and magical Content (see section at the end for extensive sample of a DataTemplate in Code behind)
I think you can replace UserControl with the ContentControl.
Just set the content of the ContentControl to the desired template and use it as ItemTemplate for the ItemsControl.

How to create DataTemplate at runtime?

I have defined the DataTemplate in the XAML, however I need to change it to be defined at run time, because its binding is dynamic.
<UserControl.Resources>
<DataTemplate x:Key="myCellTemplate">
<TextBlock Text="{Binding Description}" Margin="4"/>
</DataTemplate>
</UserControl.Resources>
Is there any way to define it in code-behind?
Thank you.
You might be able to accomplish what you need with a custom DataTemplateSelector and I'd recommend that approach, if possible. That said, it is possible to create a DataTemplate in code:
Type type = typeof(MyUserControl); //for example
var template = new DataTemplate();
template.VisualTree = new FrameworkElementFactory(type);
return template;
In this context, type is the type of visual element you want to have as the root of your template. If necessary, you could add additional elements using the factory, but in the one case where I've used this, I simply created UserControl elements to represent the different templates I was dynamically creating.
My apologies, this apparently isn't supported in Silverlight. In Silverlight, you have to use XamlReader.

Creating a XAML Resource from Code Without a Key

Is there a way to add a resource to a ResourceDictionary from code without giving it a resource key?
For instance, I have this resource in XAML:
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type xbap:FieldPropertyInfo}"
ItemsSource="{Binding Path=Value.Values}">
<TextBlock Text="{Binding Path=Name}" />
<HierarchicalDataTemplate>
</TreeView.Resources>
I need to create this resource dynamically from code and add it to the TreeView ResourceDictionary. However, in XAML having no Key means that it's used, by default, for all FieldPropertyInfo types. Is there a way to add it to the resource in code without having a key or is there a way I can use a key and still have it used on all FieldPropertyInfo types?
Here's what I've done in C# so far:
HierarchicalDataTemplate fieldPropertyTemplate = new HierarchicalDataTemplate("FieldProperyInfo");
fieldPropertyTemplate.ItemsSource = new Binding("Value.Values");
this.Resources.Add(null, fieldPropertyTemplate);
Obviously, adding a resource to the ResourceDictionary the key null doesn't work.
Use the type that you want the template to apply to as the key:
HierarchicalDataTemplate fieldPropertyTemplate = new
HierarchicalDataTemplate("FieldProperyInfo");
fieldPropertyTemplate.SetBinding(
HierarchialDataTemplate.ItemSourceProperty,
new Binding("Value.Values");
this.Resources.Add(FieldPropertyInfo.GetType(), fieldPropertyTemplate);
The reason your code wasn't working was your weren't actually setting the binding. You need to call SetBinding, with the property you want the binding bound to.
Use the type that you want the template to apply to as the key:
this.Resources.Add(FieldPropertyInfo.GetType(), fieldPropertyTemplate);
As with your template above you provide a type. You have to either have to provide a name or a type.

Categories