Welcome to the Xceed Community | Help
Community Search  
More Search Options

Tech Side

It's All About the StatRows Part 2 - Code Behind

Have you ever had that feeling that you couldn’t get enough of StatRows? Well if you haven’t had, then you will now. I’ve decided to write you a sequel on “It’s All About the StatRows” to bring you part 2 – Code Behind! I’ve noticed that there are more and more developers that are coding XAML in code behind. We all know how that feels because between bugs in .NET and the time spent doing this, it just does not seem to be a fun task. I wish this could be easier, but unfortunately it is not since you will need to store XAML in a string and then load it using XAMLReader.To avoid as much error as possible, code your XAML in XAML first so that you don't get any syntax errors when bringing into code behind. There won't be any beautiful red zig-zag lines in between quotations ("").

 

So for the first topic of the post, I wanted to spend time showing you how to implement this in code behind. Before, we get started; I forgot to mention that I have noticed that this question was asked many times. I know that it was asked on StackOverflow and on our forums a bunch of times. I feel that writing a blog about this and hopefully those looking for answers will come here.

 

Build it and they shall come!

 

Let’s clear the air here and make everyone understand that, creating instances of DataTemplates, assigning styles and adding them to the Resources collection just won’t work in code behind. We have tried time and time again, until we found out that there is a bug in the .NET framework. You can attack this in any way and it just won’t cut. The only way to do it is to write the XAML and store it in a string. Here is a basic example:

 

private DataTemplate GenerateStatRowDataTemplate()
{
   ParserContext pc = new ParserContext();
   pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
   pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
   pc.XmlnsDictionary.Add("xcdg", "http://schemas.xceed.com/wpf/xaml/datagrid");

   string statRowTemplate = "<DataTemplate>";
   statRowTemplate+= "<xcdg:StatRow>";
   statRowTemplate += "<xcdg:StatCell FieldName=\"Column4\"   ResultPropertyName=\"AvgColumn4\">";
   statRowTemplate += "</xcdg:StatCell>";
   statRowTemplate += "</xcdg:StatRow>";
   statRowTemplate += "</DataTemplate>";

   StringReader stringReader = new StringReader(statRowTemplate);
   XmlReader xmlReader = XmlReader.Create(stringReader);
   MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(statRowTemplate.ToString()));
   

   DataTemplate dt = (DataTemplate)XamlReader.Load(ms,pc);
   dt.LoadContent();
   return dt;
}

 

This is the simplest way to achieve exactly what you want. The XamlReader.Load will load the XAML the way it should and place it in a DataTemplate instance. You can then add the DataTemplate into the FixedFooters or the groups footers. Voila! Now you have a StatRow which has now become dynamic.

 

But what if we want to do more? Say, a CellContentTemplate for the StatCell? This is easy, but we still run into another issue. The ParserContext won’t recognize your local namespace. You can try, but you won’t succeed. So now what do we do? Our first step is to add the namespace into the DataTemplate in the XAML string variable. So let’s modify the above code.

 

string statRowTemplate = "<DataTemplate xmlns:local=\"clr-namespace:TestProject;assembly=TestProject\">";

 

That’s it!

 

Now we have to give our converter a name. To do this, we must do it in the Resources of the DataTemplate. Here is the modified code:

 

statRowTemplate += "<DataTemplate.Resources><local:StatCellConverter x:Key=\"myConverter\"/></DataTemplate.Resources>";

 

That’s it again!

 

And now we must code our DataTemplate so that we can provide it to the CellContentTemplate property of the StatCell. This is easy as well and does not require much effort. In the next piece of code, I had written a converter that took any values that were being divided by 0 and displaying an error message instead of “#DIV/0#”.

 

statRowTemplate += "<xcdg:StatCell.ContentTemplate>";
statRowTemplate += "<DataTemplate>";
statRowTemplate += "<TextBlock Text=\"{Binding ., Converter={StaticResource ResourceKey=myConverter}}\" />";
statRowTemplate += "</DataTemplate>";
statRowTemplate += "</xcdg:StatCell.ContentTemplate>";

 

So overall, this was not a difficult task at all. The only issue is that we must first recognize what works and what doesn’t. In an ideal world, we would want to do this in .NET code rather than storing XAML in code behind. But who said life was easy? So here is the final code up until now:

 

private DataTemplate GenerateStatRowDataTemplate()
{
   ParserContext pc = new ParserContext();
   pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
   pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
   pc.XmlnsDictionary.Add("xcdg", "http://schemas.xceed.com/wpf/xaml/datagrid");

   string statRowTemplate = "<DataTemplate xmlns:local=\"clr-namespace:TestProject;assembly=TestProject\">";
   statRowTemplate += "<DataTemplate.Resources><local:StatCellConverter x:Key=\"myConverter\"/></DataTemplate.Resources>";
   statRowTemplate+= "<xcdg:StatRow>";
   statRowTemplate += "<xcdg:StatCell FieldName=\"Column4\" ResultPropertyName=\"AvgColumn4\">";
   statRowTemplate += "<xcdg:StatCell.ContentTemplate>";
   statRowTemplate += "<DataTemplate>";
   statRowTemplate += "<TextBlock Text=\"{Binding ., Converter={StaticResource ResourceKey=myConverter}}\" />";
   statRowTemplate += "</DataTemplate>";
   statRowTemplate += "</xcdg:StatCell.ContentTemplate>";
   statRowTemplate += "</xcdg:StatCell>";
   statRowTemplate += "</xcdg:StatRow>";
   statRowTemplate += "</DataTemplate>";

   StringReader stringReader = new StringReader(statRowTemplate);
   XmlReader xmlReader = XmlReader.Create(stringReader);
   MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(statRowTemplate.ToString()));
   DataTemplate dt = (DataTemplate)XamlReader.Load(ms,pc);
   dt.LoadContent();
   return dt;
}

 

This does conclude the post on It’s All About the StatRows Part 2 – Code Behind. This does not mean that it is the end of StatRows blogging, but, for now I believe I have covered the more popular questions and concerns about it. I shall return shortly, and hopefully bring you more wisdom to carry forth your development adventures. Before I end it, I just want to say Happy New Year and welcome to 2012! Xceed is always looking to make improvements and to bring you the best components. Just remember that those of us on the Tech Side of things, we support you! Thanks for reading. Marc – out.

 

Published February 18, 2012 4:13 PM by Marc [Xceed]

Comments

 

Friedrich said:

Yuck! Why does Microsoft not fix the framework bug?  Is this still a problem in .net 4.5?  In any case, its good to know about this, thanks for the example - merci!

Friedrich Brunzema

October 30, 2012 10:54 PM
 

James said:

If you have a StatRow defined in xaml, and just want to add some more StatCells at run time, what would the approach be?

Would you need to generate a whole new DataTemplate?

Could you get the xaml string for the design-time one and adjust it?

April 22, 2014 11:22 AM
Anonymous comments are disabled
Contact | Site Map | Reviews | Legal Terms of Use | Trademarks | Privacy Statement Copyright 2011 Xceed Software Inc.