Tuesday 14 August 2012

Telerik WPF RadDatePicker, XML serialization, handling null values

To support blank values, an instance of the RadDatePicker must be bound to a value of DateTime? (nullable) type. Otherwise wiping out control's value does not change the bound value at all. Even more, it displays a nasty red border around the control.

If a bound value is a member of class intended to be serialized and de-serialized, it should be attributed in a specific way.

a) Apparently a member of DateTime? type stored in XML attribute, but only XML element should be used for that. An example is below.


private DateTime? _startDate;


[XmlElementAttribute(
    Form = System.Xml.Schema.XmlSchemaForm.Unqualified, 
    IsNullable = true)]
public DateTime? StartDate
{
    get
    {
        return this._startDate;
    }

    set
    {
        this._startDate = value;
        this.OnPropertyChanged("StartDate");
    }
}


The IsNullable parameter has to be either omitted or set to True.

b) Optionally you may include ShouldSerialize method as below. Note that the method's name must end with the member's name.


public bool ShouldSerializeStartDate()
{
    return this.StartDate.HasValue;
}


With such method present, an element with null value will be completely removed from serialization output. 

With no ShouldSerialize method implemented, such element will stay in the output but will hold no value.

<SampleEntity>
<StartDate xsi:nil="true" />
<EndDate>2012-07-31T00:00:00</EndDate>
</SampleEntity>

This post I conclude with two generic serialization routines.

public static string SerializeInstance<T>(this T instance)
{
    var serializer = new XmlSerializer(typeof(T));

    var stringBuilder = new StringBuilder();

    var settings = new XmlWriterSettings
    {
        ConformanceLevel = ConformanceLevel.Document,
        OmitXmlDeclaration = true
    };


    using (var writer = XmlWriter.Create(stringBuilder, settings))
    {
        serializer.Serialize(writer, instance);
        return stringBuilder.ToString();
    }
}

public static T DeserializeInstance<T>(string content)
{
    var serializer = new XmlSerializer(typeof(T));

    using (var reader = new StringReader(content ?? string.Empty))
    {
        var instance = (T)serializer.Deserialize(reader);
        return instance;
    }
}



I didn't change anything and now it's not working!

That's an explanation any developer dealing with end-users very likely have heard. In fact most of the times it means "the stupid thing is not working, I have changed something that I'm not aware of, I cannot find a suitable person or entity to blame, fix it fast because I'm already two days late with my report!".

Very nice, then today I am such an end-user. The data part of a .NET WinForm application throws an exception. One of the following postulates for sure must be false:
- "this morning everything worked"
- "I swear I did not change anything"

To make it short, in app.config I have created the appSettings section preceding the connectionStrings section. It is not my first visit into this little trap.