You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将运行时组合属性值回写到原设计时字符串属性?

实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 09:13:15