Telerik blogs

If you need a custom editor to edit a specific data, you can use one of the following approaches:

 

  1. Use CellEditTemplate property of the GridViewColumn.
  2. Create a custom column by inheriting from GridViewBoundColumnBase.

 

As almost anything in our life both approaches have some advantages and disadvantages. Although it is quite easy to implement the first option, there are some significant disadvantages like not so usable with many RadGridView instances, and more important this bypasses the RadGridView validation and editing engine. For more information about this approach you can take a look at this online example.

 

In this blog post I’ll try to explain how to implement and take maximum advantages from the second option (needs more efforts to implement).

 

I’ll demonstrate the second approach by creating a column with embedded color picker control as an editor. I will start with creating a class that inherits from GridViewBoundColumnBase (this is the base class used to create a column with editing capabilities). There are several methods you have to override in order to get this column to work:

 

1. CreateCellElement – override this method if you want to customize how cells that belongs to this column will look like. This method is called when GridViewCell is prepared and returned element will be used as a ContentPresenter. If you do not override this method a TextBlock control will be used as a default presenter.

 

   1: public override FrameworkElement CreateCellElement(GridViewCell cell, object dataItem)
   2:         {
   3:             Border cellElement = new Border();
   4:             var valueBinding = new Binding(this.DataMemberBinding.Path.Path)
   5:                 {
   6:                     Mode = BindingMode.OneTime,
   7:                     Converter = new ColorToBrushConverter()
   8:                 };
   9:             cellElement.SetBinding(Border.BackgroundProperty, valueBinding);
  10:             cellElement.Width = 45;
  11:             cellElement.Height = 20;
  12:             cellElement.CornerRadius = new CornerRadius(5);
  13: return cellElement;
  14:         }

There is nothing unusual here just a border with bound background to the color from data item.

 

2. CreateCellEditElement – override this method to create custom editor element (according to type of the property or some other business logic). This method must be overridden otherwise GridViewCell will have no content when enters into edit mode.

 

   1: public override FrameworkElement CreateCellEditElement(GridViewCell cell, object dataItem)
   2:         {
   3:             var cellEditElement = new RadColorPicker();
   4: this.BindingTarget = RadColorPicker.SelectedColorProperty;
   5:  
   6:             cellEditElement.MainPalette = this.MainPalette;
   7:  
   8:             Binding valueBinding = this.CreateValueBinding();
   9:  
  10:             cellEditElement.SetBinding(RadColorPicker.SelectedColorProperty, valueBinding);
  11:  
  12: return cellEditElement as FrameworkElement;
  13:         }

In this method we create and return an instance of a RadColorPicker control. In order to work properly as an editor you have to bind this editor to the underlying data property. Lets take a look at the CreateValueBinding method:

   1: private Binding CreateValueBinding()
   2:         {
   3:             Binding valueBinding = new Binding();
   4:             valueBinding.Mode = BindingMode.TwoWay;
   5:             valueBinding.NotifyOnValidationError = true;
   6:             valueBinding.ValidatesOnExceptions = true;
   7:             valueBinding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
   8:             valueBinding.Path = new PropertyPath(this.DataMemberBinding.Path.Path);
   9: return valueBinding;
  10:         }

 

 

We set BindingMode to TwoWay, because this is an editor and we need to update data property which is bound to the parent GridViewColumn.

NotifyOnValidationError and ValidatesOnExceptions properties are related to validation engine (if any error or exception occurs while we set new value to the data object will result as validation error and editor will enter into invalid state (if editor has such state)).

Set UpdateSourceTrigger to Explicit and allow RadGridView to validate and update the value of the data item at the right moment.

Of course every TwoWay binding requires a path, so we take the path from the DataMemberBinding property.

Another interesting line of the CreateCellEditElement is: cellEditElement.MainPalette = this.MainPalette. This line shows how you can transfer properties from column to the actual editor. In order to allow such properties and transfer them to custom column instance you have to override CopyPropertiesFrom method:

   1: public override void CopyPropertiesFrom(GridViewColumn source)
   2:         {
   3: base.CopyPropertiesFrom(source);
   4:             var radColorPickerColumn = source as RadColorPickerColumn;
   5: if (radColorPickerColumn != null)
   6:             {
   7: this.MainPalette = radColorPickerColumn.MainPalette;
   8:             }
   9:         }

Then you can set this custom property via xaml:

   1: <local:RadColorPickerColumn UniqueName="FavouriteColor" DataMemberBinding="{Binding FavouriteColor}" 
   2:                                             Header="FavouriteColor" MainPalette="ReallyWebSafe">

 

Call to the base method is very critical because if you do not call base method properties like DataMemberBinding will not be copied to the RadColorPickerColumn.

 

And now we have to integrate this column into the RadGridView validation and editing engine. There are two methods which you have to override:

 

   1: public override object GetNewValueFromEditor(object editor)
   2:         {
   3:             RadColorPicker colorPicker = editor as RadColorPicker;
   4: if (colorPicker != null)
   5:             {
   6: return colorPicker.SelectedColor;
   7:             }
   8: else
   9:             {
  10: return null;
  11:             }
  12:         }
  13:  
  14: public override IList<ValidationError> UpdateSourceWithEditorValue(GridViewCell gridViewCell)
  15:         {
  16:             List<ValidationError> errors = new List<ValidationError>();
  17:             RadColorPicker editor = gridViewCell.GetEditingElement() as RadColorPicker;
  18:             BindingExpression bindingExpression = editor.ReadLocalValue(RadColorPicker.SelectedColorProperty) as BindingExpression;
  19: if (bindingExpression != null)
  20:             {
  21:                 bindingExpression.UpdateSource();
  22:                 errors.AddRange(Validation.GetErrors(editor));
  23:             }
  24: return errors;
  25:         }

 

As you can see first method gathers required information from the actual editor (used by the validation engine), after UI validation is successful then new value is submitted to the data item via second method. This second method returns errors (if any) that occurred while new value is set to the data item (Data layer validation).

 

There is another useful property which you probably already noticed - BindingTarget property. Generally the actual editor is a single control which has a ValueProperty bound to the data item. When you set BindingTarget property to this ValueProperty, there is no need to override GetNewValueFromEditor and UpdateSourceWithEditorValue methods. Base methods will take necessary actions to validate and update the value. There is only one restriction this ValueProperty must be a direct property of the CellEditElement returned as a result of the CreateCellEditElement method. In this example BindingTarget property is set to RadColorPicker.SelectedColorProperty. If you have a composite UserControl you have to set BindingTarget to UserControl1.ValueProperty.

 

You can play with this example:

 

 

 

Happy editing!

Enjoy!


About the Author

Nedyalko Nikolov

 is Team Lead in Telerik XAML Team

Comments

Comments are disabled in preview mode.