Das MVVM und Events

by Gregor Biswanger 27. Juli 2010 04:01

Bei der Implementierung des Entwurfsmusters MVVM (Model-View-ViewModel) wird im ViewModel die Oberfläche durch Properties abgebildet. Dabei gelten für Aktionen, zum Beispiel die Logik beim Auslösen eines einfachen Buttons, dass das Handling mittels Commands umgesetzt wird. Das bringt einen enormen Vorteil mit sich, zum einen wäre das die 100% Entkopplung mittels Data-Binding. Allerdings erhält man zudem einen großen Nachteil. Commands beschränken sich nur auf die gängigen Standardaktionen. Dabei wird zum Beispiel nur beim betätigen eines Buttons das Command ausgelöst. Bei einer ListBox wäre dies wiederrum die Auswahl eines Items.

Diese Einschränkung kann unter WPF mittels EventTrigger elegant gelöst werden. Dennoch gibt es ein weiteres Problem, man erhält leider keine weiteren Informationen die im Normalfall von klassischen Events mittels EventArgs übergeben werden würden. Zudem gibt es unter Silverlight keine Trigger-Funktionalität.

In manchen Situationen können die Informationen zwar über CommandParameter übertragen werden, trotzdem tritt man immer wieder auf das fehlende Informationsproblem. Zudem möchte man Commands eventuell gar nicht auf die Standardaktionen binden. Viel eleganter wäre es, wenn man auf jeden beliebigen Event eines Controls ein Command auslösen könnte. Dazu müsste man dann vom ViewModel auf den EventManager zugreifen. Das benötigt leider etwas Source-Code und leider besteht eine gewisse Anhänglichkeit zu den jeweiligen Controls. Es müsste eine Lösung geben womit vom ViewModel entkoppelt auf Events Reagiert werden kann. Zudem wäre es wünschenswert, das kaum Source-Code dazu nötig ist.

Genau zu diesem Problem bietet Expression Blend 4 die Lösung mittels Behaviors. Behaviors sind fertige UI-Funktionalitäten die in gewisser Art als Snippet auf das gewünschte Control gezogen werden. Ab Expression Blend 4 bieten folgende Behavios die gewünschte Funktionalität:

 

Name:

Funktion:

CallMethodAction

Löst bei einem bestimmten Event eine beliebige Methode eines Zielobjekts (z.B. ViewModel) aus. Dabei werden die jeweiligen EventArgs mit übertragen.

ChangePropertyAction

Bei einem Event wird ein Propertie eines beliebigen Zielobjekts (z.B. ViewModel), nach einer beliebigen Iteration ein Wert zugewiesen.

InvokeCommandBehavior

Erweitert ein Control durch ein Command, das auch auf jedem beliebigem Event ausgelöst werden kann. Es werden dabei keine EventArgs übertragen, nur CommandParameter .

 

Ein Beispiel: Das SelectionChanged-Event einer Liste im ViewModel behandeln

Als einfaches Beispiel bietet sich das abfangen des SelectionChanged-Event einer Liste an. Dazu wird ein WPF oder Silverlight-Projekt mit einer ListBox benötigt. Die Beispieldaten können mit dem Data-Feature das es ab Expression Blend 3 gibt, zur Verfügung gestellt werden. Ein How-To dazu gibt es hier: Expression Blend 3 - Daten für Designer bereitstellen

 

Abb-1-1-Eine-Liste-mit-Beispieldaten

Abb.1.1. – Eine Liste mit Beispieldaten

 

Der nächste Schritt ist das Anlegen des ViewModels. Dazu wird eine einfache Klasse mit dem Namen „ExampleViewModel“ erzeugt. Hier wird eine Methode und die dazugehörige SelectionChangedEventArgs-Signatur hinzugefügt.

 

   1:  using System;
   2:  using System.Windows.Controls;
   3:   
   4:  namespace WpfCallMethodExample.ViewModels
   5:  {
   6:      public class ExampleViewModel
   7:      {
   8:          public void SelectionChangedMethod(object sender, SelectionChangedEventArgs e)
   9:          {
  10:              throw new NotImplementedException();
  11:          }
  12:      }
  13:  }

