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.