views:

175

answers:

3

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 with 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 ?

+2  A: 

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         |          ----------------
-------------           -----------------
devnull
Thank you devnull. This is a very good idea and I came up with something similar too. But the problem is that I will be able to store only a specific data type. Would you mind explaining why the altering of the table is not a good design decision please? :)
Ranhiru Cooray
Because everything depending on that table would need to be updated to reflect those changes. Having a fixed and consistent schema allows a clean separation between the data store and the application. If you plan on writing a webapp that works with the same database you would then have to duplicate the code that's handling the database schema update.
devnull
+3  A: 

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:

http://stackoverflow.com/questions/1126783/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.

Rob
Querying unfortunately is required for the custom fields. IMO, there will not be much use for the custom field if the user cannot search right?
Ranhiru Cooray
+1  A: 

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:

alt text

JMSA