Динамическая генерация пользовательского интерфейса в C#

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

поэтому я собираюсь использовать базу данных SQL Server CE, и я надеюсь иметь таблицу книг с обычными атрибутами и по требованию изменить таблицу в соответствии с особыми потребностями (добавить больше столбцов).

но мое беспокойство генерирует GUI динамически для поддержки новых атрибутов.

существуют ли какие-либо подходы к решению динамического поколения GUI?

Я не прошу полный код (который, очевидно, я не получу), но если у вас есть какое-либо кодирование для поддержки подхода, пожалуйста, будьте любезны опубликовать его:)

есть ли что-нибудь, что я должен знать о плюсах, минусах, тупиках, предостережениях или предупреждениях и т. д.?

4 ответов


на стороне модели данных, которую @devnull подобрал, вы описываете реализацию пользовательских полей, а @devnull описывает ЕАВ модель.

есть хорошая статья stackoverflow, которая охватывает шаблоны проектирования для пользовательских полей в приложении:

какие шаблоны проектирования для поддержки пользовательских полей в приложении?

выбор модели данных и поколение пользовательского интерфейса тесно связаны, поэтому вы не можете ответить на Вопрос генерации пользовательского интерфейса, пока вы не решите модель данных / шаблон настраиваемого поля. Моя первоначальная реакция была такой же, как у @devnull на альтернативном подходе, но на самом деле нет отличного решения.

вы можете уменьшить большую сложность, если у вас есть надмножество всех возможных полей и разрешить пользователю включать/отключать те, которые подходят для их домена приложения. Я сделал несколько реализаций пользовательских полей в приложении с очень умными людьми, и это всегда трудный. Если вы достаточно хорошо понимаете домен приложения, вы можете держаться подальше от гибких архитектур uber и сэкономить много горя.

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


Я не знаю, является ли динамическое изменение таблицы хорошим дизайнерским решением. Вместо этого можно создать таблицу подстановки, в которой можно определить типы сведений, и таблицу сведений о книгах, в которой будут храниться эти сведения. Затем вы можете отобразить эти сведения в разделе редактирования книги в виде datagrid, который имеет типы сведений в виде строк, каждая строка имеет столбец, в котором вы будете редактировать значение. Конечно, детализация книги может быть чем угодно, кроме простого строкового значения, но это смогите быть обращано легко. Надеюсь, я был достаточно ясен :)

-------------           -----------------          ----------------
|  Books    |           |  BooksDetail  |          |  DetailTypes |
-------------           -----------------          ----------------
| ID (PK)   | 1      n  | ID (PK)       | 1     1  | ID (PK)      |
| AuthorID  | --------> | BookID        | -------> | Name         |
| Title     |           | DetailID      |          | Description  |
| Year      |           | Value         |          ----------------
-------------           -----------------

доступно множество инструментов генерации кода. Некоторые из них генерируют код с легко используемым GUI.

MyGeneration

CodeNGen

CodeSmith

IgnyteDataLayerGen

NetGenerationCodeGen

Кислород Код Генератор

.NetTiers

CodeThatBuilder

CslaGenerator

CodeBreeze

в качестве альтернативы следующие коды могут сделать вашу жизнь проще.

вы можете иметь общую базовую форму для таких объектов:

public partial class BaseForm : Form
    {
        ///////////Event Mechanism///////////
        protected internal event ItemStateChanged ItemStateChangeEvent;
        protected internal void OnItemStateChanged()
        {
            if (ItemStateChangeEvent != null)
            {
                ItemStateChangeEvent();
            }
        }
        ///////////Event Mechanism///////////

        protected internal Label ErrorMessageTextBox 
        {
            get { return this.errorMessageTextBox; }
            set { this.errorMessageTextBox = value; }
        }

        protected internal ToolStripStatusLabel TotalToolStripStatusLabel
        {
            get { return this.totalToolStripStatusLabel; }
            set { this.totalToolStripStatusLabel = value; }
        }

        protected internal FormViewMode FormViewMode { get; set; }

        public BaseForm()
        {
            InitializeComponent();
        }
    }

и общая базовая форма для коллекций:

public partial class CollectionBaseForm : BaseForm
    {
        protected internal ToolStripMenuItem ReportMenu { get { return this.reportsToolStripMenuItem; } set { this.reportsToolStripMenuItem = value; } }
        protected internal DataGridView DataGridView { get {return this.dataGridView1 ;} set {dataGridView1 = value ;} }
        protected internal Button SearchButton { get { return btnSearch; } set { btnSearch = value; } }
        protected internal Button AddNewButton { get { return btnAddNew; } set { btnAddNew = value; } }
        protected internal Button EditButton { get { return btnEdit; } set { btnEdit = value; } }
        protected internal Button DeleteButton { get { return btnDelete; } set { btnDelete = value; } }
        protected internal Button PickButton { get { return btnPick; } set { btnPick = value; } }

        private FormViewMode _formViewMode;
        public FormViewMode FormViewMode 
        {
            get 
            {
                return _formViewMode;
            }
            set
            {
                _formViewMode = value;

                EnableDisableAppropriateButtons(_formViewMode);
            }
        }

        private void EnableDisableAppropriateButtons(FormViewMode FormViewMode)
        {
            if (FormViewMode == FormViewMode.Collection)
            {
                AddNewButton.Enabled = true;
                EditButton.Enabled = true;
                DeleteButton.Enabled = true;
                PickButton.Enabled = false;
            }
            else if (FormViewMode == FormViewMode.Picker)
            {
                AddNewButton.Enabled = false;
                EditButton.Enabled = false;
                DeleteButton.Enabled = false;
                PickButton.Enabled = true;
            }
        }

        public CollectionBaseForm()
        {
            InitializeComponent();

            this.MaximumSize = this.MinimumSize = this.Size;

            this.FormViewMode = FormViewMode.Collection;
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
        }            
    }

тогда все ваши формы будут иметь то же самое генерал смотрит:

alt text


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

http://zxtrix.wordpress.com/2010/11/13/automatic-winforms-ui-generation-from-object-metadata/