这可能是一个非常基本的问题,但自几个月以来,我一直对此表示怀疑。 我想创建一个简单的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);
}
}
这甚至可能吗?我希望我不要对样机代码含糊不清,并且您可以理解我的目标。 任何建议将不胜感激。非常感谢:)
答案 0 :(得分:0)
是的,有可能。我已经完成了这件事,目的是自动创建设置对话框(我厌倦了在自己的程序之一需要用户修改设置的情况下制作自定义表单)。
如何?
您将需要研究“反射”,它为您提供了一种动态询问对象结构的方法。
我不为此使用泛型,而是从类中查询Type。
如果我将Test1
传递给我的班级,我会得到:
我希望我可以提供源代码,但可惜,它属于我的雇主。但是,我可以提供一个简短的摘要来帮助您入门:
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));
答案 1 :(得分:0)
嗯,看起来像是一个旧的演示可以帮助解决的问题:
注意:我正在使用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的引用是一个自定义控件:
在加载配置后,它看起来像:
显然,这很粗糙,但是它应该提供执行类似操作所需的所有基础知识。