Custom Editor in WPF PropertyGrid
14 Aug 202324 minutes to read
The PropertyGrid control supports several built-in editors. Based on the property type, the built-in editors automatically assigned as value editor for the properties. You can assign own value editor(control) for the properties instead of default value editor by using the Editor attribute or CustomEditorCollection.
For example, if you creates an EmailID
property as a string type, TextBox
is assigned as a value editor and all the text will be allowed. If you want to accept the input that is only in the mail id format, you can assign SfMaskedEdit control with email-id mask as the value editor for the EmailID
property.
Best practice to follow
When using the CustomEditorCollection property to assign a custom editor to multiple properties of the same data type in the PropertyGrid
, it is recommended to use the EditorType
,PropertyType
and HasPropertyType
properties of the CustomEditor
class. Otherwise, for proper functionality, you must create a new CustomEditor
class and assign it to each property using the Properties
collection property.
Creating the Custom Editor
To create CustomEditor, we need to implement ITypeEditor interface. Here, SfMaskedEdit
control is assigned with mail id mask as EmailEditor
and UpDown
control is assigned with min, max value as IntegerEditor
. EmailEditor
and IntegerEditor
are the custom editors.
//Custom Editor for the EmailId properties.
public class EmailEditor : ITypeEditor {
SfMaskedEdit maskededit;
public void Attach(PropertyViewItem property, PropertyItem info) {
if (info.CanWrite) {
var binding = new Binding("Value")
{
Mode = BindingMode.TwoWay,
Source = info,
ValidatesOnExceptions = true,
ValidatesOnDataErrors = true
};
BindingOperations.SetBinding(maskededit, SfMaskedEdit.ValueProperty, binding);
}
else {
maskededit.IsEnabled = false;
var binding = new Binding("Value")
{
Source = info,
ValidatesOnExceptions = true,
ValidatesOnDataErrors = true
};
BindingOperations.SetBinding(maskededit, SfMaskedEdit.ValueProperty, binding);
}
}
public object Create(PropertyInfo propertyInfo) {
maskededit = new SfMaskedEdit();
maskededit.MaskType = MaskType.RegEx;
maskededit.Mask = "[A-Za-z0-9._%-]+@[A-Za-z0-9]+.[A-Za-z]{2,3}";
return maskededit;
}
public void Detach(PropertyViewItem property) {
}
}
//Custom Editor for the integer type properties.
public class IntegerEditor : ITypeEditor {
UpDown upDown;
public void Attach(PropertyViewItem property, PropertyItem info) {
if (info.CanWrite) {
var binding = new Binding("Value")
{
Mode = BindingMode.TwoWay,
Source = info,
ValidatesOnExceptions = true,
ValidatesOnDataErrors = true
};
BindingOperations.SetBinding(upDown, UpDown.ValueProperty, binding);
}
else {
upDown.IsEnabled = false;
var binding = new Binding("Value")
{
Source = info,
ValidatesOnExceptions = true,
ValidatesOnDataErrors = true
};
BindingOperations.SetBinding(upDown, UpDown.ValueProperty, binding);
}
}
public object Create(PropertyInfo propertyInfo) {
upDown = new UpDown();
upDown.ApplyZeroColor = false;
upDown.MinValue = 0;
upDown.MaxValue = 100;
upDown.NumberDecimalDigits = 0;
return upDown;
}
public void Detach(PropertyViewItem property) {
}
}
NOTE
To assign a created custom editor to a properties, refer the Assigning a Custom Editor topic.
Creating Custom Editor for a dynamic property.
If the SelectedObject has a property of type dynamic
, ExpandoObject
or ICustomTypeDescriptor
, we can create CustomEditor
class by inheriting BaseTypeEditor. You can initialize a new instance of the custom editor using the BaseTypeEditor.Create(PropertyDescriptor) function. Below example shows, how to get the value of dynamic properties using its PropertyDescriptor and apply the value in ComboEditor
to ComboBox objects.
//Custom Editor for the List<string> type properties.
public class ComboEditor : BaseTypeEditor
{
ComboBox comboBox;
public override void Attach(PropertyViewItem property, PropertyItem info)
{
var binding = new Binding("Value")
{
Mode = BindingMode.TwoWay,
Source = info,
ValidatesOnExceptions = true,
ValidatesOnDataErrors = true
};
BindingOperations.SetBinding(comboBox, ComboBox.SelectedItemProperty, binding);
}
// Create a custom editor for a normal property
public override object Create(PropertyInfo PropertyInfo)
{
throw new NotImplementedException();
}
// Create a custom editor for a dynamic property
public override object Create(PropertyDescriptor PropertyDescriptor)
{
comboBox = new ComboBox();
// Getting the values of dynamic property
dynamic comboBoxItemsList = PropertyDescriptor.GetValue(PropertyDescriptor.Name);
foreach (dynamic items in comboBoxItemsList)
{
comboBox.Items.Add(items);
}
comboBox.SelectedIndex = 0;
return comboBox;
}
public override void Detach(PropertyViewItem property)
{
comboBox = null;
}
}
NOTE
Download demo application from GitHub.
Assigning a Custom Editor using Editor Attribute
We can assign the CustomEditor
to any individual property by name of the property and to multiple properties based on the property type by using the Editor
attribute.
//CustomEditor for the specfic(EmailID) property
[Editor("EmailID", typeof(EmailEditor))]
//Custom Editor for the multiple(Tnteger type) properties
[Editor(typeof(int), typeof(IntegerEditor))]
public class Employee {
public string EmailID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Experience { get; set; }
}
class ViewModel {
public object SelectedEmployee { get; set; }
public ViewModel() {
SelectedEmployee = new Employee()
{
Age = 25,
Name = "mark",
Experience = 5,
EmailID = "mark@gt"
};
}
}
<syncfusion:PropertyGrid SelectedObject="{Binding SelectedEmployee}"
x:Name="propertyGrid1" >
<syncfusion:PropertyGrid.DataContext>
<local:ViewModel></local:ViewModel>
</syncfusion:PropertyGrid.DataContext>
</syncfusion:PropertyGrid>
PropertyGrid propertyGrid1 = new PropertyGrid();
propertyGrid1.DataContext = new ViewModel();
propertyGrid1.SetBinding(PropertyGrid.SelectedObjectProperty, new Binding("SelectedEmployee"));
Here, EmailID
property value editor changed from TextBox
to MaskedEdit
control with email id mask. Also, we assigned the IntegerEditor
for the integer type properties, so it applied to the Experience
and Age
properties. Then, the value editors for the Experience
and Age
property is changed from NumericTextBox
to Updown
control.
Assigning a Custom Editor using Collection
We can assign the CustomEditor
to any particular property and to multiple properties using the CustomEditorCollection
.
Assigning a Custom Editor to the specific property
If we want to apply custom editor for any particular property, we need to create the CustomEditor
instance, assign our own editor to the CustomEditor.Editor
and add the property name to the CustomEditor.Properties
collection. Then, add the CustomEditor
instance to the PropertyGrid.CustomEditorCollection
.
public class Employee {
public string EmailID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Experience { get; set; }
}
class ViewModel {
public object SelectedEmployee { get; set; }
public CustomEditorCollection customEditorCollection = new CustomEditorCollection();
public CustomEditorCollection CustomEditorCollection
{
get { return customEditorCollection; }
set { customEditorCollection = value; }
}
public ViewModel() {
SelectedEmployee = new Employee() { Age = 25, Name = "mark", Experience = 5, EmailID = "mark@gt" };
// EmailEditor added to the collection and will applied to the "EmailID" property
CustomEditor editor1 = new CustomEditor();
editor1.Editor = new EmailEditor();
editor1.Properties.Add("EmailID");
CustomEditorCollection.Add(editor1);
}
}
<syncfusion:PropertyGrid CustomEditorCollection="{Binding CustomEditorCollection}"
SelectedObject="{Binding SelectedEmployee}"
x:Name="propertyGrid1" >
<syncfusion:PropertyGrid.DataContext>
<local:ViewModel></local:ViewModel>
</syncfusion:PropertyGrid.DataContext>
</syncfusion:PropertyGrid>
PropertyGrid propertyGrid1 = new PropertyGrid();
propertyGrid1.DataContext = new ViewModel();
propertyGrid1.SetBinding(PropertyGrid.CustomEditorCollectionProperty, new Binding("CustomEditorCollection"));
propertyGrid1.SetBinding(PropertyGrid.SelectedObjectProperty, new Binding("SelectedEmployee"));
Here, The EmailID
is a string property, the TextBox
is assigned as a default editor. We changed it as SfMaskedEdit
textbox that accepts only inputs which are in the email id format.
Assigning a Custom Editor based on the property type
If we want to apply custom editor for multiple properties which are all contains same type, we need to create the CustomEditor
instance, assign our own editor to the CustomEditor.Editor
and sets the CustomEditor.HasPropertyType
property to true
. Then, mention the property type to the CustomEditor.PropertyType
.
public class Employee {
public string EmailID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Experience { get; set; }
}
class ViewModel {
public object SelectedEmployee { get; set; }
public CustomEditorCollection customEditorCollection = new CustomEditorCollection();
public CustomEditorCollection CustomEditorCollection
{
get { return customEditorCollection; }
set { customEditorCollection = value; }
}
public ViewModel() {
SelectedEmployee = new Employee() { Age = 25, Name = "mark", Experience = 5, EmailID = "mark@gt" };
// IntegerEditor added to the collection and will applied to the "int" type properties
CustomEditor editor = new CustomEditor();
editor.Editor = new IntegerEditor();
editor.HasPropertyType = true;
editor.PropertyType = typeof(int);
CustomEditorCollection.Add(editor);
}
}
<syncfusion:PropertyGrid CustomEditorCollection="{Binding CustomEditorCollection}"
SelectedObject="{Binding SelectedEmployee}"
x:Name="propertyGrid1" >
<syncfusion:PropertyGrid.DataContext>
<local:ViewModel></local:ViewModel>
</syncfusion:PropertyGrid.DataContext>
</syncfusion:PropertyGrid>
PropertyGrid propertyGrid1 = new PropertyGrid();
propertyGrid1.DataContext = new ViewModel();
propertyGrid1.SetBinding(PropertyGrid.CustomEditorCollectionProperty, new Binding("CustomEditorCollection"));
propertyGrid1.SetBinding(PropertyGrid.SelectedObjectProperty, new Binding("SelectedEmployee"));
Here, we assigned the IntegerEditor
custom editor for the integer type properties, so it applied to the Experience
and Age
properties. Then, the value editors for the Experience
and Age
property is changed from NumericTextBox
to Updown
control.
Click here to download the sample that showcases the CustomEditor
support.
Assigning a Custom Editor by the editor type
By default, when we use the CustomEditor.Editor to target multiple properties in PropertyGrid
, the same custom editor instance is used for all those properties. To maintain a dedicated or separate instance of the custom editor for each property, use CustomEditor.EditorType. The default value of the EditorType
property is null.
You can set the value for EditorType
property when custom editor is initialized in ViewModel
class as shown below.
<syncfusion:PropertyGrid CustomEditorCollection="{Binding CustomEditorCollection}"
SelectedObject="{Binding SelectedEmployee}"
x:Name="propertyGrid1" >
<syncfusion:PropertyGrid.DataContext>
<local:ViewModel></local:ViewModel>
</syncfusion:PropertyGrid.DataContext>
</syncfusion:PropertyGrid>
public class Employee
{
public string Country { get; set; }
public double Experience { get; set; }
public string Name { get; set; }
public double Age { get; set; }
}
class ViewModel
{
public object SelectedEmployee { get; set; }
private CustomEditorCollection customEditorCollection = new CustomEditorCollection();
public CustomEditorCollection CustomEditorCollection
{
get { return customEditorCollection; }
set { customEditorCollection = value; }
}
public ViewModel()
{
SelectedEmployee = new Employee() { Age = 25, Name = "mark", Experience = 5, EmailID = "mark@gt.com" };
CustomEditor editor1 = new CustomEditor()
{
EditorType = typeof(IntegerEditor),
HasPropertyType = true,
PropertyType = typeof(double)
};
CustomEditorCollection.Add(editor1);
}
}
You can also set value for CustomEditorType
property for CustomEditor
class in the xaml file as shown below.
Use constructor with parameters in custom editor
By default, PropertyGrid
control only invokes the constructor without parameter in custom editor. You can invoke and pass arguments to the constructors with any number of parameters in custom editor using the ConstructorParameter property of CustomEditor class. The default value of ConstructorParameter
is null. This can be achieved by following the below steps.
NOTE
ConstructorParameter
property will work only if a value is assigned for theEditorType
property in theCustomEditor
class.
-
Create a custom editor for the desired property item in
PropertyGrid
. Add constructor with parameters in the custom editor class.public class IntegerEditor : ITypeEditor { IntegerTextBox integerTextBox; bool ShowUpDown = false; public IntegerEditor() { } // Constructor with parameter in custom editor public IntegerEditor(bool showUpDown) { ShowUpDown = showUpDown; } public void Attach(PropertyViewItem property, PropertyItem info) { if (info.CanWrite) { var binding = new Binding("Value") { Mode = BindingMode.TwoWay, Source = info, ValidatesOnExceptions = true, ValidatesOnDataErrors = true }; BindingOperations.SetBinding(integerTextBox, IntegerTextBox.ValueProperty, binding); } else { integerTextBox.IsEnabled = false; var binding = new Binding("Value") { Source = info, ValidatesOnExceptions = true, ValidatesOnDataErrors = true }; BindingOperations.SetBinding(integerTextBox, IntegerTextBox.ValueProperty, binding); } } public object Create(PropertyInfo propertyInfo) { integerTextBox = new IntegerTextBox() { ApplyZeroColor = false, MinValue = 0, MaxValue = 50, ShowSpinButton = ShowUpDown, }; return integerTextBox; } public void Detach(PropertyViewItem property) { } }
-
Create
Employee
andViewModel
classes with required properties. Pass the required objects in an object array and assign it to theConstructorParameter
property ofCustomEditor
as shown below.public class Employee { public string EmailID { get; set; } public double Experience { get; set; } public string Name { get; set; } public long Age { get; set; } } class ViewModel { public object SelectedEmployee { get; set; } private CustomEditorCollection customEditorCollection = new CustomEditorCollection(); public CustomEditorCollection CustomEditorCollection { get { return customEditorCollection; } set { customEditorCollection = value; } } public int DecimalDigits { get; set; } public ViewModel() { SelectedEmployee = new Employee() { Age = 25, Name = "Mark Anthony", EmailID = "markanthony@syncfusion.com", Experience = 3 }; CustomEditor editor1 = new CustomEditor() { EditorType = typeof(IntegerEditor), HasPropertyType = true, PropertyType = typeof(long), ConstructorParameters = new object [] {true} }; CustomEditorCollection.Add(editor1); } }
<syncfusion:PropertyGrid CustomEditorCollection="{Binding CustomEditorCollection}" SelectedObject="{Binding SelectedEmployee}" x:Name="propertyGrid1" > <syncfusion:PropertyGrid.DataContext> <local:ViewModel></local:ViewModel> </syncfusion:PropertyGrid.DataContext> </syncfusion:PropertyGrid>
Since we have assigned the custom editor for property type long(Int64), the custom editor will be applied for Age
property item. You can also create custom editor and set value for ConstructorParameter
property in xaml file as shown below.
<syncfusion:PropertyGrid SelectedObject="{Binding SelectedEmployee}"
x:Name="propertyGrid1" >
<syncfusion:PropertyGrid.DataContext>
<local:ViewModel></local:ViewModel>
</syncfusion:PropertyGrid.DataContext>
<syncfusion:PropertyGrid.CustomEditorCollection>
<syncfusion:CustomEditorCollection>
<syncfusion:CustomEditor PropertyType="{x:Type a:Int64}" HasPropertyType="True" EditorType="{x:Type local:IntegerEditor}" >
<syncfusion:CustomEditor.ConstructorParameters>
<x:Array Type="{x:Type a:Object}">
<a:Boolean>True</a:Boolean>
</x:Array>
</syncfusion:CustomEditor.ConstructorParameters>
</syncfusion:CustomEditor>
</syncfusion:CustomEditorCollection>
</syncfusion:PropertyGrid.CustomEditorCollection>
</syncfusion:PropertyGrid>
Create custom editor control for the property item
The PropertyGrid
control allows users to create their editor controls using the CustomEditor class and CustomEditorCollection property for property items. The custom editors can be inherited from ITypeEditor and BaseTypeEditor interfaces.
The Create
method in the custom editor class can be used to create and assign the required editor controls for specific property items. The Create method’s PropertyInfo parameter allows users to customize the editor control based on the value of PropertyInfo
class.
public object Create(PropertyInfo propertyInfo)
{
textBox = new IntegerTextBox();
if (propertyInfo.Name == "Age")
{
textBox.MinValue = 20;
textBox.MaxValue = 50;
}
if (propertyInfo.CanWrite)
textBox.ShowSpinButton = true;
return textBox;
}
NOTE
If a CustomEditor class is inherited from BaseTypeEditor interface, the Create method will have
PropertyDescriptor
parameter value which can be used as per requirement.
Attach the custom editor with property item
The PropertyGrid
control control allows users to bind the essential properties of the custom editor control with the properties of the property items using the Attach
method. You can also customize the property items using the PropertyItem and PropertyViewItem using the parameters in the Attach
method.
public void Attach(PropertyViewItem property, PropertyItem info)
{
if (info.CanWrite)
{
property.FontFamily = new FontFamily("Comic Sans MS");
var binding = new Binding("Value")
{
Mode = BindingMode.TwoWay,
Source = info,
ValidatesOnExceptions = true,
ValidatesOnDataErrors = true
};
BindingOperations.SetBinding(textBox, IntegerTextBox.ValueProperty, binding);
}
}
Dispose the custom editor
The PropertyGrid
control control allows you to dispose the custom editor control and it’s dependent properties in CustomEditor class by using the Detach
method. You can also dispose the PropertyViewItem which will be available from the parameter of Detach
method.
public void Detach(PropertyViewItem property)
{
if (property != null && this.textBox != null)
{
this.textBox = null;
property.Dispose();
property = null;
}
}