开发者

Dynamic UI Generation in C#

I am designing an application for a library. Not a large scale library, but a very small scale library where my primary task is to just keep information about the books. But this library application should be able to adapt to any professional's private library. For an example, for a lawyer, apart from the basic information about the book (title, author, publisher etc), there maybe other special fields that is associated w开发者_如何学Goith a book (Case Number, Court Number etc). A doctor may have some other special attributes for a book. Same goes for other professions.

So I am going to use an SQL Server CE database and I am hoping to have a BOOK table with the usual attributes and on demand ALTER the table to suit the special needs (add more columns).

But my worry is generating the GUI dynamically to support the new attributes.

Are there any approaches to tackle the dynamic GUI generation?

I am not asking for complete code (which obviously I wont get), but if you do have any coding to support the approach, please be kind enough to post it :)

Is there anything I should know about the pros, cons, dead ends, cautions or warnings etc?


On the data model side that @devnull picked up, you are describing a custom fields implementation and @devnull is describing the EAV model.

There's a good stackoverflow article that covers design patterns for custom fields in an application:

What are design patterns to support custom fields in an application?

The data model choice and the UI generation are tightly linked, so you can't really answer the UI generation question until you decide on your data model/custom field pattern. My initial reaction was the same as @devnull's on the alter approach, but there really is no great solution.

You can reduce a lot of complexity if you have a superset of all possible fields and allow the user to enable/disable the ones that are appropriate to their application domain. I've done several implementations of custom fields in an application with very smart people and it's always hard. If you understand the application domain well enough you can stay away from the uber-flexible architectures and save yourself a lot of grief.

Note that an important consideration is whether they will need to query on the custom fields. It's much easier if you don't have to support general querying. You just slot userdate1, usern, etc. and provide a metadata table for labels.


I don't know if altering the table dynamically is a good design decision. You could instead have a lookup table in which you can define detail types, and a books detail table in which you would store these details. Then you can display these details in the book editing section in the form of a datagrid that has the detail types as rows, each row having a column in which you would edit the value. Of course, the detail of a book can be anything else than a simple string value but this can be handled with ease. Hope i was clear enough :)

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


There are lots of code generation tools available. Some of them generates code with readily usable GUI.

MyGeneration

CodeNGen

CodeSmith

IgnyteDataLayerGen

NetGenerationCodeGen

OxyGen Code Generator

.NetTiers

CodeThatBuilder

CslaGenerator

CodeBreeze

Alternatively the following codes can make your life more easier.

You can have a general base form for entities like this:

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();
        }
    }

And a general base form for Collections:

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);
        }            
    }

Then all of your forms will have the same general looks:

Dynamic UI Generation in C#


This might help, its not dynamic but it could be adapted easily enough..

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