Listing 1.1. – Source-Code des ViewModels „ExampleViewModel.cs“

 

Eine Instanz zum ViewModel wird von der View aus im Resourcen-Bereich der jeweiligen View erzeugt.

 

   1:  <Window
   2:          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:          xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
   5:          xmlns:local="clr-namespace:WpfCallMethodExample.ViewModels"
   6:          xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfCallMethodExample.MainWindow"
   7:          Title="MainWindow" Height="350" Width="525">
   8:      <Window.Resources>
   9:          <DataTemplate x:Key="ItemTemplate">
  10:              <StackPanel>
  11:                  <TextBlock Text="{Binding Property1}"/>
  12:              </StackPanel>
  13:          </DataTemplate>
  14:          <local:ExampleViewModel x:Key="ViewModel" />
  15:      </Window.Resources> 
  16:      <Grid DataContext="{Binding Source={StaticResource SampleDataSource}}">
  17:          <ListBox Margin="8,64,8,8" ItemTemplate="{DynamicResource ItemTemplate}" ItemsSource="{Binding Collection}" />
  18:          <TextBlock Margin="8,8,8,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="52" FontSize="21.333"><Run Language="de-de" Text="CallMethodExample"/></TextBlock>
  19:      </Grid>
  20:  </Window>

Listing 1.2. – Eine Instanz zum ViewModel von der View erzeugen lassen.

 

Es folgt nun das Zuweisen eines Behaviors. Dabei wird im Assets-Fenster unter dem Reiterpunkt Behaviors, das Behavior CallMethodAction ausgewählt und mittels Drag & Drop auf die ListBox gezogen.

 

Abb-1_2-DasCallMethodBehavior_auf_die_ListBox_ziehen

Abb.1.2. –Das CallMethodBehavior auf die ListBox ziehen

 

Um die Einstellungen des Behaviors zu Konfigurieren, muss im Objekt-Fenster das beliege Control aufgeklappt werden. Dahinter stehen dann alle definierten Behaviors. Nach der gewünschten Auswahl stehen die Einstellungen im Fenster Properties.

 

Abb-1-3–Properties-zum-Behavior-anzeigen

Abb.1.3 – Properties zum Behavior anzeigen

 

Bei den Properties zum CallMethodAction-Behavior wird nun unter Trigger das Event SelectionChanged ausgewählt. Dabei wird als Triggertype der EventTrigger belassen. Unter Common Properties muss als TargetObject ein Binding zum ViewModel erfolgen. Als MethodName wird dann der Methodenname manuell eingetragen. Ganz wichtig ist hierbei das auslasen der Klammern. Siehe Abb.1.4..

 

Abb-1-4–CallMethodAction-Behavior-konfigurieren

Abb.1.4. – CallMethodAction-Behavior konfigurieren

Der XAML-Code sollte nun wie unter Listing 1.3. aussehen. Dabei wurde das Projekt um die Microsoft.Expression.Interactions-Assembly erweitert. Diese bietet dann eine Erweiterung für Trigger-Funktionalitäten. Unter Silverlight wird somit die fehlende Trigger-Funktion zur Verfügung gestellt.

 

   1:  <Window
   2:          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:          xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
   5:          xmlns:local="clr-namespace:WpfCallMethodExample.ViewModels"
   6:          xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfCallMethodExample.MainWindow"
   7:          Title="MainWindow" Height="350" Width="525">
   8:      <Window.Resources>
   9:          <DataTemplate x:Key="ItemTemplate">
  10:              <StackPanel>
  11:                  <TextBlock Text="{Binding Property1}"/>
  12:              </StackPanel>
  13:          </DataTemplate>
  14:          <local:ExampleViewModel x:Key="ViewModel" />
  15:      </Window.Resources> 
  16:      <Grid DataContext="{Binding Source={StaticResource SampleDataSource}}">
  17:          <ListBox Margin="8,64,8,8" ItemTemplate="{DynamicResource ItemTemplate}" ItemsSource="{Binding Collection}">
  18:              <i:Interaction.Triggers>
  19:                  <i:EventTrigger EventName="SelectionChanged">
  20:                      <ei:CallMethodAction TargetObject="{Binding Mode=OneWay, Source={StaticResource ViewModel}}" MethodName="SelectionChangedMethod"/>
  21:                  </i:EventTrigger>
  22:              </i:Interaction.Triggers>
  23:          </ListBox>
  24:          <TextBlock Margin="8,8,8,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="52" FontSize="21.333"><Run Language="de-de" Text="CallMethodExample"/></TextBlock>
  25:          
  26:      </Grid>
  27:  </Window>

