2010-08-28 8 views
7

Projektuję aplikację dla biblioteki. Nie jest to biblioteka o dużej skali, ale biblioteka o bardzo małej skali, której głównym zadaniem jest przechowywanie informacji o książkach. Ale ta aplikacja biblioteki powinna być w stanie dostosować się do prywatnej biblioteki dowolnego profesjonalisty. Na przykład dla prawnika, oprócz podstawowych informacji o książce (tytuł, autor, wydawca itp.), Mogą być inne specjalne pola związane z książką (numer sprawy, numer sądu itp.). Lekarz może mieć inne szczególne cechy książki. To samo dotyczy innych zawodów.Dynamiczne generowanie interfejsu użytkownika w języku C#

Tak więc zamierzam użyć bazy danych SQL Server CE i mam nadzieję, że będę mieć tabelę BOOK ze zwykłymi atrybutami i na żądanie ZMIENAM tabelę zgodnie ze specjalnymi potrzebami (dodać więcej kolumn).

Ale martwię się dynamicznie generując GUI do obsługi nowych atrybutów.

Czy istnieją jakieś sposoby rozwiązania problemu z dynamicznym generowaniem GUI?

Nie pytam dla kompletnego kodu (co oczywiście nie będę dostać), ale jeśli nie ma żadnego kodowania do wspierania podejścia, należy być na tyle uprzejmy, żeby go :)

zakładać Czy coś powinienem wiedzieć o plusy, minusy, ślepe zaułki, przestrogi i ostrzeżenia itp.?

+0

Co ty platforma rozwija? Mobilny? Sieć? Pulpit? – anonymous

+0

Używam C# do opracowania na pulpit. WinForms :) –

Odpowiedz

5

Na stronie modelu danych, który @devnull podniósł, jesteś opisujące realizację niestandardowych pól i @devnull opisuje model EAV.

Istnieje dobry artykuł stackoverflow, który obejmuje wzorców projektowych dla niestandardowych pól w aplikacji:

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

Wybór modelu danych i generowanie UI są ściśle ze sobą powiązane, tak naprawdę nie można odpowiedzieć na UI generowanie pytania, dopóki nie zdecydujesz o modelu danych/niestandardowym wzorze pola. Moja początkowa reakcja była taka sama jak w przypadku podejścia @ devnull, ale naprawdę nie ma świetnego rozwiązania.

Możesz zmniejszyć wiele złożoności, jeśli masz nadzbiór wszystkich możliwych pól i zezwolić użytkownikowi na włączanie/wyłączanie tych, które są odpowiednie dla ich domeny aplikacji. Zrobiłem kilka implementacji niestandardowych pól w aplikacji z bardzo inteligentnymi ludźmi i zawsze jest to trudne. Jeśli dobrze zrozumiesz domenę aplikacji, będziesz mógł trzymać się z daleka od elastycznych architektur i zaoszczędzić sobie wiele żalu.

Należy zwrócić uwagę, że ważną kwestią jest, czy będą musieli zapytać o niestandardowe pola. Jest to znacznie łatwiejsze, jeśli nie musisz obsługiwać ogólnych zapytań. Po prostu ustaw użytkownika userdate1, usern itd. I podaj tabelę metadanych dla etykiet.

+0

W przypadku pól niestandardowych wymagane jest niestety zapytanie. IMO, pole niestandardowe nie będzie przydatne w przypadku, gdy użytkownik nie będzie mógł przeszukiwać w prawo? –

4

Nie wiem, czy zmiana stołu dynamicznie jest dobrą decyzją projektową. Zamiast tego możesz mieć tabelę odnośników, w której możesz zdefiniować typy szczegółów oraz tabelę szczegółów książek, w której będziesz przechowywać te szczegóły. Następnie możesz wyświetlić te szczegóły w sekcji edycji książki w postaci datagridu, który ma typy szczegółów jako wiersze, a każdy wiersz ma kolumnę, w której chcesz edytować wartość. Oczywiście szczegół książki może być czymkolwiek innym niż zwykłą wartością ciągu znaków, ale można to łatwo obsłużyć. Mam nadzieję, że było wystarczająco jasne :)

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

Dziękuję devnull. To bardzo dobry pomysł i wymyśliłem coś podobnego. Ale problem polega na tym, że będę mógł przechowywać tylko określony typ danych. Czy mógłbyś wyjaśnić, dlaczego zmiana stołu nie jest dobrą decyzją projektową? :) –

+0

Ponieważ wszystko w zależności od tej tabeli musiałoby zostać zaktualizowane, aby odzwierciedlić te zmiany. Posiadanie stałego i spójnego schematu umożliwia czyste oddzielenie magazynu danych od aplikacji. Jeśli planujesz napisać aplikację webową działającą z tą samą bazą danych, musisz zduplikować kod obsługujący aktualizację schematu bazy danych. – devnull

+0

plus 1 do dynamicznego zmieniania tabeli jest złym decyzją w zakresie projektowania –

3

Dostępnych jest wiele narzędzi do generowania kodu. Niektóre z nich generują kod z łatwo dostępnym GUI.

MyGeneration

CodeNGen

CodeSmith

IgnyteDataLayerGen

NetGenerationCodeGen

OxyGen Code Generator

.NetTiers

CodeThatBuilder

CslaGenerator

CodeBreeze

Alternatywnie następujące kody mogą uczynić swoje życie bardziej łatwiejsze.

Można mieć ogólną formę bazową dla podmiotów takich jak ten:

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

oraz ogólnej postaci bazowej dla kolekcji:

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

Następnie wszystkich formach będą miały te same ogólne wygląd:

alt text