关于在WinForms中从C#属性生成GUI的提示
本文关键字:GUI 提示 属性 WinForms 中从 | 更新日期: 2023-09-27 18:25:17
上下文
我有大量的小类或结构。这些类的实现细节并不重要,但对于每一个类,都有一些简单的内置数据类型属性,我想公开这些属性,以便在WinForms控件中编辑它们。不过,每个班级的情况会完全不同。例如:
class SleepAction : IGameAction
{
public float Duration { get; set; }
}
class TeleportCharacterAction : IGameAction
{
public string CharacterId { get; set;
public string DestinationRoomId { get; set; }
public Vector2 DestinationPosition { get; set; }
}
问题是,我想要一个单个WinForms控件,它能够编辑所有对象类型。顶部将有一个所有类类型的下拉列表,当从该下拉列表中选择一个项目时,界面将更改为容纳该类型的属性,并创建该类型的实例来存储数据。
起初,我考虑手工制作每个接口,可能使用一个TabControl
对象,每个类一个选项卡,隐藏选项卡。但后来类的数量呈指数级增长,所以我转向其他解决方案,可能使用属性和反射。我只是不知道该怎么开始。
我现在想的是:
class ActionEditorControl : UserControl
{
void ChangeEditorMode(Type type)
{
// Clear all GUI interface
// Create object of type Type with default constructor
// Use Type metadata to generate new GUI interface
// Databind new interface to object properties
}
object GetObject()
{
// Return current object
}
}
在我的模型对象上,我可以使用属性来添加必要的元数据:
class SleepAction : IGameAction
{
[FieldLabel("Duration")]
[FieldType("NumericSpinner")]
public float Duration { get; set; }
}
class TeleportCharacterAction : IGameAction
{
[FieldLabel("Character")]
[FieldType("CharacterList")]
public string CharacterId { get; set;
[FieldLabel("Room")]
[FieldType("RoomList")]
public string DestinationRoomId { get; set; }
[FieldLabel("Position")]
[FieldType("VectorPicker")]
public Vector2 DestinationPosition { get; set; }
}
当然,我需要教我的控制如何解释这些属性。现在是我的实际问题。
具体问题
- 这行得通吗
- 除了解决我忽略的这个问题,还有更好的选择吗
- 如何处理界面中控件的位置或布局
- 最后,我以前从未使用过自定义属性。有什么好的例子可以让我开始吗
是的,这应该有效,我已经构建了类似的东西来生成基于实体的动态搜索对话框。
自定义属性可以标识应该出现在窗体上的属性。然后,窗体可以为这些属性生成控件,并使用数据绑定将控件链接回对象上的属性上。
TableLayoutPanel可以帮助对生成的控件进行布局。一列可以存储标签对象,第二列可以存储控件(文本框等)。如果您想要更多的列,也可以选择多组。
使用属性
既然你有一个类型,你可以在每个属性中搜索你的特殊属性:
foreach (var property in searchObjectType.GetProperties())
{
var labelAttrib = (FieldLabelAttribute)property.GetCustomAttributes(typeof(FieldLabelAttribute), false).FirstOrDefault();
var typeAttrib = (FieldTypeAttribute)property.GetCustomAttributes(typeof(FieldTypeAttribute), false).FirstOrDefault();
}
表格面板:
一旦你知道你需要构建一个控件,就要弄清楚你要构建什么样的控件:(这假设你有一个带有Order属性的属性,这样你就知道在网格中放置控件的"位置"。这个例子基于五列,分别是label、control、spacer、label和control):
if (type == typeof(string))
{
generatedControl = new Textbox();
generatedControl.DataBindings.Add("Text", myObject, property.Name);
}
然后将控件添加到表中(这假设您创建了一个标签控件):
pnlLayout.Controls.Add(label, (myAttrib.Order % 2 * 3), myAttrib.Order / 2);
pnlLayout.Controls.Add(generatedControl, (myAttrib.Order % 2 * 3) + 1, myAttrib.Order / 2);
您所描述的内容听起来很像PropertyGrid。