2010-08-28 3 views
7

Je suis en train de concevoir une application pour une bibliothèque. Pas une bibliothèque à grande échelle, mais une bibliothèque à très petite échelle où ma tâche principale est de garder des informations sur les livres. Mais cette application de bibliothèque devrait pouvoir s'adapter à la bibliothèque privée de n'importe quel professionnel. Par exemple, pour un avocat, outre les informations de base sur le livre (titre, auteur, éditeur, etc.), il peut y avoir d'autres champs spéciaux associés à un livre (numéro de dossier, numéro de tribunal, etc.). Un médecin peut avoir d'autres attributs spéciaux pour un livre. Idem pour les autres professions.Génération d'interface utilisateur dynamique en C#

Donc je vais utiliser une base de données SQL Server CE et j'espère avoir une table BOOK avec les attributs habituels et ALTER la table à la demande pour répondre aux besoins spéciaux (ajouter plus de colonnes).

Mais mon souci est de générer dynamiquement l'interface graphique pour supporter les nouveaux attributs.

Y a-t-il des approches pour s'attaquer à la génération de l'interface graphique dynamique?

Je ne demande pas de code complet (qui, évidemment, je reçois l'habitude), mais si vous avez tout codage pour soutenir l'approche, s'il vous plaît de bien vouloir poster :)

Est-ce que je devrais savoir sur les avantages, les inconvénients, les impasses, les mises en garde ou les avertissements, etc.?

+0

Quelle plate-forme vous développez pour? Mobile? Web? Bureau? – anonymous

+0

J'utilise C# pour développer pour le bureau. WinForms :) –

Répondre

5

Du côté du modèle de données qui @devnull pris en charge, vous décrivez un champs personnalisés et la mise en œuvre @devnull modèle décrit la EAV.

Il y a un bon article stackoverflow qui couvre les modèles de conception pour les champs personnalisés dans une application:

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

Le choix du modèle de données et la génération de l'interface utilisateur sont étroitement liés, de sorte que vous ne pouvez pas vraiment répondre à l'interface utilisateur question de génération jusqu'à ce que vous décidiez de votre modèle de données/modèle de champ personnalisé. Ma réaction initiale était la même que celle de @ devnull sur l'approche alter, mais il n'y a vraiment pas de bonne solution.

Vous pouvez réduire la complexité si vous disposez d'un sur-ensemble de tous les champs possibles et que vous permettez à l'utilisateur d'activer/désactiver ceux qui sont appropriés à son domaine d'application. J'ai fait plusieurs implémentations de champs personnalisés dans une application avec des gens très intelligents et c'est toujours difficile. Si vous comprenez bien le domaine d'application, vous pouvez rester loin des architectures ultra-flexibles et vous épargner beaucoup de chagrin. Notez qu'une considération importante est de savoir s'ils devront interroger les champs personnalisés. C'est beaucoup plus facile si vous n'avez pas à gérer les requêtes générales. Vous venez d'insérer userdate1, usern, etc. et de fournir une table de métadonnées pour les étiquettes.

+0

La requête est malheureusement nécessaire pour les champs personnalisés. OMI, il n'y aura pas beaucoup d'utilisation pour le champ personnalisé si l'utilisateur ne peut pas effectuer une recherche à droite? –

4

Je ne sais pas si la modification dynamique de la table est une bonne décision de conception. Vous pouvez à la place avoir une table de recherche dans laquelle vous pouvez définir des types de détail, et une table de détail des livres dans laquelle vous stockez ces détails. Vous pouvez ensuite afficher ces détails dans la section d'édition du livre sous la forme d'une grille de données contenant les types de détail en tant que lignes, chaque ligne ayant une colonne dans laquelle vous modifieriez la valeur. Bien sûr, le détail d'un livre peut être autre chose qu'une simple valeur de chaîne, mais cela peut être facilement géré. Espoir que j'été assez clair :)

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

Je vous remercie devnull. C'est une très bonne idée et j'ai trouvé quelque chose de similaire aussi. Mais le problème est que je ne pourrai stocker qu'un type de données spécifique. Pourriez-vous expliquer pourquoi la modification de la table n'est pas une bonne décision de conception s'il vous plaît? :) –

+0

Parce que tout ce qui dépend de cette table devrait être mis à jour pour refléter ces changements. Avoir un schéma fixe et cohérent permet une séparation nette entre le magasin de données et l'application. Si vous envisagez d'écrire une application Web qui fonctionne avec la même base de données, vous devrez dupliquer le code qui gère la mise à jour du schéma de base de données. – devnull

+0

plus 1 pour modifier dynamiquement la table est une mauvaise décision de conception –

3

De nombreux outils de génération de code sont disponibles. Certains d'entre eux génère du code avec une interface utilisateur facilement utilisable.

MyGeneration

CodeNGen

CodeSmith

IgnyteDataLayerGen

NetGenerationCodeGen

OxyGen Code Generator

.NetTiers

CodeThatBuilder

CslaGenerator

CodeBreeze

Vous pouvez également les codes suivants peuvent vous rendre la vie plus facile.

Vous pouvez avoir une forme de base générale pour les entités comme celle-ci:

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

Et une forme de base générale des 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); 
     }    
    } 

Alors tous vos formulaires auront les mêmes regards généraux:

alt text

Questions connexes