Tuesday, 13 April 2010

Date formatting using bindings in Silverlight DataForm

I had fun today trying to work out why I could not get the date column of a data form grid to be formatted correctly. Listed below is some xaml markup of the dataform..

   1: <df:DataForm x:Name="Form1" ItemsSource="{Binding Mode=OneWay}" AutoGenerateFields="True"
   2:                 AutoEdit="True" AutoCommit="False"
   3:                 CommitButtonContent="Save"
   4:                 CancelButtonContent="Cancel"               
   5:                 CommandButtonsVisibility="Commit"
   6:                 LabelPosition="Top" ScrollViewer.VerticalScrollBarVisibility="Disabled"
   7:                 EditEnded="NoteForm_EditEnded"> 
   8:         <df:DataForm.EditTemplate>
   9:             <DataTemplate>                    
  10:                 <StackPanel>
  11:                     <df:DataField>
  12:                         <TextBox Text="{Binding Title, Mode=TwoWay}"/>
  13:                     </df:DataField>
  14:  
  15:                     <df:DataField>
  16:                         <TextBox Text="{Binding Description, Mode=TwoWay}" AcceptsReturn="True" HorizontalScrollBarVisibility="Auto"
  17:                                  VerticalScrollBarVisibility="Auto" Height="" TextWrapping="Wrap" SizeChanged="TextBox_SizeChanged"/>                        
  18:                     </df:DataField>
  19:  
  20:                     <df:DataField>
  21:                         <TextBlock Text="{Binding Username}"/>
  22:                     </df:DataField>
  23:  
  24:                     <df:DataField>
  25:                         <TextBlock Text="{Binding DateCreated}"/>
  26:                     </df:DataField>
  27:                 </StackPanel>
  28:             </DataTemplate>
  29:         </df:DataForm.EditTemplate>
  30:     </df:DataForm>

The problem with this is no matter what format parameter I put on the annotation

   1: /// <summary>
   2: /// Gets or sets the date created of the noteannotation
   3: /// </summary>
   4: [Display(Name="Date Created")]
   5: [Editable(false)]
   6: [DisplayFormat(DataFormatString = "{0:u}", ApplyFormatInEditMode = true)]
   7: public DateTime DateCreated { get; set; }

it was being displayed as 4/6/2010 10:02:15 AM

This is the default binding format on the dataform. To solve this a convertor needed to be added to the datafield in question.

   1: <df:DataField>
   2:     <TextBlock Text="{Binding DateCreated, Converter={StaticResource DateConverter}}"/>
   3: </df:DataField>

The DateConverter is just a class than implements the IValueConverter interface. Example below shows the date time format I needed..

   1: /// <summary>
   2: /// Date time formatter - for short dates for data bound items
   3: /// </summary>
   4: public class DateConverter : IValueConverter
   5: {
   6:     #region Public Methods
   7:  
   8:     #region IValueConvertor Members
   9:  
  10:     /// <summary>
  11:     /// Convert data item to a short date
  12:     /// </summary>
  13:     /// <param name="value">Value</param>
  14:     /// <param name="targetType">Target type</param>
  15:     /// <param name="parameter">Paramter</param>
  16:     /// <param name="culture">Culture</param>
  17:     /// <returns>Converted object</returns>
  18:     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  19:     {
  20:         var date = (DateTime)value;
  21:         return (date.ToString("dd/MM/yyyy HH:mm:ss"));
  22:     }
  23:  
  24:     /// <summary>
  25:     /// Convert back data item to a short date
  26:     /// </summary>
  27:     /// <param name="value">Value</param>
  28:     /// <param name="targetType">Target type</param>
  29:     /// <param name="parameter">Paramter</param>
  30:     /// <param name="culture">Culture</param>
  31:     /// <returns>Converted object</returns>
  32:     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  33:     {
  34:         var s = (string)value;
  35:         return (DateTime.Parse(s));
  36:     }
  37:  
  38:     #endregion IValueConvertor Members
  39:  
  40:     #endregion Public Methods
  41: }

This works like a treat - could be improved with some null checking! :)

No comments: