如何将运行时组合属性值回写到原设计时字符串属性?
实现PropertyGrid中拆分/合并FullName属性的方案
核心思路
通过自定义TypeDescriptor替换原A类的FullName属性,用可展开的FullNameWrapper类拆分显示名和姓,同时在子属性修改时自动合并回原FullName字符串,无需修改原A类。
代码实现
1. 可展开的FullName包装类
这个类负责拆分原FullName为子属性,并在子属性变更时自动更新原对象的FullName:
public class FullNameWrapper { private readonly A _owner; private string _forename; private string _lastName; public FullNameWrapper(A owner) { _owner = owner; // 初始化时拆分原FullName if (!string.IsNullOrEmpty(_owner.FullName)) { var nameParts = _owner.FullName.Split(new[] {' '}, 2); _forename = nameParts.Length > 0 ? nameParts[0] : string.Empty; _lastName = nameParts.Length > 1 ? nameParts[1] : string.Empty; } } public string Forename { get => _forename; set { _forename = value; UpdateOwnerFullName(); } } public string LastName { get => _lastName; set { _lastName = value; UpdateOwnerFullName(); } } // 合并子属性到原FullName private void UpdateOwnerFullName() { _owner.FullName = $"{Forename} {LastName}".Trim(); } // 未展开时显示合并后的完整名称 public override string ToString() { return _owner.FullName; } }
2. 自定义属性描述符
替换原FullName属性,指定使用ExpandableObjectConverter实现展开:
public class FullNamePropertyDescriptor : PropertyDescriptor { private readonly PropertyDescriptor _originalProperty; public FullNamePropertyDescriptor(PropertyDescriptor originalProperty) : base(originalProperty) { _originalProperty = originalProperty; } public override bool CanResetValue(object component) => _originalProperty.CanResetValue(component); public override object GetValue(object component) => new FullNameWrapper((A)component); public override void ResetValue(object component) => _originalProperty.ResetValue(component); public override void SetValue(object component, object value) { if (value is FullNameWrapper wrapper) { wrapper.UpdateOwnerFullName(); } } public override bool ShouldSerializeValue(object component) => _originalProperty.ShouldSerializeValue(component); public override Type ComponentType => _originalProperty.ComponentType; public override bool IsReadOnly => false; public override Type PropertyType => typeof(FullNameWrapper); // 配置展开转换器 public override TypeConverter Converter => new ExpandableObjectConverter(); }
3. 自定义类型描述器与类型提供器
替换原A类的属性集合,将原FullName替换为自定义属性:
public class ATypeDescriptor : CustomTypeDescriptor { private readonly ICustomTypeDescriptor _originalDescriptor; public ATypeDescriptor(ICustomTypeDescriptor originalDescriptor) { _originalDescriptor = originalDescriptor; } public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) { var originalProps = _originalDescriptor.GetProperties(attributes); var modifiedProps = new List<PropertyDescriptor>(); foreach (PropertyDescriptor prop in originalProps) { if (prop.Name == nameof(A.FullName)) { modifiedProps.Add(new FullNamePropertyDescriptor(prop)); } else { modifiedProps.Add(prop); } } return new PropertyDescriptorCollection(modifiedProps.ToArray()); } } public class ATypeDescriptionProvider : TypeDescriptionProvider { private readonly TypeDescriptionProvider _originalProvider; public ATypeDescriptionProvider(TypeDescriptionProvider originalProvider) { _originalProvider = originalProvider; } public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { var originalDescriptor = _originalProvider.GetTypeDescriptor(objectType, instance); return new ATypeDescriptor(originalDescriptor); } }
4. 注册类型提供器
在程序启动时注册,让PropertyGrid使用自定义的类型描述:
// 注册到A类 TypeDescriptor.AddProvider( new ATypeDescriptionProvider(TypeDescriptor.GetProvider(typeof(A))), typeof(A) );
效果说明
- PropertyGrid中
FullName会显示为可展开项,未展开时显示完整名称 - 展开后可分别编辑
Forename和LastName,修改后原A.FullName会自动更新 - 直接修改原
A.FullName时,展开的子属性也会同步拆分更新
内容的提问来源于stack exchange,提问作者Piglet
相关产品推荐
相关产品推荐

