How does the PropertyGrid control display two levels of nested dynamic JSON objects?

安稳与你 提交于 2021-02-11 15:02:33

问题


I have a requirement that several of my colleagues' configuration files should be displayed uniformly with the PropertyGrid control, which I have implemented with reference to the following post:https://www.codeproject.com/Articles/193462/Using-PropertyGrid-to-Display-and-Edit-Dynamic-Obj.

My way is: define a ConfigObject object first, then deserialized json configuration file into ConfigObject object using JsonConvert.Convert(Newtonsoft.Json), and then assigned to the PropertyGrid.SelectedObject. But this way I can only display and edit the one level of nested json objects, if more than two levels of nested structure, so the nested property field will be not editable.

Consider the following two-level JSON structure:

{
  "DAMultiCast": "18:80:c2:00:00:0e",
  "SA": "18:60:24:A8:77:FF",
  "gPTPType": "0x88f7",
  "AVTPType": "0x22f0",
  "Initial": {
    "SyncMessageType": "0x10",
    "FollowupMessageType": "0x18",
    "ReqMessageType": "0x12",
    "RespMessageType": "0x13",
    "RespFollowupMessageType": "0x1A",
    "versionPTP": "0x02",
    "SyncMessagelength": "44",
    "FollowupMessagelength": "76",
    "ReqMessagelength": "54",
    "subdomainnumber": "0",
    "resv0": "0x00",
    "Syncflagfield": "0x0208",
    "Followupflagfield": "0x0008",
    "correctionField": "00:00:00:00:00:00:00:00",
    "resv1": "00:00:00:00",
    "SyncClockIdentity": "01:02:03:ff:fe:46:76:34",
    "RespClockIdentity": "00:22:97:ff:fe:80:0d:f2",
    "sourcePortId": "0x0001",
    "sequenceId": "143",
    "SyncControlField": "0",
    "FollowupControlField": "2",
    "DelayReqControlField": "5",
    "logMessagePeriod": "-3",
    "tlvType": "3",
    "lengthField": "28",
    "organizationId": "32962",
    "organizationSubType": "1",
    "cumulativeScaledRateOffset": "0",
    "gmTimeBaseIndicator": "0",
    "lastGmPhaseChange": "00:00:00:00:00:00:00:00:00:00:00:00",
    "scaledLastGmFreqChange": "0",
    "requestingPortIdentity": "01:02:03:ff:fe:46:76:34",
    "requestingPortId": "1"
  },
  "TM1_TG1_6.1.1B": {
    "WaitTime1": "10",
    "WaitTime2": "2"
  }
}

回答1:


This might give you a hint to achieve your goal.

Source1: Dynamically Create a Class at Runtime
Source2: PropertyGrid Browsable not found for entity framework created property, how to find it?
Source3: Make a Property Read-Only in PropertyGrid

OUTPUT:

CODE:

private void loadJsonToPropertyGrid(string jsonString)
    {
        var jsonObject = JsonConvert.DeserializeObject<JObject>(jsonString);
        var obj = createClass("Item", jsonObject);
        var customClass = JsonConvert.DeserializeObject(jsonString, obj.GetType());
        var customClassType = customClass.GetType();

        DynamicTypeDescriptor typeDescriptor = new DynamicTypeDescriptor(customClassType);

        var propertyDescriptorList = typeDescriptor.Properties.Cast<PropertyDescriptor>().ToList()
        .Where(p => p.PropertyType.Name != "String").ToList();

        propExpandAndReadOnly(propertyDescriptorList);

        propertyGrid1.SelectedObject = typeDescriptor.FromComponent(customClass);
    }

    private void propExpandAndReadOnly(List<PropertyDescriptor> propertyDescriptorList)
    {
        foreach (var propertyDescriptor in propertyDescriptorList)
        {
            propertyDescriptor.SetReadOnlyAttribute(true);
            propertyDescriptor.SetExpandableAttribute(true);

            DynamicTypeDescriptor typeDescriptor = new DynamicTypeDescriptor(propertyDescriptor.PropertyType);
            var chilPropertyDescriptorList = typeDescriptor.Properties.Cast<PropertyDescriptor>().ToList()
            .Where(p => p.PropertyType.Name != "String").ToList();
            propExpandAndReadOnly(chilPropertyDescriptorList);
        }
    }

    private Type[] getPropertiesType(string[] properties, JObject jsonObject)
    {
        var propertyTypes = new List<Type>();

        foreach (var property in properties)
        {
            var jToken = jsonObject.GetValue(property);
            Type propertyType;

            if (jToken.HasValues)
            {
                var obj = createClass(property, (JObject)jsonObject.GetValue(property));
                propertyType = obj.GetType();
            }
            else
            {
                propertyType = typeof(string);
            }

            propertyTypes.Add(propertyType);
        }

        return propertyTypes.ToArray();
    }

    private object createClass(string name, JObject jsonObject)
    {
        MyClassBuilder MCB = new MyClassBuilder(name);
        var properties = jsonObject.Properties().Select(p => p.Name).ToArray();
        var propertiesType = getPropertiesType(properties, jsonObject);
        var obj = MCB.CreateObject(properties, propertiesType);

        return obj;
    }

UPDATE
Creation of PropertyDescriptorExtensions

public static class PropertyDescriptorExtensions
{
    public static void SetReadOnlyAttribute(this PropertyDescriptor p, bool value)
    {
        var attributes = p.Attributes.Cast<Attribute>()
            .Where(x => !(x is ReadOnlyAttribute)).ToList();

        attributes.Add(new ReadOnlyAttribute(value));

        typeof(MemberDescriptor).GetProperty("AttributeArray",
            BindingFlags.Instance | BindingFlags.NonPublic)
            .SetValue((MemberDescriptor)p, attributes.ToArray());
    }

    public static void SetExpandableAttribute(this PropertyDescriptor p, bool value)
    {
        var attributes = p.Attributes.Cast<Attribute>()
            .Where(x => !(x is ReadOnlyAttribute)).ToList();

        if (value)
        {
            attributes.Add(new TypeConverterAttribute(typeof(ExpandableObjectConverter)));
        }

        typeof(MemberDescriptor).GetProperty("AttributeArray",
            BindingFlags.Instance | BindingFlags.NonPublic)
            .SetValue((MemberDescriptor)p, attributes.ToArray());
    }
}

Happy coding, cheers!



来源:https://stackoverflow.com/questions/63372009/how-does-the-propertygrid-control-display-two-levels-of-nested-dynamic-json-obje

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!