Solution Explorer

MVVM Tutorial – Part 5 (View und StartApplication)

Solution Explorer

Solution Explorer

In diesem Teil erstellen wir nun endlich unser View, sodass wir auch etwas anzeigen können. Dafür gibt es 2 neue Projekte: View und StartApplication. Im View Projekt definieren wir unser View nach dem MVVM Pattern und das StartApplication Projekt wird unser neues Startup Project, welches dann View und ViewModel miteinander verbindet.

View

Erstellen wir nun also das View Projekt (Class Library). Referenzen benötigen wir hier keine (alle notwendigen werden von Visual Studio automatisch hinzugefügt). Wir fügen nun ein WPF UserControl (kein WinForm UserControl!!!) hinzu und nennen es PersonListView, da es das View zu unserem PersonListViewModel wird. Visual Studio erstellt automatisch in Grid in dem UserControl. Dieses Grid unterteilen wir in 2 Zeilen, wobei die untere 50px hoch ist und die obere gestreckt werden soll. In der oberen Zeile (Zeile 0 muss nicht explizit angegeben werden). Als ItemSource geben wir dem Datagrid eine Property namens Persons. Unser View weiß zu diesem Zeitpunkt noch nicht, dass wir Persons aus unserem PersonListViewModel meinen, das legen wir erst später fest. Data Binding geht nur über Namen, dem View ist also egal, was dahinter liegt (Es sollte nur eine Collection sein). In der unteren Zeile möchten wir einen Button haben, welcher eine Person hinzufügt. Daher binden wir die Command Eigenschaft des Buttons an ein Command namens AddPersonCommand (zufällig heißt so auch die Property unseres PersonListViewmodels).

<UserControl x:Class="View.PersonListView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="50" />
        </Grid.RowDefinitions>
        <DataGrid ItemsSource="{Binding Persons}" />
        <Button Content="Add Person" Command="{Binding AddPersonCommand}" Grid.Row="1" />
    </Grid>
</UserControl>

Die Designansicht sollte folgendermaßen aussehen:

PersonListView

PersonListView in der Designansicht

Damit ist unser View auch schon fertig. Da wir unsere Personen nur in einer Tabelle anzeigen wollen, brauchen wir kein View für Personen zu definieren.

StartApplication

Nun muss das ganze noch zusammen geführt werden, wofür unser StartApplication Projekt zuständig ist. Wir erstellen es als Projekt vom Typ WPF Application. Dieses können wir auch gleich als Startup Application festlegen. Referenzen müssen wir zu den Projekten View, ViewModel und ViewModelBase hinzufügen. In der Design Ansicht von Mainwindow.xaml ziehen wir unser PersonListView aus der Toolbox in das Grid. Sollte das PersonListView nicht in der Toolbox auftauchen, muss die Solution vorher einmal kompillliert werden. So SOllte nun der XAML Code vom MainWIndow aussehen:

<Window xmlns:my="clr-namespace:View;assembly=View"  x:Class="StartApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <my:PersonListView Name="personListView"/>
    </Grid>
</Window>

Nun müssen wir in der Code Behind Datei (MainWindow.xaml.cs) noch unser ViewModel als DataContext unseres Views festlegen, damit die Bindings auch funktionieren.
Alle Bindings werden immer vom DataContext aus aufgelöst. Da unser View nun nach Properties mit den Namen Persons und AddPersonCommand sucht und unser ViewModel diese bereitstellt, funktioniert auch alles wunderbar. Sollten hierbei einmal Fehler auftauchen, so werden diese in der Konsole ausgegeben, das Programm läuft aber weiter!

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            SetupBindings();
        }

        private void SetupBindings()
        {
            var viewModel = new PersonListViewModel();
            personListView.DataContext = viewModel;
        }
    }

Wenn wir nun unser StartApplication Projekt starten, sollten wir folgendes Fenster sehen:

Fenster beim Start von StartApplication

Fenster beim Start von StartApplication

