PropertyGrid 控件如何显示两层嵌套的动态 JSON 对象? [英] How does the PropertyGrid control display two levels of nested dynamic JSON objects?

查看:100
本文介绍了PropertyGrid 控件如何显示两层嵌套的动态 JSON 对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个要求,我同事的几个配置文件应该和PropertyGrid控件统一显示,我参考下面的帖子实现了:
代码:

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().ToList().Where(p => p.PropertyType.Name != "String").ToList();propExpandAndReadOnly(propertyDescriptorList);propertyGrid1.SelectedObject = typeDescriptor.FromComponent(customClass);}private void propExpandAndReadOnly(List propertyDescriptorList){foreach (var propertyDescriptor in propertyDescriptorList){propertyDescriptor.SetReadOnlyAttribute(true);propertyDescriptor.SetExpandableAttribute(true);DynamicTypeDescriptor typeDescriptor = new DynamicTypeDescriptor(propertyDescriptor.PropertyType);var chilPropertyDescriptorList = typeDescriptor.Properties.Cast().ToList().Where(p => p.PropertyType.Name != "String").ToList();propExpandAndReadOnly(chilPropertyDescriptorList);}}私有类型[] getPropertiesType(string[] 属性,JObject jsonObject){var propertyTypes = new List();foreach(属性中的 var 属性){var jToken = jsonObject.GetValue(property);类型属性类型;如果(jToken.HasValues){var obj = createClass(property, (JObject)jsonObject.GetValue(property));propertyType = obj.GetType();}别的{propertyType = typeof(string);}propertyTypes.Add(propertyType);}返回 propertyTypes.ToArray();}私有对象 createClass(字符串名称,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);返回对象;}

更新
创建 PropertyDescriptorExtensions

公共静态类 PropertyDescriptorExtensions{public static void SetReadOnlyAttribute(this PropertyDescriptor p, bool value){var 属性 = p.Attributes.Cast().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 属性 = p.Attributes.Cast().Where(x => !(x is ReadOnlyAttribute)).ToList();如果(值){attributes.Add(new TypeConverterAttribute(typeof(ExpandableObjectConverter)));}typeof(MemberDescriptor).GetProperty(AttributeArray",BindingFlags.Instance |BindingFlags.NonPublic).SetValue((MemberDescriptor)p,attributes.ToArray());}}

快乐编码,干杯!

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"
  }
}

解决方案

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!

这篇关于PropertyGrid 控件如何显示两层嵌套的动态 JSON 对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