XamlWriter and Bindings Serialization
About serialization of Bindings to XAML with the standard MS XamlWriter.
Introduction
This article is to show how we can save your dynamically created bindings to XAML by using the standard MS XamlWriter
class in a simple and easy manner.
Background
I am one of the developers of a project called FreeSCADA. One of the main parts of this project is the Graphical Designer which has some functionality to save vector graphics in XAML format. In the process of developing, I was faced with a problem. Bindings created from the code (or loaded with a XAML file) were not serialized in XAML format. I was trying to find solutions over the web, but found out only the following article. Unfortunately, this solution isn't suitable for more complex XAML files for some reasons. I did not believe that MS had some special internal solution to this problem, because I saw that the TemplateBinding
extension could do such serialization perfectly, but Expression Binding could not. So, I downloaded the MS reference source code for debugging and started studying it. As a result, I found a very simple solution, which I will describe below.
Proposed solution
When I debugged code from MS, I found out that XamlWriter
interprets the DependencyProperty value as a Binding
. It checks this Binding
type for the availability of some registered type converter which can transform this value to the MarkupExtension
delivered type. If it is available, then XamlWriter
converts this Binding
to MarkupExtension
and does further serialization.
So, if you want to save your Binding
s, you can try the following simple code snippet. Basically, we need a class which looks something like this:
class BindingConvertor : ExpressionConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if(destinationType==typeof(MarkupExtension))
return true;
else return false;
}
public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value, Type destinationType)
{
if (destinationType == typeof(MarkupExtension))
{
BindingExpression bindingExpression = value as BindingExpression;
if (bindingExpression == null)
throw new Exception();
return bindingExpression.ParentBinding;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
After that, register this class as the type converter for the BindingExpression
type. This can be done with the following code:
static class EditorHelper
{
public static void Register <T, TC>()
{
Attribute[] attr = new Attribute[1];
TypeConverterAttribute vConv = new TypeConverterAttribute(typeof(TC));
attr[0] = vConv;
TypeDescriptor.AddAttributes(typeof(T), attr);
}
...
}
And call this function somewhere:
EditorHelper.Register <BindingExpression,BindingConvertor>();
After this, you must switch XamlWriter
to the expression saving mode:
StringBuilder outstr=new StringBuilder();
XamlCode.Clear();
//this code need for right XML fomating
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
XamlDesignerSerializationManager dsm =
new XamlDesignerSerializationManager(XmlWriter.Create(outstr, settings));
//this string need for turning on expression saving mode
dsm.XamlWriterMode = XamlWriterMode.Expression;
XamlWriter.Save(MainPanel, dsm);
That's all you need. A working example can be found in the posted source code zip archive.
P.S.: I'm sorry for some inaccuracies which where there in the first version of this article.