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}”/>
Did you see http://www.buttonchrome.com/post/Generic-IValueConverter-for-Silverlight-or-WPF.aspx
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?
Does it work as you expect if you use a DataGridTextColumn?
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.
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
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.
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;
}
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.
I think we have to subclass DatePicker, override the Keydown event and add our code along with the code in the base class
works well… any ideas on how to do the same thing with a ComboBox? (DataGridComboColumn)
Bill,
I am not sure I understand. what are you looking for?
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.
There is already one which is already included DataGridComboBoxColumn in silverlight. will that not work?
There is a DataGridCheckBoxColumn.. but I do not see any DataGridComboBoxColumn. I am using Silverlight 2. Are you sure it is there?
now I remember I used templatecolumn and had Combobox in it. did you try that.
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.
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
Hi. This works well. I was just wondering what we need to add to enable sorting. Thanks.
could you detail what you are doing