在WPF 的DataGrid 中, 若需要自設DataGridColumn, 可以利用XAML DataGridTemplateColumn. 然而若遇到AutoGenerateColumn為true 或須要增加其re-usability 時, 自建user control 反而比較化算.
在這裡, 會建立兩個DataGird column來分別存取數字和日期.
建立DataGrid column 時, 只須要建立一個class 並inherit DataGridBoundColumn 或其sub class 便可. 之後再implement method 分別建立View 及Edit 時的DataTemplate 便可.
DateGridDateTimeColumn.cs
public class DataGridDateTimeColumn : DataGridBoundColumn
{
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
return GenerateDatePicker(dataItem);
}
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
return GenerateTextBlock(dataItem);
}
private DatePicker GenerateDatePicker(object source)
{
DatePicker result = new DatePicker()
{
Margin = new Thickness() { Bottom = 0, Left = 0, Right = 0, Top = 0 },
Padding = new Thickness() { Bottom = -2, Left = -2, Right = -2, Top = -2 }
};
Binding baseBinding = this.Binding as Binding;
Binding binding = new Binding()
{
Path = baseBinding.Path,
Source = source,
Mode = BindingMode.TwoWay,
StringFormat = Properties.Settings.Default.DisplayDateFormat
};
result.SetBinding(DatePicker.SelectedDateProperty, binding);
return result;
}
private TextBlock GenerateTextBlock(object source)
{
TextBlock result = new TextBlock()
{
Margin = new Thickness() { Bottom = 0, Left = 0, Right = 0, Top = 0 },
TextAlignment = TextAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
Binding baseBinding = this.Binding as Binding;
Binding binding = new Binding()
{
Path = baseBinding.Path,
Source = source,
Mode = BindingMode.TwoWay,
StringFormat = Properties.Settings.Default.DisplayDateFormat
};
result.SetBinding(TextBlock.TextProperty, binding);
return result;
}
}
DataGridNumericColumn.cs
public class DataGridNumericColumn : DataGridTextColumn
{
protected override object PrepareCellForEdit(System.Windows.FrameworkElement editingElement, System.Windows.RoutedEventArgs editingEventArgs)
{
TextBox edit = editingElement as TextBox;
edit.PreviewTextInput += OnPreviewTextInput;
return base.PrepareCellForEdit(editingElement, editingEventArgs);
}
private void OnPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = (!IsDataValid(e.Text));
}
private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
var data = e.SourceDataObject.GetData(DataFormats.Text);
if (!IsDataValid(data)) e.CancelCommand();
}
private bool IsDataValid(object data)
{
return ((string)data).IsNumeric();
}
}
叫用時, 只須設定好xml namesapace 後, 像平時用user control 般便可. 例如:
<DataGrid.Columns>
<local:DataGridNumericColumn Header="Number" Binding="{Binding NumericProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<local:DataGridDateTimeColumn Header="Date" Binding="{Binding DateTimeProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
Leave a Reply