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:
Das Model
Das ViewModel
Definition View
Die View stellt das dar, was der Benutzer davon erwartet. So werden reine Daten, Videos und Bilder dargestellt. Benutzereingaben über Tastatur, Maus usw. werden abgefangen und an das ViewModel weitergeleitet.
Im Code-behind der View wird so wenig Code als möglich geschrieben. Es kann aber durchaus erforderlich sein, dies zu tun. Ist das der Fall, dann darf sich der Code nur auf die View beziehen und dieser keine zusätzlichen Abhängigkeiten bringen. Grundsätzlich wird hier mit Datenbindung gearbeitet und so die Möglichkeit geschaffen, die View einfach auszutauschen, ohne Änderungen am Code vornehmen zu müssen.
Beispielhafte View
Nachfolgend findet sich eine mögliche Darstellung der View. Die Basis für die Datenbindung wird durch ein ViewModel dargestellt, welches der Eigenschaft DataContext der View gesetzt wird.
<UserControl x:Class="DevTyr.MvvmObjectsDemo.View.CompanyView"
xmlns="schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Name" Grid.Row="0"/>
<TextBlock Text="Strasse" Grid.Row="1"/>
<TextBlock Text="Hausnummer" Grid.Row="2"/>
<TextBlock Text="Stadt" Grid.Row="3"/>
<TextBlock Text="PLZ" Grid.Row="4"/>
<TextBlock Text="Land" Grid.Row="5"/>
<TextBox Text="{Binding Name}" Grid.Column="1" Grid.Row="0"/>
<TextBox Text="{Binding Street}" Grid.Column="1" Grid.Row="1"/>
<TextBox Text="{Binding StreetNumber}" Grid.Column="1" Grid.Row="2"/>
<TextBox Text="{Binding City}" Grid.Column="1" Grid.Row="3"/>
<TextBox Text="{Binding Zip}" Grid.Column="1" Grid.Row="4"/>
<TextBox Text="{Binding Country}" Grid.Column="1" Grid.Row="5"/>
</Grid>
</UserControl>
Wie das ViewModel in den Datenkontext der View gelangt, zeigt dieser Beitrag.
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
Hallo Norbert,
du beschreibst in diesem Artikel, dass die View am besten keinen oder nur sehr wenig Code enthält um keine Abhängigkeiten zu erhalten.
Wie verhält es sich nun bei Benutzeroberflächen die zB. ein UserControl visible-schalten oder ein neues Fenster öffnen sollen?
Dazu müsste ich ja zumindest das entsprechende Click-Event im Codebehind der View feuern bzw. das entsprechend programmieren.
Wäre das dann bereits eine Verletzung des Trennungsgebotes?
Im Prinzip würde ich ja nur eine weitere View öffnen, die dann unabhängig von meiner ersten View über das jeweilige ViewModel Daten anzeigt?
Oder sollten die Actions/Events über ICommand an das ViewModel und dann via Messaging an die neue View übergeben werden?
lg
Markus
Hallo Markus,
generell würde ich wenig bis gar nichts im Code-Behind der View machen. Gerade das Ausführen von Aktionen (siehe Button-Klicks etc.) sind Kandidaten für den Einsatz von Commands (siehe auch dieses Beispiel: https://www.norberteder.com/popups-per-mvvm-offnen/). Auch das Sichtbar-schalten auf Basis gewählter Einstellungen/Daten lässt sich ideal über das ViewModel und einer Datenbindung gestalten. Ein Messaging muss an dieser Stelle nicht zwingend eingesetzt werden.
lG;
Norbert
Hallo Norbert,
vielen lieben Dank für deine Ausführliche Erklärung den Interessanten Artikel. Das hat mir schon sehr weitergeholfen.
Der Ansatz mit den Popups scheint mir ganz vernünftig – damit muss man nicht immer mit Fenstern “jonglieren”. Dem Popup könnte man dann aber trotzdem ein anderes ViewModel anbinden als beim MainWindow?
lg
Markus
Natürlich.
Alles klar, danke dir! :)