2010-08-28 16 views
7

Sto progettando un'applicazione per una libreria. Non una libreria su larga scala, ma una libreria di dimensioni molto ridotte in cui il mio compito principale è quello di mantenere solo le informazioni sui libri. Ma questa applicazione di libreria dovrebbe essere in grado di adattarsi alla biblioteca privata di qualsiasi professionista. Ad esempio, per un avvocato, a parte le informazioni di base sul libro (titolo, autore, editore, ecc.), Potrebbero esserci altri campi speciali associati a un libro (numero di caso, numero di tribunale, ecc.). Un dottore potrebbe avere altri attributi speciali per un libro. Lo stesso vale per altre professioni.Generazione UI dinamica in C#

Quindi ho intenzione di utilizzare un database SQL Server CE e spero di avere una tabella BOOK con i soliti attributi e su richiesta ALTER la tabella per soddisfare le esigenze particolari (aggiungere più colonne).

Ma la mia preoccupazione è generare la GUI in modo dinamico per supportare i nuovi attributi.

Esistono approcci per affrontare la generazione dinamica della GUI?

Non sto chiedendo per il codice completo (che ovviamente non lo vorrei ottenere), ma se si dispone di alcuna codifica a sostenere l'approccio, si prega di essere così gentile da post-it :)

C'è qualcosa che dovrei sapere sui pro, contro, vicoli ciechi, avvertenze o avvertenze, ecc.?

+0

Quale piattaforma stai sviluppando per? Mobile? Web? Desktop? – anonymous

+0

Sto usando C# per lo sviluppo per il desktop. WinForms :) –

risposta

5

Sul lato modello di dati che @devnull raccolto, si sta descrivendo un'implementazione campi personalizzati e @devnull sta descrivendo il modello EAV.

C'è un buon articolo StackOverflow che copre i modelli di progettazione per i campi personalizzati in un'applicazione:

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

Il modello di dati scelta e la generazione di interfaccia utente sono strettamente collegati, quindi non si può davvero rispondere alla UI domanda di generazione fino a quando non decidi sul tuo modello di dati/modello di campo personalizzato. La mia reazione iniziale è stata la stessa di @ devnull sull'approccio alternativo, ma non c'è davvero una grande soluzione.

È possibile ridurre molta complessità se si dispone di un superset di tutti i campi possibili e consentire all'utente di abilitare/disabilitare quelli appropriati al proprio dominio dell'applicazione. Ho fatto diverse implementazioni di campi personalizzati in un'applicazione con persone molto intelligenti ed è sempre difficile. Se capisci bene il dominio dell'applicazione, puoi stare lontano dalle architetture super-flessibili e risparmiarti un sacco di dolore.

Si noti che una considerazione importante è se avranno bisogno di eseguire una query sui campi personalizzati. È molto più semplice se non devi supportare l'interrogazione generale. Basta inserire userdate1, usern, ecc. E fornire una tabella di metadati per le etichette.

+0

La query è purtroppo necessaria per i campi personalizzati. IMO, non ci sarà molto uso per il campo personalizzato se l'utente non può cercare giusto? –

4

Non so se modificare dinamicamente la tabella sia una buona decisione di progettazione. Potresti invece avere una tabella di ricerca in cui è possibile definire i tipi di dettaglio e una tabella dei dettagli dei libri in cui archiviare questi dettagli. Quindi è possibile visualizzare questi dettagli nella sezione di modifica dei libri sotto forma di un datagrid che ha i tipi di dettagli come righe, ogni riga con una colonna in cui si modificherà il valore. Naturalmente, i dettagli di un libro possono essere nient'altro che un semplice valore di stringa, ma questo può essere gestito con facilità. Spero di essere stato abbastanza chiaro :)

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

Grazie devnull. Questa è un'ottima idea e mi è venuta in mente qualcosa di simile. Ma il problema è che sarò in grado di memorizzare solo un tipo di dati specifico. Ti dispiacerebbe spiegare perché l'alterazione del tavolo non è una buona decisione di progettazione, per favore? :) –

+0

Perché tutto ciò che dipende da quella tabella dovrebbe essere aggiornato per riflettere tali cambiamenti. Avere uno schema fisso e coerente consente una separazione netta tra l'archivio dati e l'applicazione. Se si prevede di scrivere una webapp che funziona con lo stesso database, si dovrà quindi duplicare il codice che gestisce l'aggiornamento dello schema del database. – devnull

+0

più 1 per modificare dinamicamente la tabella è una decisione di progettazione errata –

3

Ci sono molti strumenti di generazione del codice disponibili. Alcuni di essi generano codice con GUI facilmente utilizzabile.

MyGeneration

CodeNGen

CodeSmith

IgnyteDataLayerGen

NetGenerationCodeGen

OxyGen Code Generator

.NetTiers

CodeThatBuilder

CslaGenerator

CodeBreeze

In alternativa i seguenti codici possono rendere la vita più facile.

Si può avere una forma di base generale per gli enti di questo tipo:

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

E una forma di base generale per Collezioni:

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

Poi tutte le forme avranno lo stesso aspetto generale:

alt text