Das ViewModel ist ein Bestandteil des Patterns MVVM. Dieser Beitrag gibt eine Einführung in dieses Thema und zeigt ebenfalls eine praxisnahe Verwendung anhand von Beispielen auf.

Kürzlich habe ich eine Anfrage erhalten, was die einzelnen Objekte, welche durch das Pattern MVVM beschrieben werden, tatsächlich beinhalten. Darauf möchte ich kurz mit meiner Interpretation dieses Patterns eingehen und zur Diskussion stellen.

Die weiteren Bestandteile des MVVM-Patterns:
Die View
Das Model

Definition ViewModel

Das ViewModel stellt das Model für die View dar. Es gibt das eigentliche Model nach außen. Darauf kann per Datenbindung gebunden werden. Durch die im Model implementierte Change Notification werden Änderungen direkt an die View weitergeben. Code, der dies manipuliert, ist nicht notwendig. Ebenfalls stellt das ViewModel Funktionalitäten per Commands zur Verfügung. Diese werden durch die View ebenfalls gebunden, wodurch in der View kein Code dafür anfällt.

Besonders wichtig ist, dass das ViewModel nicht mit einem Code-behind verwechselt werden darf. Es ist nicht gestattet, Referenzen auf Elemente der View zu erstellen und auf diese zuzugreifen. Dies würde eine direkte Abhängigkeit erzeugen und den Versuch des Trennens und der losen Kopplung per Datenbindung ad absurdum führen. Muss auf UI-Elemente zugegriffen werden, dann ist das Code-behind der View die korrekte Stelle.

Auflistungen von modifizierbaren Objekten sind über ObservableCollection<> nach außen zu geben. Durch diese Klasse können Änderungen an der Auflistung erkannt und an das Binding System weitergegeben werden, ohne dafür zusätzlichen Code schreiben zu müssen.

Das ViewModel selbst bietet durch die Abstraktion der View die Möglichkeit an, alle angebotenen Funktionalitäten per Testing abzudecken. Der umständliche Weg, die Funktionen über Views zu testen, entfällt hierdurch.

Beispielhaftes ViewModel

Eine einfache Basisklasse für ViewModels könnte folgendermaßen aussehen:

public class ViewModelBase : INotifyPropertyChanged
{
    protected void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Und so eine konkrete Implementierung:

public class CompanyViewModel : ViewModelBase
{
    private CompanyModel model;

    public CompanyModel Company
    {
        get { return model; }
        set
        {
            if (model == value)
                return;
            model = value;
            RaisePropertyChanged("Company");
        }
    }
}

Zu ergänzen ist an dieser Stelle, dass das ViewModel zuständig ist, die Daten zu laden (bzw. diesen Teil der Logik aufzurufen). Ebenfalls werden Commands für die unterschiedlichsten Funktionalitäten zur Verfügung gestellt.

Weiterführende praxisrelevante Informationen bieten diese Beispiele:
Lose Kommunikation zwischen ViewModels
Lose Kommunikation zwischen ViewModels 2
Binden von ViewModels via Locator
Binden von ViewModels via Locator 2

Über den Autor

Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler und Fotograf. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.

8 Kommentare

  • Hallo Norbert,

    vielen Dank für diesen sehr Interessanten Blog.
    Mir stellt sich noch die Frage wie ich es Löse, wenn ich in meinem ViewModel als Eigenschaft ein Frameworkelement habe, das dieses entsprechend an zB. ein Canvas gebunden wird.
    Ich stehe dort im Moment ein wenig auf dem Schlauch wie ich dies Elegant löse…

    Grüße Michael

  • Dein ViewModel darf keine Eigenschaft vom Typ FrameworkElement haben. Das ViewModel ist kein Code-behind und darf auch nicht so behandelt werden. Das FrameworkElement gehört in die View.

    Was willst du denn machen? Vermutlich läßt sich dein Vorhaben über ein DataTemplate lösen.

  • Ja da liegt mein Dilemma.

    Ich habe einen Screen, welcher unterschiedliche "Sektoren" anzeigen soll.
    Diese Sektoren sind UIElemente welche wiederum aus unterschiedlichen Background und Content bestehen.
    Dementsprechend Weiß ich vorab nicht Wieviele Sektoren ich zur Laufzeit habe.

