关于在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; }
}

当然,我需要教我的控制如何解释这些属性。现在是我的实际问题。

具体问题

  1. 这行得通吗
  2. 除了解决我忽略的这个问题,还有更好的选择吗
  3. 如何处理界面中控件的位置或布局
  4. 最后,我以前从未使用过自定义属性。有什么好的例子可以让我开始吗

关于在WinForms中从C#属性生成GUI的提示

是的,这应该有效,我已经构建了类似的东西来生成基于实体的动态搜索对话框。

自定义属性可以标识应该出现在窗体上的属性。然后,窗体可以为这些属性生成控件,并使用数据绑定将控件链接回对象上的属性上。

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。