Автоматическое создание пользовательского интерфейса на основе переданного класса - PullRequest
0 голосов
/ 02 ноября 2018

это может быть очень простой вопрос, но я ломаю голову над этим уже несколько месяцев. Я хочу создать простой интерфейс для создания объектов класса, который я передаю в конструктор интерфейса. Допустим, у меня есть 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);
        }
    }

Это вообще возможно? Я надеюсь, что я не был смутным с кодом макета, и вы можете понять, к чему я клоню. Любой совет будет высоко оценен. Большое спасибо:)

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Хм, похоже на то, что может помочь решить старая демка:

Примечание. Я использую JSON и библиотеку JSON NewtonSoft для своей реализации, чтобы прочитать JSON и построить объект / пользовательский интерфейс из этого:

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 - это пользовательский элемент управления:

enter image description here

А после загрузки конфига это выглядит так:

enter image description here

Очевидно, что это грубо, но оно должно предоставить все основы, которые вам нужны, чтобы сделать что-то подобное.

0 голосов
/ 02 ноября 2018

Да, это возможно. Я сделал именно это с целью автоматического создания диалоговых окон настроек (я устал от создания пользовательской формы каждый раз, когда в одной из моих программ были настройки, которые пользователь должен был изменить).

Как?

Вам нужно изучить «отражение», которое дает вам возможность динамически опрашивать структуру объектов.

Я не использую для этого дженерики, а скорее запрашиваю Тип из класса.

Если я передаю Test1 в мой класс, я получаю это:

enter image description here

Хотел бы я предоставить исходный код, но, увы, он принадлежит моему работодателю. Однако я могу предоставить короткий фрагмент, чтобы вы могли начать:

  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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...