Wie kann ich ohne Duplizierung Code unveränderliche Objekte in WPF bearbeiten?

StackOverflow https://stackoverflow.com/questions/862209

  •  21-08-2019
  •  | 
  •  

Frage

Wir viel unveränderlicher Wert Objekte in unserem Domain-Modell haben, ein Beispiel dafür ist eine Position, definiert durch eine Breite, Länge und Höhe.

/// <remarks>When I grow up I want to be an F# record.</remarks>
public class Position
{
    public double Latitude
    {
        get;
        private set;
    }

    // snip

    public Position(double latitude, double longitude, double height)
    {
        Latitude = latitude;
        // snip
    }
}

Die offensichtliche Art und Weise der Bearbeitung einer Position zu ermöglichen, ist eine Ansichtsmodell zu bauen, die Getter hat und Einrichter, sowie eine ToPosition () Methode die validierte unveränderliche Position Instanz zu extrahieren. Während diese Lösung wäre in Ordnung, es in einer Menge von duplizierten Code führen würde, insbesondere XAML.

Die Wertobjekte in Frage bestehen aus drei bis fünf Eigenschaften, die in der Regel eine Variante von X, Y, Z & einigen Hilfs Sachen sind. Vor diesem Hintergrund hatte ich drei Viewmodel betrachtet zu schaffen, die verschiedenen Möglichkeiten zu handhaben, wobei jedes Ansichtsmodell benötigen würde Eigenschaften für den Wert jeder Eigenschaft sowie eine Beschreibung belichten für jedes Etikett (zB. „Latitude“) angezeigt werden.

Weiter zu gehen, scheint es, wie ich es zu einem allgemeinen Ansichtsmodell vereinfachen könnte, die mit N Eigenschaften und Haken alles up mit Reflexion umgehen können. So etwas wie ein Eigenschaftenraster, aber für unveränderliche Objekte. Ein Problem mit einem Eigenschaftenraster ist, dass ich mag in der Lage sein, um das Aussehen zu ändern, so dass ich Etiketten und Textfelder haben kann wie zum Beispiel:

Latitude:   [      32 ]  <- TextBox
Longitude:  [     115 ]
Height:     [      12 ]

oder legen Sie sie in einem Datagrid wie:

Latitude  |  Longitude  |  Height
      32           115         12

Also meine Frage ist:

Können Sie sich eine elegante Möglichkeit, dieses Problem zu lösen? Gibt es Bibliotheken, die diese oder Artikel über etwas Ähnliches tun?

Ich bin in erster Linie auf:

  • Code-Duplizierung minimiert werden
  • Einfache neue Wert Objekttypen
  • hinzufügen
  • Mögliche mit irgendeiner Art von Validierung
  • erweitern
War es hilfreich?

Lösung

Ich fand diese alte Frage, während meine möglichen Optionen in der gleichen Situation zu erforschen. Ich dachte, ich es für den Fall, jemand anderes stolpert auf, um es zu aktualisieren soll:

Eine weitere Option (nicht verfügbar, wenn Paul seine Lösung angeboten, da .Net 4 noch nicht aus war) ist die gleiche Strategie zu verwenden, sondern es CustomTypeDescriptors mit der Umsetzung eine Kombination von Generika, dynamischen Objekten und Reflexion verwenden zu erreichen die gleiche Wirkung.

In diesem Fall definieren Sie eine Klasse

class Mutable<ImmutableType> : DynamicObject
{
   //...
}

Es ist Konstruktor eine Instanz der unveränderlichen Typ und einem Delegierten, die eine neue Instanz davon aus einem Wörterbuch konstruiert, wie in Paul Antwort. Der Unterschied ist jedoch, dass Sie die TryGetMember und TrySetMember außer Kraft setzen ein internes Wörterbuch zu füllen, die Sie schließlich als Argument für den Konstruktor-Delegierten nicht benutzen wollen. Sie verwenden Reflektion, um zu verifizieren, dass die einzigen Eigenschaften, die Sie akzeptieren sind diejenigen, die in ImmutableType tatsächlich umgesetzt werden.

Performance weise, ich wette, dass Paulus die Antwort schneller ist, und umfasst keine dynamische Objekte, von denen bekannt ist C # -Entwickler in Passungen zu setzen. Aber die Implementierung für diese Lösung ist auch ein wenig einfacher, weil Typdeskriptoren ein bisschen obskur ist.


Hier ist die angeforderte Proof-of-Concept- / Beispielimplementierung:

https://bitbucket.org/jwrush/mutable-generic-example

Andere Tipps

Benutzerdefinierte Typdeskriptoren könnte dieses Problem zu lösen, verwendet werden. Bevor Sie in eine Position zu binden, könnte Ihr Typdeskriptor in kicken und bekommen und stellen Methoden zur Verfügung stellen, um vorübergehend die Werte aufzubauen. Wenn die Änderungen übernommen werden, könnte es das unveränderliche Objekt bauen.

Es könnte wie folgt aussehen:

DataContext = new Mutable(position, 
    dictionary => new Position(dictionary["lattitude"], ...)
);

Ihre Bindungen können noch wie folgt aussehen:

<TextBox Text="{Binding Path=Lattitude}" />

Da das Veränderliche Objekt ‚vorgeben‘ Eigenschaften wie Lattitude dank seinen TypeDescriptor zu haben.

Alternativ einen Konverter in Ihren Bindungen Sie vielleicht verwenden und mit irgendeiner Art von Konvention kommen.

Ihre Mutable Klasse würde das aktuelle unveränderliche Objekt und ein Func<IDictionary, object>, dass Sie das neue unveränderliche Objekt erstellen kann, sobald die Bearbeitung abgeschlossen ist. Ihre Mutable Klasse würde die Verwendung des Typdeskriptor machen, der propertyDescriptors schaffen würde, die das neue unveränderliche Objekt auf gesetzt werden erstellen.

Für ein Beispiel dafür, wie Typdeskriptoren zu verwenden, finden Sie hier:

http://www.paulstovell.com/editable-object-adapter

Bearbeiten : Wenn Sie einschränken möchten, wie oft Ihre unveränderliche Objekte erstellt werden, können Sie bei BindingGroups und IEditableObject sehen auch, was Ihre Mutable auch umsetzen können.

  

Können Sie sich eine elegante Möglichkeit, dieses Problem zu lösen?

Ehrlich gesagt, man muss nur um das Problem tanzen, aber nicht erwähnen, das Problem selbst.;)

Wenn ich das richtig das Problem denkt, dann ist die Kombination von Multibinding und IMultiValueConverter sollte es tun.

HTH.

P. S. BTW, haben Sie unveränderliche Klasse Instanzen, nicht Wertobjekte. Mit Wertobjekten (die durch struct Schlüsselwort beschrieben werden) würden Sie tanzen viel mehr, egal ob es Setter oder nicht.)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top