2010-08-28 27 views
7

Estoy diseñando una aplicación para una biblioteca. No es una biblioteca a gran escala, sino una biblioteca a muy pequeña escala donde mi principal tarea es simplemente mantener la información sobre los libros. Pero esta aplicación de biblioteca debería poder adaptarse a la biblioteca privada de cualquier profesional. Por ejemplo, para un abogado, aparte de la información básica sobre el libro (título, autor, editor, etc.), puede haber otros campos especiales asociados con un libro (Número de caso, Número de tribunal, etc.). Un médico puede tener algunos otros atributos especiales para un libro. Lo mismo ocurre con otras profesiones.Generación de IU dinámica en C#

Así que voy a utilizar una base de datos SQL Server CE y espero tener una tabla BOOK con los atributos habituales y bajo demanda ALTERAR la tabla para satisfacer las necesidades especiales (agregar más columnas).

Pero mi preocupación es generar la GUI dinámicamente para admitir los nuevos atributos.

¿Hay algún enfoque para abordar la generación dinámica de GUI?

yo no estoy pidiendo código completo (que obviamente no voy a conseguir), pero si usted tiene ningún tipo de codificación para apoyar el enfoque, por favor tenga la amabilidad de publicar él :)

¿Hay algo que debería saber sobre los pros, contras, callejones sin salida, precauciones o advertencias, etc.

+0

¿En qué plataforma está desarrollando para? ¿Móvil? ¿Web? ¿Escritorio? – anonymous

+0

Estoy usando C# para desarrollar para el escritorio. WinForms :) –

Respuesta

5

Por el lado de modelo de datos que @devnull recogido, que está describiendo una implementación de campos personalizados y @devnull está describiendo el modelo EAV.

Hay un buen artículo stackoverflow que cubre los patrones de diseño para los campos personalizados en una aplicación:

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

La elección del modelo de datos y la generación de interfaz de usuario están estrechamente vinculados, por lo que realmente no se puede responder a la interfaz de usuario pregunta de generación hasta que decida su modelo de datos/patrón de campo personalizado. Mi reacción inicial fue la misma que la de @ devnull en el enfoque alternativo, pero realmente no hay una gran solución.

Puede reducir la complejidad si tiene un superconjunto de todos los campos posibles y permite al usuario habilitar/deshabilitar los que son apropiados para su dominio de aplicación. He realizado varias implementaciones de campos personalizados en una aplicación con gente muy inteligente y siempre es difícil. Si entiende el dominio de la aplicación lo suficientemente bien, puede mantenerse alejado de las arquitecturas súper flexibles y ahorrarse un montón de dolor.

Tenga en cuenta que una consideración importante es si tendrán que consultar en los campos personalizados. Es mucho más fácil si no tienes que admitir consultas generales. Simplemente inserta userdate1, usern, etc. y proporciona una tabla de metadatos para las etiquetas.

+0

La consulta desafortunadamente es necesaria para los campos personalizados. IMO, no habrá mucho uso para el campo personalizado si el usuario no puede buscar ¿correcto? –

4

No sé si la alteración dinámica de la tabla es una buena decisión de diseño. En su lugar, podría tener una tabla de búsqueda en la que pueda definir tipos de detalles y una tabla de detalles de libros en la que almacene estos detalles. Luego puede mostrar estos detalles en la sección de edición de libros en forma de una cuadrícula de datos que tiene los tipos de detalles como filas, cada fila tiene una columna en la que debe editar el valor. Por supuesto, el detalle de un libro puede ser algo más que un simple valor de cadena, pero esto se puede manejar con facilidad. Espero haber sido lo suficientemente claro :)

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

Gracias devnull. Esta es una muy buena idea y se me ocurrió algo similar también. Pero el problema es que podré almacenar solo un tipo de datos específico. ¿Le importaría explicar por qué la alteración de la tabla no es una buena decisión de diseño, por favor? :) –

+0

Porque todo lo que dependa de esa tabla debería actualizarse para reflejar esos cambios. Tener un esquema fijo y consistente permite una separación limpia entre el almacén de datos y la aplicación. Si planea escribir una aplicación web que funcione con la misma base de datos, deberá duplicar el código que maneja la actualización del esquema de la base de datos. – devnull

+0

más 1 para alterar dinámicamente la tabla es una mala decisión de diseño –

3

Hay muchas herramientas de generación de código disponibles. Algunos de ellos generan código con GUI fácilmente utilizable.

MyGeneration

CodeNGen

CodeSmith

IgnyteDataLayerGen

NetGenerationCodeGen

OxyGen Code Generator

.NetTiers

CodeThatBuilder

CslaGenerator

CodeBreeze

Como alternativa, los siguientes códigos puede hacer su vida más fácil.

Usted puede tener una forma de base general para entidades como esta:

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

Y una forma de base general para las colecciones:

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

Entonces todas sus formas tendrá la misma apariencia generales:

alt text

Cuestiones relacionadas