Durch Klick auf den Button können wir darüber hinaus eine neue Person hinzufügen. Einigen wird vielleicht aufgefallen sein, dass sich die Spalte Model nicht automatisch ändert, wenn Werte in den anderen Spalten geändert werden. Dies liegt daran, dass die Model Property im ViewModel nicht auf Änderungen der anderen Properties reagiert. Dies ist gewollt, da das Model normalerweise nicht in er GUI angezeigt werden soll und wir dies auch gleich ändern werden. Außerdem bekommt ihr einen Fehler, wenn ihr etwas in die Modelzeile schreibt (System.Windows.Data Error wird in der Konsole ausgegeben), da WPF nicht weiß, wie es ein string Objekt in ein Person Objekt konvertieren soll.
Desshalb führen wir nun eine kleine Änderung an dem DataGrid im PersonListView durch:

        <DataGrid ItemsSource="{Binding Persons}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Full Name" Binding="{Binding Name}" />
                <DataGridTextColumn Header="Street" Binding="{Binding Street}" />
                <DataGridTextColumn Header="Postal code" Binding="{Binding PostalCode}" />
                <DataGridTextColumn Header="City" Binding="{Binding City}" />
            </DataGrid.Columns>
        </DataGrid>

Wir haben AutoGenerateColums auf False gestellt, womit keine Zeilen mehr automatisch erzeugt werden. Würde man nur dies Einstellen und die DataGrid.Columns weglassen, bekäme man beim Ausführen ein leeres Grid angezeigt. Hier definieren wir aber unsere Spalten selbst. Der Vorteil daran ist, dass wir genau sagen können, welche Spalten wie angezeigt werden sollen. Wir können die Header frei definieren und auch die Art der Spalte (Es gibt noch CheckBoxColumn, ComboBoxColumn,…). Dabei muss beachtet werden, dass die Bindings hier in den einzelnen PersonViewModels gesucht werden. Für den Namen nutzen wir also {Binding Name} und nicht {Binding Persons.Name}.
Wenn ihr das Projekt jetzt startet, bekommt ihr folgendes Fenster zu sehen:

Fenster beim Start von StartApplication

Fenster beim Start von StartApplication

Auch hier wieder die Solution zum Download: MVVMTutorial Solution (Model, ViewModelBase, ViewModel, View und StartApplication)

Im nächsten Teil werden wir dann noch ein paar weitere Möglichkeiten mit unserem View ausprobieren.

2 Gedanken zu „MVVM Tutorial – Part 5 (View und StartApplication)

  1. Sinmson

    Hi,
    ich glaube da ist ein Fehler und zwar in der MainWindow.xaml.cs,
    du arbeitest mit „personListView“ in Z. 21 – 22

    „var viewModel = new PersonListViewModel();
    personListView.DataContext = viewModel;“

    Und zwar bekomme ich mit deinem Projekt 2 Errors:
    Der Name „personListView“ ist im aktuellen Kontext nicht vorhanden.
    Der Name „InitializeComponent“ ist im aktuellen Kontext nicht vorhanden.

    Weil, du hast ja „personListView“ nirgendwo definiert.

    Ich habe komischerweise 4 Fehler:
    Der Typ ‚System.Windows.Markup.IQueryAmbient‘ ist in einer nicht referenzierten Assembly definiert. Fügen Sie einen Verweis auf die Assembly ‚System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089‘ hinzu.
    Der Typname ‚IComponentConnector‘ konnte nicht im Namespace ‚System.Windows.Markup‘ gefunden werden. Dieser Typ wurde an Assembly ‚System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089‘ weitergeleitet. Fügen Sie ggf. einen Verweis auf die Assembly hinzu.
    Das Tag „PersonListView“ ist im XML-Namespace „clr-namespace:View;assembly=View“ nicht vorhanden.
    Der Name „personListView“ ist im aktuellen Kontext nicht vorhanden.

    Lg Tim

  2. Niklas

    Hi Tim,

    du musst in dem View-Project noch eine Referenz auf System.Xaml setzen. Erstellt man das Project als Class-Library ist diese Referenz noch nicht mit eingebunden. Dann sollte es klappen.

    Grüße

    Niklas

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.