2012-02-21 1 views
2

КонтекстСоветы по генерации GUI из C# атрибутов в WinForms

У меня есть очень большое количество мелких классов или структур. Детали реализации этих классов не важны, но для каждого из них будет несколько простых встроенных свойств типа данных, которые я хочу выставить, чтобы их можно было отредактировать в элементе управления 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. И, наконец, я никогда раньше не использовал пользовательские атрибуты. Любой хороший пример, чтобы начать меня?

ответ

2

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

Пользовательские атрибуты могут идентифицировать свойства, которые должны отображаться в форме. Затем форма может генерировать элементы управления для этих свойств и использовать привязку данных для привязки элемента управления к свойству объекта.

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, так что вы знаете «где», для размещения элемента управления в сетке. Этот пример основан на пяти колоннах, будучи этикетки, контроль, распорка, этикетка, контроль):

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); 
+0

Спасибо, ты прибил его! На самом деле выглядит довольно просто, я ожидал, что это будет более сложным. –

1

То, что вы описываете, очень похоже на PropertyGrid.

+0

Это хороший момент, и я понимаю, что, возможно, оставил некоторую информацию из моего вопроса. Сначала я подумал, что сначала использую сетку свойств, но то, что я действительно хочу здесь, - это взглянуть, более знакомый обычному пользователю компьютера, например форме, с метками/текстовыми полями/списками/большими элементами управления. В сетке свойств есть ощущение «программистов» и общий сжатый вид, которого я хочу избежать в этом сценарии. –

+0

Достаточно честный. В этом случае ответ Quip выглядит довольно хорошо. Вероятно, вы также должны предоставить механизм, позволяющий подключать пользовательский интерфейс, когда возникнет такая необходимость. Я бы определил интерфейс IEditor, который реализован пользовательским элементом управления, который генерирует ui на основе атрибутов и также может быть реализован с помощью пользовательских элементов управления, специфичных для класса. Затем завод может построить правильную реализацию. –

Смежные вопросы