【问题标题】:Automatically generating a UI based on the Class that has been passed根据已传递的 Class 自动生成 UI
【发布时间】:2019-04-06 05:02:08
【问题描述】:

这可能是一个非常基本的问题,但几个月以来我一直在努力解决这个问题。 我想创建一个简单的 UI 来创建我传递给 UI 构造函数的类的对象。 假设我有 2 个课程:

    class Test1
    {
        public static List<Test1> objectList;
        public string code;
        public string name;
    }

    class Test2
    {
        public static List<Test2> objectList;
        public string code;
        public string name;
        public int value;
    }

(静态类将包含从该类创建的所有对象)

我想做的是创建一个代码,它将一个类作为变量(可能是一个泛型类?),并在此基础上根据类中可用的字段创建所有标签和文本框。 例如

    public RegisterUI<T> ()
    {
        Grid grd = new Grid();
        DataGrid dg = new DataGrid();
        Button saveBtn = new Button();

        //Binding the static list of objects to the DataGrid
        dg.ItemSource = T.objectList;

        //Adding the UI elemnts to the grid
        grd.children.add(dg);
        grd.children.add(saveBtn);

        //Creating for each field in the Class T a lable based on its name and a combobox + binding
        foreach(field in T)
        {
            Lable lbl = new Lable(field.getName);
            ComboBox cbx = new ComboBox();
            grd.children.add(lbl);
            grd.children.add(cbx);
        }
    }

这甚至可能吗?我希望我不会对模型代码含糊其辞,您可以理解我的目标。 任何建议将不胜感激。非常感谢:)

【问题讨论】:

    标签: c# wpf user-interface data-binding automation


    【解决方案1】:

    是的,这是可能的。为了自动创建设置对话框,我已经完成了这件事(我厌倦了制作自定义表单,只要我的一个程序有需要由用户修改的设置)。

    怎么做?

    您将需要研究“反射”,它为您提供了一种动态询问对象结构的方法。

    我不为此使用泛型,而是从类中询问类型。

    如果我将Test1 传入我的班级,我会得到:

    我希望我可以提供源代码,但可惜它属于我的雇主。不过,我可以提供一个简短的 sn-p 来帮助您入门:

      Type type = typeof(Test1);
    
      //Get public fields
      List<FieldInfo> fieldInfo = type.GetFields().ToList();
    
      //Get private fields.  Ensure they are not a backing field.
      IEnumerable<FieldInfo> privateFieldInfo = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(f => !f.Name.Contains("k__BackingField"));
    
      //Get public properties 
      List<PropertyInfo> properties = type.GetProperties().ToList();
    
      //Get private properties 
      properties.AddRange(type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance));
    

    【讨论】:

    • 非常感谢您的建议,我可以继续。
    • @CKnodyvara 如果您认为此答案有帮助,请单击“向上箭头”进行投票,然后单击“复选标记”将其标记为您问题的答案。您可以对任何您认为有帮助的答案进行投票,但只能将一个标记为答案。
    【解决方案2】:

    嗯,看起来旧的演示可能会帮助解决:

    注意:我在实现中使用 JSON 和 NewtonSoft 的 JSON 库来读取 JSON 并从中构建对象/UI:

    private void LoadConfig()
        {
            JsonSerializerSettings jss = new JsonSerializerSettings()
            {
                DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate
            };
            var cfg = ConfigIO.OpenDefault();
            ConfigItem ci = JsonConvert.DeserializeObject<ConfigItem>(cfg.Object);
            IEnumerable<MemberInfo> atts = ConfigInterOps.GetAttributes(typeof(ConfigItem));
            FillForm(ci, atts);
        }
    
    private void FillForm(Object referenceObject, IEnumerable<MemberInfo> atts)
        {
            int location = 5;
            foreach (var att in atts)
            {
                var cfg = new ConfigurationBox(att.Name, referenceObject.GetType()
                    .GetProperty(att.Name).GetValue(referenceObject, null));
    
                cfg.Name = $"cfg_ {att.Name}";
                cfg.Top = 3 * location;
                location += 10;
                Controls["flowLayoutPanel1"].Controls.Add(cfg);                
            }
        }
    

    上面提到的我制作和使用的几个类:

    public static class ConfigInterOps
    {
        public static IEnumerable<MemberInfo> GetAttributes(Type type)
        {
            return type.GetMembers()
                .Where(x => x.MemberType == MemberTypes.Property ||
                    x.MemberType == MemberTypes.Field);
        }
    }
    
    public static class ConfigIO
    {
        public static void Save(Config cfg)
        {
            UseDefaultLocation(cfg);
            if (!File.Exists(cfg.FileLocation))
            {
                File.Create(cfg.FileLocation);
            }
            File.WriteAllText(cfg.FileLocation, JsonConvert.SerializeObject(cfg));
        }
    
        private static void UseDefaultLocation(Config cfg)
        {
            cfg.FileLocation = cfg.FileLocation ?? Path.Combine($"{AppContext.BaseDirectory}", "conf.jobj");
        }
    
        public static Config OpenDefault()
        {
            var cfg = new Config();
            UseDefaultLocation(cfg);
            return Open(cfg);            
        }
    
        public static Config Open(Config config)
        {
            var text = File.ReadAllText(config.FileLocation);
            Config openedCfg = JsonConvert.DeserializeObject<Config>(text);
            return openedCfg;
        }
    }
    

    对 ConfigurationBox 的引用是一个自定义控件:

    加载配置后它看起来像:

    显然它很粗略,但它应该提供你做类似事情所需的所有基础知识。

    【讨论】:

    • 嗨,非常感谢。我还不熟悉 JSON,但我想我必须深入了解它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 2021-08-25
    相关资源
    最近更新 更多