Listing 1.3. – XAML-Code der View.

 

Zu guter Letzt wird nun die SelectionChangedMethod mit Logik erweitert. Dabei folgt nun ein MessageBox Aufruf mit den ausgewählten Datensatz. Wobei bemerkt werden muss, das ein MessageBox Aufruf in der Regel nicht vom ViewModel aus geschieht.

 

   1:  using System.Windows;
   2:  using System.Windows.Controls;
   3:  using Expression.Blend.SampleData.SampleDataSource;
   4:   
   5:  namespace WpfCallMethodExample.ViewModels
   6:  {
   7:      public class ExampleViewModel
   8:      {
   9:          public void SelectionChangedMethod(object sender, SelectionChangedEventArgs e)
  10:          {
  11:              Item selectedItem = (Item)e.AddedItems[0];
  12:              MessageBox.Show(selectedItem.Property1);
  13:          }
  14:      }
  15:  }

Listing 1.4. – Source-Code der Implementierung von SelectionChangedMethod.

Beim Ausführen der Anwendung, erscheint nun bei der Auswahl eines Items die jeweilige MessageBox.

Abb-1-5–Die-Auswahl-eines-Items-wird-in-einer-MessageBox-dargestellt

Abb.1.5. – Die Auswahl eines Items wird in einer MessageBox dargestellt.

Fazit

Behaviors sind immer wichtiger geworden. Ich selbst sehe Sie auch als eine Art Aspektorientierte Programmierung für das Frontend. Es muss kein Code geschrieben werden, es kann zudem immer wieder verwendet werden und die Übersichtlichkeit des eigenen Codes bleibt gegeben. Die neuen Behaviors in Expression Blend 4 bringen eine große Abhilfe bei den Stolpersteinen der heutigen Entwicklung mit sich. Zum Beispiel bei der Entwicklung mit dem MVVM.



Wenn ihnen der Artikel gefallen hat oder er für sie hilfreich war, bitten "kicken" sie ihn.
kick it on dotnet-kicks.de

Kommentare

Powered by BlogEngine.NET 1.4.5.0
Theme by Extensive SEO

Über den Autor

Gregor Biswanger

Microsoft MVP für Client App Dev
XING

Gregor Biswanger (Microsoft MVP für Client App Dev) ist freier Consultant, Trainer, Autor und Speaker.


Seine Schwerpunkte liegen im Bereich der .NET-Architektur, agilen Prozessen und XAML. Er veröffentlichte vor kurzem seine DVD´s mit Video-Trainings zum Thema „Meine erste Windows 8 App“, „Windows Store Apps mit XAML und C#“ und „WPF 4.5 und Silverlight 5“ bei Addison-Wesley von video2brain.


Biswanger ist auch im Auftrag von Intel GmbH als Technologieberater für die Intel Developer Zone aktiv und ist Leader bei der Ingolstädter .NET Developers Group (INdotNET). 

 

Video über mich:
http://www.youtube.com/watch?v=mx_6SiiLxjk


Basta! 2011 Speaker

CLIPer

MCTS
Windows SharePoint Services 3.0 – Application Development (MCTS)