Home > Silverlight > Creating DataGridDateColumn for DataGrid

Creating DataGridDateColumn for DataGrid

When we want to display/edit date values in DataGrid,   we could add a templatecolumn add a TextBlock to the CellTemplate and DatePicker to CellEditingTemplate. but that gets repetitive, if we are doing the same in multiple places

we can create this custom column by inheriting from DataGridBoundColumn and overriding few methods

Here is the minimal code to create a DataGridDateColumn
 public class DataGridDateColumn : DataGridBoundColumn
    {
        public string DateFormat { get; set; }
        protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
        {
            DatePicker dp = editingElement as DatePicker;
            if (dp != null)
            {
                dp.SelectedDate = DateTime.Parse(uneditedValue.ToString());
            }
        }
        protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
        {
            DatePicker dp = new DatePicker();
            Binding b = new Binding();
            b.Path = this.Binding.Path;
            b.Source = this.Binding.Source;
            if (DateFormat != null)
            {
                DateTimeConverter dtc = new DateTimeConverter();
                b.Converter = dtc;
                b.ConverterParameter = DateFormat;
            }
            dp.SetBinding(DatePicker.SelectedDateProperty, this.Binding);

            return dp;
        }

        protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
        {
            TextBlock txt = new TextBlock();
            Binding b = new Binding();
            b.Path = this.Binding.Path;
            b.Source = this.Binding.Source;
            if (DateFormat != null)
            {
                DateTimeConverter dtc = new DateTimeConverter();              
                b.Converter = dtc;
                b.ConverterParameter = DateFormat;
            }
            txt.SetBinding(TextBlock.TextProperty, b);
            return txt;
        }

        protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
        {
            DatePicker dp = editingElement as DatePicker;
            if (dp != null)
            {
                DateTime? dt = dp.SelectedDate;
                if (dt.HasValue)
                return dt.Value;
            }
            return DateTime.Today ;
        }
    }

This is a converter, in case we want to format the date value

    public class DateTimeConverter : IValueConverter
    {
        public object Convert(object value,
                           Type targetType,
                           object parameter,
                           CultureInfo culture)
        {
            DateTime date = (DateTime)value;
            return date.ToString(parameter.ToString());
        }

        public object ConvertBack(object value,
                                  Type targetType,
                                  object parameter,
                                  CultureInfo culture)
        {
            string strValue = value.ToString();
            DateTime resultDateTime;
            if (DateTime.TryParse(strValue, out resultDateTime))
            {
                return resultDateTime;
            }
            return value;
        }
    }

Once we have these classes and namespace decleration(in my ex. it is mapped to local)
we can just say

<local : DataGridDateColumn DateFormat=”yyyy-MM-dd” Binding=”{Binding HireDate}”/>

