Thursday, March 29, 2007

Creating datatemplates from code

It's really easy to create data templates from XAML, but today, one of my clients asks me to do it from code. The other request was to handle events of element form inside the template. So let's do it together

First of all we have to create DataProvider as we usual do in xaml.

 

XmlDataProvider data = new XmlDataProvider();
           data.Document = new System.Xml.XmlDocument();
           data.Document.InnerXml = getXMLstring();
           data.XPath = "/root/node";

Next step is to create binding expression for data template usage


 



Binding itemsBinding = new Binding();
            itemsBinding.XPath = "val";

So far, so good. Now comes the trick. In order to use DataTemplate class, we have to create Visual Tree of elements, being used in the template. In order to do it, first we should create FrameworkElementFactory and set all necessary handlers and properties there. The factory, is actually, kind of meta element,  derived from FrameworkElement and makes us able to markup anything, we have to have within the instance of future element. So let's do it


 



FrameworkElementFactory comboFactory = new FrameworkElementFactory(typeof(ComboBox));
            comboFactory.Name = "myComboFactory";
            comboFactory.SetBinding(ComboBox.ItemsSourceProperty, itemsBinding);
            comboFactory.AddHandler(ComboBox.SelectionChangedEvent, new SelectionChangedEventHandler(popup));

As you can see, I'm setting Binding and add event handler to FrameworkElementFactory in order them to appears in real element that will be generated by the factory.


The next step is rather simple. We'll create DataTemplate and set it's VisualTree property to newly created factory.


 



DataTemplate itemsTemplate = new DataTemplate();
           itemsTemplate.VisualTree = comboFactory;

Another binding, setting ItemTemplate property and we done.


 



Binding nodeBinding = new Binding();
            nodeBinding.Source = data;
 
            ListView lv = new ListView();
            lv.ItemTemplate = itemsTemplate;
            lv.SetBinding(ListView.ItemsSourceProperty, nodeBinding);
 
            myGrid.Children.Add(lv);

It's rather straight-forward to do it, but still, it's much simpler to create templates from XAML, isn't it? :)


Source code for this article

3 comments:

Cuperman said...

A long time ago now, maybe this article was for SL1 - is the VisualTree property still supported in SL2+ ?

Valentino said...

Great work, helped me a lot.

Dev said...

This is brilliant. Thank you!