2010-08-28 21 views
7

Ich entwerfe eine Anwendung für eine Bibliothek. Nicht eine große Bibliothek, sondern eine sehr kleine Bibliothek, in der meine Hauptaufgabe nur darin besteht, Informationen über die Bücher zu behalten. Aber diese Bibliotheksanwendung sollte in der Lage sein, sich an die private Bibliothek eines jeden Fachmanns anzupassen. Zum Beispiel können für einen Anwalt neben den grundlegenden Informationen über das Buch (Titel, Autor, Herausgeber usw.) noch weitere spezielle Felder mit einem Buch verknüpft sein (Fallnummer, Gerichtsnummer usw.). Ein Arzt kann einige andere spezielle Attribute für ein Buch haben. Gleiches gilt für andere Berufe.Dynamische UI-Generierung in C#

Also werde ich eine SQL Server CE-Datenbank verwenden und ich hoffe, eine BOOK-Tabelle mit den üblichen Attributen und auf Anfrage ALTER die Tabelle für die besonderen Bedürfnisse (weitere Spalten hinzufügen) haben.

Aber meine Sorge erzeugt die GUI dynamisch, um die neuen Attribute zu unterstützen.

Gibt es Ansätze, die dynamische GUI-Generierung zu bewältigen?

ich nicht für eine vollständige Code bin zu fragen (was natürlich ich gewohnt), aber wenn Sie eine Codierung zu tun haben, den Ansatz zu stützen, bitte so freundlich sein, es zu schreiben :)

Gibt es etwas, das ich wissen sollte über die Vor-, Nachteile, Sackgassen, Warnungen oder Warnungen usw.?

+0

Welche Plattform für angepasst werden könnten Sie entwickeln? Handy, Mobiltelefon? Netz? Desktop? – anonymous

+0

Ich verwende C#, um für den Desktop zu entwickeln. WinForms :) –

Antwort

5

Auf dem Datenmodell Seite, die nach oben @devnull gepflückt, Sie eine benutzerdefinierten Feldern Implementierung beschreiben und @devnull beschreibt das EAV Modell.

Es gibt einen guten Stackoverflow Artikel, die Design-Muster für benutzerdefinierte Felder in einer Anwendung umfasst:

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

Das Datenmodell Auswahl und die UI-Generation eng miteinander verbunden sind, so dass Sie nicht wirklich die Benutzeroberfläche beantworten können Generierungsfrage, bis Sie sich für Ihr Datenmodell/benutzerdefiniertes Feldmuster entscheiden. Meine erste Reaktion war die gleiche wie @ devnull's auf dem Alter-Ansatz, aber es gibt wirklich keine großartige Lösung.

Sie können eine Menge Komplexität reduzieren, wenn Sie eine Obermenge aller möglichen Felder haben und dem Benutzer erlauben, diejenigen zu aktivieren/deaktivieren, die für seine Anwendungsdomäne geeignet sind. Ich habe mehrere Implementierungen von benutzerdefinierten Feldern in einer Anwendung mit sehr klugen Leuten gemacht und es ist immer schwierig. Wenn Sie die Anwendungsdomäne gut genug verstehen, können Sie sich von den flexiblen Architekturen fernhalten und sich viel Leid ersparen.

Beachten Sie, dass eine wichtige Überlegung ist, ob sie die benutzerdefinierten Felder abfragen müssen. Es ist viel einfacher, wenn Sie allgemeine Abfragen nicht unterstützen müssen. Sie können userdate1, usern usw. einfach in ein Slot einfügen und eine Metadatentabelle für Labels bereitstellen.

+0

Leider ist Abfrage für die benutzerdefinierten Felder erforderlich. IMO, wird es nicht viel für das benutzerdefinierte Feld verwenden, wenn der Benutzer nicht richtig suchen kann? –

4

Ich weiß nicht, ob eine dynamische Änderung der Tabelle eine gute Designentscheidung ist. Sie könnten stattdessen eine Nachschlagetabelle haben, in der Sie Detailtypen definieren können, und eine Buchdetailliste, in der Sie diese Details speichern würden. Anschließend können Sie diese Details im Buchbearbeitungsabschnitt in Form eines Datagrids mit den Detailtypen als Zeilen anzeigen, wobei jede Zeile eine Spalte enthält, in der Sie den Wert bearbeiten würden. Natürlich kann das Detail eines Buches alles andere als ein einfacher String-Wert sein, aber dies kann mit Leichtigkeit gehandhabt werden. Hoffe, dass ich war klar genug :)

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

Vielen Dank devnull. Das ist eine sehr gute Idee und ich habe mir auch etwas Ähnliches ausgedacht. Aber das Problem ist, dass ich nur einen bestimmten Datentyp speichern kann. Würde es Ihnen etwas ausmachen zu erklären, warum die Änderung des Tisches keine gute Designentscheidung ist? :) –

+0

Da alles abhängig von dieser Tabelle aktualisiert werden müsste, um diese Änderungen widerzuspiegeln. Ein festes und konsistentes Schema ermöglicht eine saubere Trennung zwischen dem Datenspeicher und der Anwendung. Wenn Sie vorhaben, eine Webanwendung zu schreiben, die mit derselben Datenbank arbeitet, müssten Sie den Code kopieren, der das Update des Datenbankschemas verarbeitet. – devnull

+0

plus 1 zum dynamischen Ändern der Tabelle ist eine schlechte Design-Entscheidung –

3

Es sind viele Codegenerierungstools verfügbar. Einige von ihnen erzeugen Code mit einer leicht verwendbaren GUI.

MyGeneration

CodeNGen

CodeSmith

IgnyteDataLayerGen

NetGenerationCodeGen

OxyGen Code Generator

.NetTiers

CodeThatBuilder

CslaGenerator

CodeBreeze

Alternativ können die folgenden Codes können Sie Ihr Leben einfacher machen.

Sie können eine allgemeine Grundform für Unternehmen wie diese:

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

und eine allgemeine Grundform für Kollektionen:

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

Dann alle Ihrer Formulare werden das gleiche allgemeine Aussehen haben:

alt text