2013-05-02 4 views
10

Dies ist eher eine Frage Architektur/Design.Wie vermeidet man eine Databinding/Ereignishölle auf einem komplexen Bildschirm?

Ich habe ein paar Projekte in der Vergangenheit in WPF/Windows Forms, etc., die komplexe Bildschirme mit vielen Feldern haben und diese Felder miteinander verbunden sind (ihre Werte hängen voneinander mit etwas Logik beteiligt).

Diese Projekte habe ich übernommen, nachdem sie implementiert wurden, und ich fand eine Menge Ereignisse/Daten binden Hölle - was ich damit meine ist, dass, weil alle diese Felder abhängig von anderen haben sie INotifyPropertyChanged implementiert und andere Felder sind als Ergebnis verändert werden. Dies führt dazu, dass die gleichen Felder 5-6 mal aktualisiert werden, wenn der Bildschirm geladen wird, und die Reihenfolge, in der die Felder gefüllt sind, verursacht schreckliche Fehler. (Zum Beispiel: Datum vor Jobtyp eingestellt wurde, statt nach Jobtyp, so dass ich am Ende mit einer anderen Job Fee.)

Erschwerend kommt hinzu, einig Hacks umgesetzt auf UI-Ereignisse (z. B. DropDown wurde geändert, um Feld X zu aktualisieren), während andere sich im Domänenmodell befinden, an das die UI gebunden ist.

Im Grunde ist es ein riesiges Durcheinander, und ich möchte nur wissen, was der beste Weg ist, etwas wie das zu implementieren, wenn ich von Null anfangen würde. Oder ist es eine gute Idee, solch einen komplexen Bildschirm überhaupt zu vermeiden?

Antwort

0

Wir haben ziemlich komplexe UIs (einschließlich mehrerer verwandter Felder unterschiedlicher Typen, sagen wir zum Beispiel eine Zeile in einem DataGrid) und das MVVM-Muster hat ziemlich gut für uns gearbeitet. Alle Eigenschaften aus dem Modell kommen und mit dem Blick ausgesetzt, die komplexe Logik verwendet sind „verpackt“ durch eine entsprechende Eigenschaft in dem Ansichtsmodell, das keinen Hintergrund-Feld hat, sondern verweist direkt auf das Modell:

public class SomeComplexViewModel 
{ 

    public SomeModel Model {get;set;} 

    public string SomeCrazyProperty 
    { 
     get 
     { 
      return Model.SomeCrazyProperty; 
     } 
     { 
      Model.SomeCrazyProperty = value; 
      //... Some crazy logic here, potentially modifying some other properties as well. 
     } 
    } 
} 

<TextBox Text="{Binding SomeCrazyProperty}"/> 

Dies beseitigt das "Anfangswert" -Problem, da der Anfangswert, der von der Bindung gelesen wird, tatsächlich der reale Wert ist, der von dem Modell kommt, und daher wird die Logik, die in dem Setter platziert ist, nur bei Bedarf ausgeführt.

Dann wird für Dummy-Eigenschaften (die keine Logik hinter haben), binden wir direkt aus dem Blick auf das Modell:

<TextBox Text="{Binding Model.SomeRegularProperty}"/> 

Diese überflüssigen Ballast im Ansichtsmodell reduziert.

In Bezug auf Ereignisse in den Code hinter, ich vermeide das völlig. Mein Code hinter Dateien ist fast immer ein InitializeComponent() und sonst nichts.

Nur die Ansichts-spezifische Logik wird im Code dahinter platziert (z. B. Animationen usw.), wenn sie nicht direkt in XAML ausgeführt werden kann oder im Code einfacher ist (was meistens nicht der Fall ist)).

Edit:

Es ist wichtig zu erwähnen, dass die WinForms Bindungsfähigkeiten sind ein Witz im Vergleich zu den XAML-basiert sind. Könnte das der Grund sein, dass du diese schrecklichen Verwirrungen in diesen Projekten siehst?

2

Ich würde versuchen, die Geschäftslogik so viel wie möglich aus den Property Setter zu halten.

Wenn zuerst mehrere Eigenschaften für eine Berechnung benötigt werden, schreibe ich eine Methode, die die Berechnung durchführt, und rufe diese Methode gegebenenfalls auf. Z.B. Wenn alle verschiedenen Kombinationen von Eigenschaftswerten sinnvoll sind, könnte man einfach die Methode in den Settors jeder Eigenschaft aufrufen und sicherstellen, dass derselbe Code immer dann ausgeführt wird, wenn eine der Eigenschaften geändert wird. Wenn Sie nur spezielle Kombinationen von Eigenschaftswerten auswerten können, könnten Sie entweder einen Befehl implementieren und den Benutzer entscheiden lassen, wann die resultierenden Änderungen berechnet werden, oder Sie können eine Rückmeldung durch Validierung bereitstellen und die Eigenschaftsänderungen nur dann bewerten, wenn die Kombination gültig ist. Wenn es mehrere voneinander abhängige Eigenschaften gibt, verwende ich oft eine "ChangeInitiator" -Variable, um anzuzeigen, welche Eigenschaft sich geändert hat, so dass in der Berechnungsmethode klar ist, welche Eigenschaft für die Änderung verantwortlich ist und welche anderen sich infolgedessen ändern sollten. Im Grunde genommen ist dies dasselbe wie ein Teil der Berechnung in jedem Property Setter, aber ich finde, dass es mir hilft, einen Überblick zu behalten, wenn die verschiedenen Teile der Beziehung alle in einer Methode sind.

In einem Programm, das ich einmal schrieb, hatte ich einige Berechnungen in einem Hintergrund Thread in regelmäßigen Abständen, so würde ich nur ein Flag setzen, wenn ein Stück Daten, die eine neue Berechnung benötigt, und alle Updates auf einem Timer basieren jede Sekunde oder so ... das könnte Ihnen auch helfen, die Logik geradliniger zu machen, und es vermeidet, dass die Berechnung mehrere Male für eine Reihe verwandter Änderungen ausgeführt wird.

In Bezug auf Änderungsbenachrichtigung, würde ich wirklich versuchen, es nur für die UI Datenbindung zu verwenden.

Verwandte Themen