So, I found the answer to my problem. Yes, perhaps " force ", or, perhaps more correctly, " trick ", PropertyGrid , always observing DisplayName when sorting. The essence of the problem was that the PropertyGrid uses the actual name of the property when sorting the properties of several selected objects. Therefore, to get the desired behavior, we must make the grid assume that DisplayName is the actual name of the property. PropertyGrid uses PropertyDescriptors to detect various property attributes of objects. We just need a custom PropertyDescriptor that will represent the DisplayName as the actual property name. Here is the following code:
public class DisplayNameEnforcingDescriptor : PropertyDescriptor { private PropertyDescriptor _descriptor; public DisplayNameEnforcingDescriptor(PropertyDescriptor descriptor) : base(descriptor) { this._descriptor = descriptor; } public override string Name { get { return string.IsNullOrEmpty(DisplayName) ? base.Name : DisplayName; } } public override bool CanResetValue(object component) { return _descriptor.CanResetValue(component); } public override Type ComponentType { get { return _descriptor.ComponentType; } } public override object GetValue(object component) { return _descriptor.GetValue(component); } public override bool IsReadOnly { get { return _descriptor.IsReadOnly; } } public override Type PropertyType { get { return _descriptor.PropertyType; } } public override void ResetValue(object component) { _descriptor.ResetValue(component); } public override void SetValue(object component, object value) { _descriptor.SetValue(component, value); } public override bool ShouldSerializeValue(object component) { return _descriptor.ShouldSerializeValue(component); } }
The previous class is used to migrate an existing PropertyDescriptor and override the behavior of the Name property. The Name property will now return DisplayName (if not empty or empty) or the name of the actual property. All other functions are delegated to the wrapped PropertyDescriptor .
So, now we have a way to change the name of the presented property, we just need the PropertyGrid use the new PropertyDescriptor . To do this, we need to configure TypeDescriptor . Let's look at the following code again:
public class DisplayNameEnforcingConverter : ExpandableObjectConverter { public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { PropertyDescriptorCollection original = base.GetProperties(context, value, attributes); List<DisplayNameEnforcingDescriptor> descriptorList = new List<DisplayNameEnforcingDescriptor>(); foreach (PropertyDescriptor descriptor in original) descriptorList.Add(new DisplayNameEnforcingDescriptor(descriptor)); return new PropertyDescriptorCollection(descriptorList.ToArray()); } }
This class inherits from ExpandableObjectConverter to use its existing behavior and minimize our implementation. We only need to override the GetProperties method. These methods query the base type to get the corresponding PropertyDescriptorCollection , and then wrap all the elements of this collection in our DisplayNameEnforcingDescriptor . The new collection back for our wrapped items.
Now, if we assign the MyObject class to DisplayNameEnforcingConverter , sorting will always be done based on the DisplayName properties
[TypeConverter(typeof(DisplayNameEnforcingConverter))] public class MyObject { [DisplayName("ZZZZ")] public int AProperty { get; set; } [DisplayName("BBBB")] public int BProperty { get; set; } }