Categories: Silverlight
  1. Andrus
    April 5, 2009 at 8:42 pm | #2

    I tried to use it in dynamic column:

    DataGridDateColumn dateColumn = new DataGridDateColumn();
    dateColumn.Binding = new Binding(“mydateproperty”);
    dateColumn.Binding.Mode = BindingMode.TwoWay;
    Columns.Add(dateColumn);

    Issues:

    a. In non-edit mode column still shows full datetime in invariant culture format.
    b. In edit mode down arrow key does not make next row active.

    How to fix?

  2. lee
    April 6, 2009 at 9:33 am | #3

    Does it work as you expect if you use a DataGridTextColumn?

  3. Andrus
    April 6, 2009 at 9:52 am | #4

    Yes. If I use
    DataGridTextColumn textColumn2 = new DataGridTextColumn();
    textColumn2.Binding = new Binding(“mydatetimeproperty”);
    textColumn2.Binding.Mode = BindingMode.TwoWay;

    Columns shows and allows to edit datetime in invariant culture format and down arrow works.

    Replacing column class with DataGridDateColumn() still shows invariant DateTime in non-editing mode. In edit mode it shows date in UI culture format but blocks down arrow key.

    • lee
      April 6, 2009 at 4:00 pm | #5

      looks like we need to raise the DataGridCellEditEndedEvent and for that we need the DataGridRow, I will post here if I find a way to that or if I find anything better on the net

      • Andrus
        April 6, 2009 at 4:15 pm | #6

        This may fix the down arrow issue. But how to show date only when not in edit mode? I tried to use this converter in CellTemplate:

        in mydatagrid.xaml:

        ….

        in mydatagrid.cs:

        DataGridTemplateColumn templateCol = new DataGridTemplateColumn();

        templateCol.CellTemplate = XamlReader.Load(string.Format(@”
        “,
        “mydateprop”)) as DataTemplate;

        Columns.Add(templateCol);

        However DateTimeConverter is not called.

        • lee
          April 7, 2009 at 10:30 am | #7

          if we modify the code to add 2 variables
          DataGridRow row = null;
          DataGrid g;
          and modify the following methods, it works to some extent, looks like the TextBox is handling the Keydown event, so we are not getting it. What a pain to change something
          protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
          {
          DependencyObject obj = (this.GetCellContent(dataItem) as TextBlock).Parent;
          while (true)
          {
          obj = VisualTreeHelper.GetParent(obj);

          if (obj is DataGridRow)
          {
          row = obj as DataGridRow;

          }
          else if (obj is DataGrid)
          {
          g = obj as DataGrid;
          break;
          }
          }

          DatePicker dp = new DatePicker();
          dp.KeyDown += new KeyEventHandler(dp_KeyDown);

          Binding b = new Binding();
          b.Path = this.Binding.Path;
          b.Source = this.Binding.Source;
          if (DateFormat != null)
          {
          DateTimeConverter dtc = new DateTimeConverter();
          b.Converter = dtc;
          b.ConverterParameter = DateFormat;
          }
          dp.SetBinding(DatePicker.SelectedDateProperty, this.Binding);

          return dp;
          }

          void dp_KeyDown(object sender, KeyEventArgs e)
          {

          g.CommitEdit(DataGridEditingUnit.Row, true);

          if (e.Key == Key.Down)
          g.SelectedIndex += 1;
          else if (e.Key == Key.Up)
          g.SelectedIndex -= 1;
          }

          • Andrus
            April 7, 2009 at 12:30 pm | #8

            I tried this with dynamic column. Problem persists. dp.KeyDown event handler is *not* called if down arrow key is pressed when editing control is active.
            It is called for Up arrow key only.

          • lee
            April 7, 2009 at 1:45 pm | #9

            I think we have to subclass DatePicker, override the Keydown event and add our code along with the code in the base class

  4. Bill
    May 4, 2009 at 2:00 am | #10

    works well… any ideas on how to do the same thing with a ComboBox? (DataGridComboColumn)

    • lee
      May 4, 2009 at 8:10 am | #11

      Bill,
      I am not sure I understand. what are you looking for?

      • Bill
        May 4, 2009 at 1:01 pm | #12

        Im looking for a new DataGridColumn (DataGridComboColumn) that inherits from DataGridBoundColumn, but instead of showing a datetime picker, it will show a combobox that will allow a user to pick a value froma list in a datagrid.

        • lee
          May 4, 2009 at 11:00 pm | #13

          There is already one which is already included DataGridComboBoxColumn in silverlight. will that not work?

          • Bill
            May 4, 2009 at 11:22 pm | #14

            There is a DataGridCheckBoxColumn.. but I do not see any DataGridComboBoxColumn. I am using Silverlight 2. Are you sure it is there?

          • lee
            May 4, 2009 at 11:37 pm | #15

            now I remember I used templatecolumn and had Combobox in it. did you try that.

          • Bill
            May 4, 2009 at 11:57 pm | #16

            Yes.. I tried that.. and it works.. but doesnt seem very elegant.. and it makes my XAML look messy. Would prefer a new class for this function.

          • lee
            May 5, 2009 at 12:52 am | #17

            ok. unless there are gotchas if we follow the same pattern and add combobox instead of datepicker it should work. we need to add a few more properties to relay them to combobox

  5. Matt
    September 23, 2009 at 9:13 pm | #18

    Hi. This works well. I was just wondering what we need to add to enable sorting. Thanks.

    • lee
      September 24, 2009 at 12:03 am | #19

      could you detail what you are doing

  1. No trackbacks yet.