    Meinst du, das ich entsprechend in meinem Screen ein Itemscontrol habe, in welchem ich mit meinem DataTemplate die Sektoren Darstelle ( über bindings bezüglich position, größen, etc )?
    Ich stehe zur Zeit noch recht am Anfang vom MVVM, und stolpere daher leider noch über einige Sachen…

    Entwickelt wird dies übrigens mit Silverlight 4, falls dies wichtig ist.

  • Deine Sektoren sind aber für die Anzeige von Daten zuständig, oder? Vermutlich ähnliche Daten, aber eben nicht dieselben? Eventuell mit gemeinsamer Basisklasse?

    Dein ViewModel gibt die eigentlichen Datenobjekte (idealerweise wieder als ViewModel) nach aussen. Dazu brauchst du dann noch für den entsprechenden Typ ein entsprechendes DataTemplate, welches beschreibt, wie das einzelne Objekt darzustellen ist. Deine Sektoren selbst kannst du per Collection nach aussen geben, die Darstellung übernimmt ein ItemsControl (ListView, etc.).

    Damit hat dein ViewModel mit UI-Elementen nichts am Hut, du bist lose gekoppelt und kannst die Darstellung der einzelnen Objekttypen jederzeit über ein ResourceDictionary ändern.

    Hoffe, das hilft dir soweit weiter.

  • Ja, du hast recht, hatte auch diesen Lösungsansatz gestern noch umgesetzt.
    War vorher davon ausgegangen, das ich FrameworkElement in meinem Viewmodel nutzen kann, solange sie nicht eine direkten zusammenhang mit der View haben.
    In dem Aufbau konnte ich durchaus ohne Probleme view und Model trennen um zB eine andere View zu nutzen.
    Ich danke Dir für deine Hilfe, man lernt ja nie aus.

    Ich wünsche ein weiteres schönes Wochende und bin mal gespannt was man als nächstes in Deinem Blog lesen kann.

    Grüße aus dem Norden,

    Michael

  • Hallo,

    erstmal ist zu sagen, dass dies ein sehr guter Artikel ist, welche viele Hilfestellungen bietet.
    Allerdings geht mir eine Sache nicht ganz auf bzw. verstehe ich diesen Aspekt noch nicht so ganz.

    Wie schaffe ich es, meine Daten aus dem Model mithilfe des ViewModels an meine View zu binden? Ich habe es nach deinen Beispielen versucht, allerdings ohne Erfolg.

    Mein Model ähnelt deinem CompanyModel und mein ViewModel ist auf dieses angepasst. Nun habe ich mein mein ViewModel via Locator an die View gebunden, allerdings werden meine Properties nicht gelesen oder beschrieben.

    Der DataContext, also das ViewModel, wird auch gefunden. Allerdings ist das Model standardmäßig null. Auch durch ein instanziieren des Models im ViewModel konnte ich keine Änderung herbeiführen.

    Kannst du mir weiterhelfen?
    MfG
    Raiko

  • Schwer zu sagen, da ich deinen Aufbau nicht kenne.

    Das ViewModel selbst muss zusehen, dass die notwendigen Daten (Model) geladen wird. Wird das Laden derselben ausgeführt und zwar zum richtigen Zeitpunkt? Mir erscheint es so zu sein, dass deine Daten durch das ViewModel gar nicht oder zu einem zu späten Zeitpunkt geladen werden.

    Eventuell wirfst du darauf einen Blick …

  • Hallo,

    ich habe vor ca. 30min zum Laden der Daten bekommen, allerdings weiß ich jetzt nicht ob das noch MVVM "konform" ist.

    Um genau zu sein Binde ich meine Objekt wie folgender maßen an meine View.

    <Textbox Text="{Binding Path=CompanyModel.Street , Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

    Das Initialisieren des Objekts, sowie das setzen des DataContexts auf das ViewModel ist an diesem Punkt bereits abgeschlossen und das Binding wird erfolgreich vollzogen.

    Aber ist das noch MVVM konform?

Hinterlasse einen Kommentar