For probably the first time in any UI technology, Microsoft has succeeded in providing an out-of-the-box data binding framework that actually works and you may consider using outside of demo-environments. It works together very easily with RIA Services through the DomainDataSource control that just sits as an element in your XAML and you can be used to bind any other control to.
So far so great, but here’s the part they don’t tell you about: how do you get dropdowns to work with related entities and why do date/time fields get converted to UTC in your database?
Well, I had a great deal of fun finding out about these issues and judging by all the blogs and forums I’ve read so have many others.
Let’s look at the simplest issue first: dates and times getting converted automatically to UTC. I’ll tell you about the other one next time.
Building my first app with RIA, I noticed very quickly that dates and times entered in my UI didn’t get to my database correctly; in my case 1 hour always got deducted from the entered value. I started putting breakpoints in, checked the culture settings, checked my browser settings, but still could not figure out what was going on.
Then I found a blog that talked about a similar issue and had a possible answer: call the .ToUniversalTime () and .ToLocalTime() functions on each field to get the UI and database to agree. I didn’t really fancy writing a bunch of code every time I wanted to have a date in an entity, so I decided there had to be a better way of doing this. What I came u with is a DateTimeUtc2LocalValueConverter.
Basically Silverlight allows you to add a custom converter to any data binding. Normally this would be used to format data or to convert a list items to a code values. But why not convert a DateTime to another DateTime? So here’s how it works:
public class DateTimeUtc2LocalValueConverter : IValueConverter
{
public DateTimeUtc2LocalValueConverter() { }
public DateTimeUtc2LocalValueConverter(string dateFormat)
{ DateFormat = dateFormat; }
public string DateFormat { get; set; }
#region IValueConverter Members
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
DateTime valueUtc;
if (value == null) return null;
else if (value is string && !DateTime.TryParse((string)value,
out valueUtc)) { return null; }
else if (!(value is DateTime || value is DateTime?)) return null;
DateTime valueLocal = ((DateTime)value).ToLocalTime();
if (targetType == typeof(string))
{
return DateFormat == null ? valueLocal.ToString() :
valueLocal.ToString(DateFormat);
}
else if (targetType == typeof(DateTime) ||
targetType == typeof(DateTime?))
{
return valueLocal;
}
return null;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
DateTime valueLocal;
if (value == null) return null;
else if (value is string && !DateTime.TryParse(
(string)value, out valueLocal)) { return null; }
else if (!(value is DateTime || value is DateTime?)) return null;
DateTime valueUtc = ((DateTime)value).ToUniversalTime();
if (targetType == typeof(string))
{
return DateFormat == null ? valueUtc.ToString() :
valueUtc.ToString(DateFormat);
}
else if (targetType == typeof(DateTime) ||
targetType == typeof(DateTime?))
{
return valueUtc;
}
return null;
}
#endregion
}
Basically it’s an implementation of the IValueConverter interface that can take in a DateTime or a String and can output a DateTime or a String formatted in the way you want it. In between input and output the String or DateTime will be converted from UTC to local time (UTC coming from the database) or from local time to UTC (user enters local time).
How to wire it up in XAML? First declare the converter as a static resource, remembering to add the necessary namespace for the class.
...
<Grid x:Name="LayoutRoot" ...>
<Grid.Resources>
<util:DateTimeUtc2LocalValueConverter
x:Key="DateTimeUtc2LocalValueConverter" />
</Grid.Resources>
...
Then we can just add the converter to Binding of the control or controls we want.
...
<dataControls:DataFormDateField FieldLabelContent="Date"
Binding="{Binding Mode=TwoWay, Path=Date, Converter={StaticResource
DateTimeUtc2LocalValueConverter}}"/>
...
And gone is the issue, it’s as simple as that.
By Nick Verschueren, .Net Solutions Architect