在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