WPF DataGrid - Create a New Custom Column

I am trying to create my own checkbox column (replacing it by default) in order to move to more complex data columns later, and I have the following code:

public class MyCheckBoxColumn : DataGridBoundColumn { protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { var cb = new CheckBox(); var bb = this.Binding as Binding; var b = new Binding { Path = bb.Path, Source = cell.DataContext }; cb.SetBinding(ToggleButton.IsCheckedProperty, b); return cb; } protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) { var cb = new CheckBox(); var bb = this.Binding as Binding; var b = new Binding { Path = bb.Path, Source = ToggleButton.IsCheckedProperty }; cb.SetBinding(ToggleButton.IsCheckedProperty, b); return cb; } protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs) { var cb = editingElement as CheckBox; return cb.IsChecked; } protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue) { var cb = editingElement as CheckBox; if (cb != null) cb.IsChecked = (bool)uneditedValue; } protected override bool CommitCellEdit(FrameworkElement editingElement) { var cb = editingElement as CheckBox; BindingExpression binding = editingElement.GetBindingExpression(ToggleButton.IsCheckedProperty); if (binding != null) binding.UpdateSource(); return true;// base.CommitCellEdit(editingElement); } } 

And my custom DataGrid:

 public class MyDataGrid : DataGrid { protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e) { try { var type = e.PropertyType; if (type == typeof(bool)) { var col = new MyCheckBoxColumn(); col.Binding = new Binding(e.PropertyName) {Mode = BindingMode.TwoWay}; e.Column = col; } else { base.OnAutoGeneratingColumn(e); } var propDescr = e.PropertyDescriptor as System.ComponentModel.PropertyDescriptor; e.Column.Header = propDescr.Description; } catch (Exception ex) { Utils.ReportException(ex); } } } 

Now everything seems nice, except for two things:

  • It seems that the only method used in MyCheckBoxColumn is GenerateElement() . All other methods are not used. I set control points in them, and they never fall ...
  • I use ObservableCollection as a data source, and the remaining columns notify me when they change, this is not.

It is odd that the bool value changes when you check / uncheck the box, but without notification and without going through CommitCellEdit() . Does anyone know what is going wrong here?

EDIT:

It seems that if I return the TextBlock from within GenerateElement() , it will cause other methods to be called (the notification problem will not be fixed, though). But why does this not work with CheckBoxes? How does the default column work?

+6
source share
1 answer

OK Here is the complete code for a custom CheckBox column. It seems that in order to have the control as a flag as a display (non-editing) element in the DataGrid, you must make it invisible. Or you can simply use TextBlock to display some character that resembles a check mark:

 public class MyCheckBoxColumn : DataGridBoundColumn { protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { var cb = new CheckBox() { IsHitTestVisible = false, HorizontalAlignment = HorizontalAlignment.Center, HorizontalContentAlignment = HorizontalAlignment.Center }; var bb = this.Binding as Binding; var b = new Binding { Path = bb.Path, Source = dataItem, Mode = BindingMode.TwoWay }; cb.SetBinding(ToggleButton.IsCheckedProperty, b); return cb; // var cb = new TextBlock() { TextAlignment = TextAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center }; // var bb = this.Binding as Binding; // var b = new Binding { Path = bb.Path, Source = dataItem, Mode = BindingMode.TwoWay, Converter = new MyBoolToMarkConverter() }; // cb.SetBinding(TextBlock.TextProperty, b); // return cb; } protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) { var cb = new CheckBox() { HorizontalAlignment = HorizontalAlignment.Center, HorizontalContentAlignment = HorizontalAlignment.Center }; var bb = this.Binding as Binding; var b = new Binding { Path = bb.Path, Source = dataItem, Mode = BindingMode.TwoWay }; cb.SetBinding(ToggleButton.IsCheckedProperty, b); return cb; } protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs) { var cb = editingElement as CheckBox; if (cb != null) return cb.IsChecked; return false; } protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue) { var cb = editingElement as CheckBox; if (cb != null) cb.IsChecked = (bool)uneditedValue; } protected override bool CommitCellEdit(FrameworkElement editingElement) { // The following 2 lines seem to help when sometimes the commit doesn't happen (for unknown to me reasons). //var cb = editingElement as CheckBox; //cb.IsChecked = cb.IsChecked; BindingExpression binding = editingElement.GetBindingExpression(ToggleButton.IsCheckedProperty); if (binding != null) binding.UpdateSource(); return true;// base.CommitCellEdit(editingElement); } } //-------------------------------------------------------------------------------------------- public class MyBoolToMarkConverter : IValueConverter { const string cTick = "β– "; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value.GetType() != typeof(bool)) return ""; bool val = (bool)value; return val ? cTick : ""; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value.GetType() != typeof(string)) return false; string val = (string)value; return val == cTick; } } //-------------------------------------------------------------------------------------------- 
+4
source

Source: https://habr.com/ru/post/948382/


All Articles