ahhay
ahhay | Hinter den Höfen 20 | 37339 Haynrode/Germany | 036077 935077

MVVM Pattern bei Windows Store Apps



Grundlagen 1

Dieses ist eine Beschreibung über das Model-View-ViewModel-Pattern für die Entwicklung von Windows 8 -Store -Apps.

Das MVVM Architekturmuster wurde ursprünglich von Microsoft im Jahr 2005 als eine Spezialisierung der Model-View- Presenter (MVP) Muster entwickelt, welches von dem bekannten Model-View- Controller (MVC )-Muster abgeleitet wurde. MVVM wurde geschaffen, um die erweiterten Datenbindungsfunktionen in WPF und Silverlight (und jetzt WinRT Apps ) nutzen zukönnen und erleichtern eine strikte Trennung von View (XAML - Definition) und dem Model zuerreichen.



Grundlagen 2

Das Model kapselt Business / Datenlogik, die View zeigt diese Daten an und wird in diesem Fall mit XAML definiert. Weiterhin reagiert die View auf Änderungen aus dem Model oder auf Nutzereingaben. Das ViewModel ist Binding mit der View lose Verbunden und verarbeitet die Änderungen aus View und Model.




Schritt 1

namespace WpfAppRavenDb
{
    public class ViewModel : INotifyPropertyChanged
    {
        #region Implementation of INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}
                                

Erstellung des ViewModel:

Das VM ist das Bindeglied zwischen View und Model und bildet somit den Kern des MVVM-Patterns, gewissermaßen den Controller. Das VM kann Eingaben aus dem View entgegennehmen oder mit einem anderen Dienst interagieren, um die Model-Daten an die View weiterzuleiten.




Schritt 2

<Window.DataContext>
    <local:ViewModel />
</Window.DataContext>
                                

Code der View:

Die Bindung des ViewModels an die View erfolt über den DataContext des Windows.




Schritt 3

<StackPanel Grid.Column="0" Orientation="Vertical">
    <TextBlock Height="20" Text="Liste der Bücher:" />
    <ListBox ItemsSource="{Binding Path=BookList}"/>
</StackPanel>
                                

Code der View:

Die Seite ist in zwei Spalten eingeteilt. Links ist eine ListBox platziert, welche alle Bücher der Datenbank anzeigt.




Schritt 4

public ViewModel()
{
    _listData = new ObservableCollection< string> { "Book 0", "Book 1", "Book 2" };
}
                                

Erstellung der Bücherliste im ViewModel:

Der Einfachheit halber ist die Bücherliste eine Liste aus unterschiedlichen String-Einträgen.




Zwischenergebnis 1

Die View stellt die Liste der Bücher aus dem ViewModel in einer ListBox hineinander dar.




Schritt 5

<Stackpanel Orientation="Horizontal" Margin="0,20,0,10">
    <TextBox x:Name="NewItemTextBox" Width="200" />
    <Button Content="Add Item" 
            Command="{Binding AddBookCommand}" 
            CommandParameter="{Binding ElementName=NewItemTextBox, Path=Text}"/>
</StackPanel>
                        

Ergänzung der Liste durch Button-Command

Nach Betätigung des Buttons soll ein weiteres Buch der Liste hinzugefügt werden. Der Name des neue Buches kann zuvor in die TextBox eingegeben werden und wird über die ElementName-Bindung an den Command-Parameter gebunden.




Schritt 6

public ViewModel()
{
    AddBookCommand = new RelayCommand(DoAddBook);

    _listData = new ObservableCollection< string> { "Item 0", "Item 1", "Item 2" };
}
    ...
public void DoAddBook(object itemText)
{
    ...
}
                        

Ergänzung der Liste durch Button-Command

Nach Betätigung des Button soll ein weiteres Buch der Liste hinzugefügt werden.




Schritt 7

using System;
using System.Diagnostics;
using System.Windows.Input;
namespace WpfAppRavenDb
{
    public class RelayCommand : ICommand
    {
        #region Fields
        readonly Action < object> _execute;
        readonly Predicate< object> _canExecute;
        #endregion // Fields
        #region Constructors
        public RelayCommand(Action< object> execute)
            : this(execute, null)
        {
        }
        public RelayCommand(Action< object> execute, Predicate< object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute;
            _canExecute = canExecute;
        }
        #endregion // Constructors
        #region ICommand Members
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public void Execute(object parameter)
        {
            _execute(parameter);
        }
        #endregion // ICommand Members
    }
}
                                

Infrastruktur-Code für die Command-Weitergabe:

Es muss eine weitere Klasse implementiert werden, welche von der ICommand-Schnittstelle abgeleitet ist. Dort sind die Methoden CanExecute() und Execute() ausprogrammiert, um unteranderem Commandparameter zu übergeben.




Schritt 8

public void DoAddBook(object book)
{
    var newBook = book as string;
    if (string.IsNullOrEmpty(newBook)) newBook = "Book default";

    _bookList.Add(newBook);
}
                                

Wird nun der Button betätigt, wird die Methode DoAddBook() aufgerufen. Wenn in der TextBox ein neuer Buchtitel eingetragen ist, wird dieser der Bücherliste hinzugefügt, ansonsten wird in der Methode ein vorbesetzter Buchtitel verwendet.




Zwischenergebnis 2

Der Inhalt der TextBox wird als Button-Commandparameter an das ViewModel übertragen und der Bücherliste hinzugefügt. Durch die OnPropertyChanged() - Methode wird die Listenänderung an die View geleitet.




Schritt 9

RelayCommand _updateCommand;
public ICommand UpdateCommand
{
    get { return _updateCommand ?? (_updateCommand = new RelayCommand(param => this.Update())); }
}
                                

Es soll kurz eine weitere Möglichkeit vorgestellt werden, wie man ein Button-Command implementieren kann.

Nach Betätigung des Buttons wird über den Command die ViewModel-Methode Update() aufgerufen.




Schritt 10

<Button Content="Add default book" Horizontalalignment="Center"
        Command="{Binding UpdateCommand}" />
                                

Der View-Code ist schliechter als bei dem Beispiel zuvor. Es wird lediglich der Command übergeben.




Schritt 11

private void Update()
{
    _bookList.Add("Default book");
}
                                

Der Command ruft im ViewModel die Methode Update() auf und der Bücherliste wird ein weiteres Buch hinzugefügt.




Zwischenergebnis 3

Nach Betätigung des Buttons wurde ein weiteres Buch ergänzt und die View-Liste aktualisiert.




Schritt 12

private void Update()
{
    if (string.IsNullOrWhiteSpace(AddTextBoxBook)) _bookList.Add("Default book");
    else _bookList.Add(AddTextBoxBook);            
}
                                

Im letzten Beispiel des MVVM-Pattern bei Windows Store App soll das Binding an einer TextBox gezeigt werden. Hierfür wurde die Update()-Methode um die Überprüfung der Eigenschaft AddTextBoxBook erweitert.

Wenn kein Wert im Property AddTextBoxBook vorliegt, dann wird das "Default book" hinzugefügt, ansonsten der eingegebene Buchtitel.




Schritt 13

<Stackpanel Orientation="Horizontal">
    <Textblock Text="Buch ergänzen" Width="200" />
    <Textbox Text="{Binding AddTextBoxBook, Mode=TwoWay}" Width="200" />
</Stackpanel>
                                

Die View wurde um eine Textbox mit dem Binding auf das Property "AddTextBoxBook" erweitert.




Zwischenergebnis 4

Das Ergebnis des letzten Beispieles zeigt, dass der eingegebene Text in der TextBox über das Binding ans ViewModel geleitet wurde und dort den neuen Buchtitel zur Liste hinzugefügt.




Zusammenfassung

Dieser Artikel soll als Einstieg ins MVVM-Pattern für Windows Store Apps dienen, eine lückenlose Dokumentation war nicht das Ziel. Die Beispiele zeigen, dass alle Techniken aus WPF und Silverlight auch angewendet werden können.