.NET User Group Dresden, 29.9.2010 MVVM Model-View-ViewModel-Entwurfsmuster
informtools informtools Dr. Peter Fleischer Senftenberger Str. 48 D 01239 Dresden Tel.: + 49 177 2415577, +49 351 2709715 Fax: + 49 351 2709801 URL:  http://www.informtools.de E-Mail:  mailto:info@informtools.de Programmieren mit Microsoft®  Visual Basic® .NET, C#.NET Datenbankarbeit, XML, TFS, Sharepoint
Probleme   Probleme bei der Erstellung einer Anwendung mit Bedieneroberfläche: das zugrunde liegende System muss verfügbar gemacht werden; die nicht voraussagbaren stilistischen Anforderungen ihrer Benutzer müssen zufrieden gestellt werden; je höher die Komplexität der Anwendung, desto wichtiger ist es, den Code so organisieren, dass der Aufwand für die Fehlersuche minimiert werden kann und der Code noch übersichtlich bleibt;
Bekannte Entwurfsmuster MVC - Model-View-Controller MVP - Model-View-Presenter - Auf dem Bildschirm ist die Ansicht (View) zu sehen. Die Daten, die dort angezeigt werden, sind das Modell, und der Presenter verknüpft die beiden. Die Ansicht verlässt sich auf einen Presenter, der sie mit Modelldaten füllt, auf Benutzereingaben reagiert, Eingabeüberprüfung bietet (vielleicht durch Delegieren an das Modell) und andere ähnliche Aufgaben durchführt. PM -  Presentation Model - ähnlich MVP, da Ansicht von ihrem Verhalten und Zustand getrennt wird. Es wird die Abstraktion einer Ansicht erstellt, die als Presentation Model bezeichnet wird. Die Ansicht wird dann lediglich zu einer Darstellung des Presentation Model. MVVM - Model-View-ViewModel - kann als eine Spezialisierung des allgemeineren PM-Musters betrachtet, das speziell an die WPF- und die Silverlight-Plattform angepasst ist.
Elemente des MVVM Model: wie im klassischen MVC greift das "Model" auf die Datenzugriffsschicht zu und enthält den realen Zustandsinhalt (z.B. reale Daten aus der Datenbank). View: wie im klassischen MVC verweist die Sicht (View) auf alle Elemente des Nutzerinterfaces (UI), die durch die graphische Oberfläche dargestellt werden. wie Befehlsschaltflächen (Buttons), Fenster (Windows), grafische und andere Steuerelemente. ViewModel: das Sichtmodell (ViewModel) ist das Modell der Sicht (“Model of the View”), d.h. eine Abstraktion der Sicht, die die Datenbindung zwischen der Sicht und dem Modell bereitstellt.  Controller: einige Referenzen zum MVVM schließen eine Steuerungs-Schicht (Controller Layer) ein oder stellen das Sichtmodell (ViewModel) als eine spezielle funktionelle Menge parallel zum Controller dar.
MVVM in WPF In WPF ist die Sicht (View) ein XAML-Code, der als Ressource das Sichtmodell (ViewModel) nutzt. Das Sichtmodell (ViewModel) nutzt wiederum eine Instanz des Modells. Das Modell stellt Daten aus Datenbanken, Dateien usw. bereit, die dann im Sichtmodell (ViewModel) an eine für die Darstellung gewünschte Form umgewandelt werden.  Das Sichtmodell (ViewModel) stellt der Sicht (View) die Daten über Eigenschaften bereit, die ggf. das Ereignis "PropertyChanged" (INotifyPropertyChanged) auslösen, um die Sicht über Veränderungen der Werte im Sichtmodell (ViewModel) zu informieren. In der Sicht (View = XAML-Code) gibt es lediglich Bindungen des DataContext an die Ressource mit dem Sichtmodell (ViewModel) und Bindungen an die Eigenschaften des Sichtmodells (ViewModel).
Die Interaktion des Anwenders mit der Sicht (View) wird entweder über einen Befehl (Command) oder als ausgelöstes Ereignis an das Sichtmodell (ViewModel) weitergeleitet. Ein Befehl kann genutzt werden, wenn das entsprechende Steuerelement über eine Command-Eigenschaft verfügt, welche bei Aktivierung (Auslösung) ein Invoke einer Methode ausführt. Bei Nutzung eines Sichtmodells (ViewModel) wird dieses Invoke über ein Delegate in das Sichtmodell (ViewModel) "umgeleitet". Dazu kann eine das ICommand-Interface implemetierende Hilfsklasse dienen. Um Ereignisse der Steuerelemente der Sicht (View) im Sichtmodell (ViewModel) zu empfangen, muss im Sichtmodell (ViewModel) ein Ereignisbehandler an das Steuerelement gehangen werden. Dazu wird der Zugriff auf eine Eigenschaft im Sichtmodell (ViewModel) durch das Steuerelement genutzt, um über den "sender" den Zugriff auf den Verweis auf das Steuerelement zu bekommen.
Vorbereitung ViewModel-Klasse using System.ComponentModel; using System.Windows.Input; using System.Windows; using System.Windows.Controls; namespace CSmvvmDemoWPF { class ViewModel : INotifyPropertyChanged { } } XAML <Window x:Class=&quot;CSmvvmDemoWPF.MainWindow&quot; xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot; xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot; Title=&quot;MainWindow&quot; Height=&quot;350&quot; Width=&quot;525&quot; xmlns:local=&quot;clr-namespace:CSmvvmDemoWPF&quot;> <Window.Resources> <local:ViewModel x:Key=&quot;data&quot;/> </Window.Resources> <StackPanel DataContext=&quot;{Binding Source={StaticResource data}}&quot;> </StackPanel> </Window>
VB.NET ViewModel-Klasse in VB.NET Imports System.ComponentModel Public Class ViewModel Implements INotifyPropertyChanged Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged End Class
Eigenschaftsbindung <StackPanel> <Label Content=&quot;einfache Bindung Prop1a an TextBox mit direkter Aktualisierung:&quot; /> <TextBox Text=&quot;{Binding Path=Prop1a, UpdateSourceTrigger=PropertyChanged}&quot;/> <Label Content=&quot;{Binding Path=Prop1a}&quot;/> </StackPanel> private String _prop1a; public String Prop1a { get { return this._prop1a; } set { this._prop1a = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(&quot;Prop1a&quot;)); } } } public String Prop1b { get { return String.Format(&quot;Ergebnis Prop1: {0}&quot;, this._prop1a); } }
Eigenschaftsbindung in VB.NET Private _prop1a As String Public Property Prop1a() As String Get Return Me._prop1a End Get Set(ByVal value As String) Me._prop1a = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(&quot;Prop1a&quot;)) End Set End Property Public ReadOnly Property Prop1b() As String Get Return String.Format(&quot;Ergebnis Prop1: {0}&quot;, Me._prop1a) End Get End Property
Command-Bindung <StackPanel> <Label Content=&quot;Übergabe einer Aktion über ICommand&quot;/> <Button Command=&quot;{Binding Path=Command2}&quot;>Auslösen einer Aktion</Button> <Label Content=&quot;{Binding Path=Prop2}&quot;/> </StackPanel>  public ViewModel() { cmd2 = new Action<Object>(Cmd2Exec); } private Action<Object> cmd2; public ICommand Command2 { get { return new RelayCommand(cmd2); } } private void Cmd2Exec(Object obj) { Prop2 = String.Format(&quot;Button gedrückt: {0:HH:mm:ss.fff}&quot;, DateTime.Now); } private String _prop2 = &quot;Button nicht gedrückt&quot;; public String Prop2 { get { return this._prop2; } set { this._prop2 = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(&quot;Prop2&quot;)); } } }
CommandBindung in VB.NET Private cmd2 As New Action(Of Object)(AddressOf Cmd2Exec) Public ReadOnly Property Command2() As ICommand Get Return New RelayCommand(cmd2) End Get End Property Sub Cmd2Exec(ByVal obj As Object) Prop2 = String.Format(&quot;Button gedrückt: {0:HH:mm:ss.fff}&quot;, Now) End Sub Private _prop2 As String = &quot;Button nicht gedrückt&quot; Public Property Prop2() As String Get Return Me._prop2 End Get Set(ByVal value As String) Me._prop2 = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(&quot;Prop2&quot;)) End Set End Property
angehängtes Ereignis - attached behavior <StackPanel> <Label Content=&quot;Bindung eines Ereignisses (attached behaviors)&quot; local:ViewModel.Prop3a=&quot;True&quot;/> <Label Content=&quot;{Binding Path=Prop3b}&quot;/> </StackPanel> public static bool GetProp3a(DependencyObject obj)  //propa { return (bool)obj.GetValue(Prop3aProperty); } public static void SetProp3a(DependencyObject obj, bool value) { obj.SetValue(Prop3aProperty, value); } // Using a DependencyProperty as the backing store for Prop3a.  This enables animation, styling, binding, etc... public static readonly DependencyProperty Prop3aProperty = DependencyProperty.RegisterAttached(&quot;Prop3a&quot;, typeof(bool), typeof(Label), new UIPropertyMetadata(false, OnProp3a));
angehängtes Ereignis - Verarbeitung private static void OnProp3a(DependencyObject depObj, DependencyPropertyChangedEventArgs e) { var sb = depObj as Label; if (sb == null) return; if (e.NewValue.GetType() != typeof(bool)) return; if ((bool)e.NewValue) { sb.MouseDown += OnLblMouseDown; } else { sb.MouseDown -= OnLblMouseDown; } } private static void OnLblMouseDown(Object sender, EventArgs e) { var lbl = (Label)sender; var vm = (ViewModel)lbl.DataContext; vm.Prop3b = String.Format(&quot;rechte Maustaste gedrückt: {0:HH:mm:ss.fff}&quot;, DateTime.Now); } private String _prop3b = &quot;rechte Maustaste nicht gedrückt&quot;; public String Prop3b { get { return this._prop3b; } set { this._prop3b = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(&quot;Prop3b&quot;)); } } }
angehängtes Ereignis - VB.NET Public Shared Function GetProp3a(ByVal obj As DependencyObject) As Boolean Return CType(obj.GetValue(Prop3aProperty), Boolean) End Function Public Shared Sub SetProp3a(ByVal obj As DependencyObject, ByVal value As Boolean) obj.SetValue(Prop3aProperty, value) End Sub Public Shared ReadOnly Prop3aProperty As DependencyProperty = _ DependencyProperty.RegisterAttached(&quot;Prop3a&quot;, _ GetType(Boolean), _ GetType(Label), _ New UIPropertyMetadata(False, AddressOf OnProp3a))
angehängtes Ereignis - VB.NET - Verarbeitung Private Shared Sub OnProp3a(ByVal depObj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs) Dim sb = TryCast(depObj, Label) If sb Is Nothing Then Exit Sub If e.NewValue.GetType IsNot GetType(Boolean) Then Exit Sub If CType(e.NewValue, Boolean) Then AddHandler sb.MouseDown, AddressOf OnLblMouseDown Else RemoveHandler sb.MouseDown, AddressOf OnLblMouseDown End If End Sub Private Shared Sub OnLblMouseDown(ByVal sender As Object, ByVal e As EventArgs) Dim lbl = CType(sender, Label) Dim vm = CType(lbl.DataContext, ViewModel) vm.Prop3b = String.Format(&quot;rechte Maustaste gedrückt: {0:HH:mm:ss.fff}&quot;, Now) End Sub Private _prop3b As String = &quot;rechte Maustaste nicht gedrückt&quot; Public Property Prop3b() As String Get Return Me._prop3b End Get Set(ByVal value As String) Me._prop3b = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(&quot;Prop3b&quot;)) End Set End Property
RelayCommand using System; using System.Windows.Input; using System.Diagnostics; namespace CSmvvmDemoWPF { 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(&quot;execute&quot;); _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 } }
RelayCommand – VB.NET Public Class RelayCommand Implements Icommand Private ReadOnly _execute As Action(Of Object) Private ReadOnly _canExecute As Predicate(Of Object) Public Sub New(ByVal execute As Action(Of Object)) Me.New(execute, Nothing) End Sub Public Sub New(ByVal execute As Action(Of Object), ByVal canExecute As Predicate(Of Object)) ' это проверка русского текста  If execute Is Nothing Then Throw New ArgumentNullException(&quot;execute&quot;) End If Me._execute = execute Me._canExecute = canExecute End Sub Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute Return If(Me._canExecute Is Nothing, True, Me._canExecute(parameter)) End Function Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged AddHandler(ByVal value As EventHandler) AddHandler CommandManager.RequerySuggested, value End AddHandler RemoveHandler(ByVal value As EventHandler) RemoveHandler CommandManager.RequerySuggested, value End RemoveHandler RaiseEvent(ByVal sender As System.Object, ByVal e As System.EventArgs) End RaiseEvent End Event Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute Me._execute(parameter) End Sub End Class

MVVM Pattern

  • 1.
    .NET User GroupDresden, 29.9.2010 MVVM Model-View-ViewModel-Entwurfsmuster
  • 2.
    informtools informtools Dr.Peter Fleischer Senftenberger Str. 48 D 01239 Dresden Tel.: + 49 177 2415577, +49 351 2709715 Fax: + 49 351 2709801 URL: http://www.informtools.de E-Mail: mailto:info@informtools.de Programmieren mit Microsoft® Visual Basic® .NET, C#.NET Datenbankarbeit, XML, TFS, Sharepoint
  • 3.
    Probleme Probleme bei der Erstellung einer Anwendung mit Bedieneroberfläche: das zugrunde liegende System muss verfügbar gemacht werden; die nicht voraussagbaren stilistischen Anforderungen ihrer Benutzer müssen zufrieden gestellt werden; je höher die Komplexität der Anwendung, desto wichtiger ist es, den Code so organisieren, dass der Aufwand für die Fehlersuche minimiert werden kann und der Code noch übersichtlich bleibt;
  • 4.
    Bekannte Entwurfsmuster MVC- Model-View-Controller MVP - Model-View-Presenter - Auf dem Bildschirm ist die Ansicht (View) zu sehen. Die Daten, die dort angezeigt werden, sind das Modell, und der Presenter verknüpft die beiden. Die Ansicht verlässt sich auf einen Presenter, der sie mit Modelldaten füllt, auf Benutzereingaben reagiert, Eingabeüberprüfung bietet (vielleicht durch Delegieren an das Modell) und andere ähnliche Aufgaben durchführt. PM - Presentation Model - ähnlich MVP, da Ansicht von ihrem Verhalten und Zustand getrennt wird. Es wird die Abstraktion einer Ansicht erstellt, die als Presentation Model bezeichnet wird. Die Ansicht wird dann lediglich zu einer Darstellung des Presentation Model. MVVM - Model-View-ViewModel - kann als eine Spezialisierung des allgemeineren PM-Musters betrachtet, das speziell an die WPF- und die Silverlight-Plattform angepasst ist.
  • 5.
    Elemente des MVVMModel: wie im klassischen MVC greift das &quot;Model&quot; auf die Datenzugriffsschicht zu und enthält den realen Zustandsinhalt (z.B. reale Daten aus der Datenbank). View: wie im klassischen MVC verweist die Sicht (View) auf alle Elemente des Nutzerinterfaces (UI), die durch die graphische Oberfläche dargestellt werden. wie Befehlsschaltflächen (Buttons), Fenster (Windows), grafische und andere Steuerelemente. ViewModel: das Sichtmodell (ViewModel) ist das Modell der Sicht (“Model of the View”), d.h. eine Abstraktion der Sicht, die die Datenbindung zwischen der Sicht und dem Modell bereitstellt. Controller: einige Referenzen zum MVVM schließen eine Steuerungs-Schicht (Controller Layer) ein oder stellen das Sichtmodell (ViewModel) als eine spezielle funktionelle Menge parallel zum Controller dar.
  • 6.
    MVVM in WPFIn WPF ist die Sicht (View) ein XAML-Code, der als Ressource das Sichtmodell (ViewModel) nutzt. Das Sichtmodell (ViewModel) nutzt wiederum eine Instanz des Modells. Das Modell stellt Daten aus Datenbanken, Dateien usw. bereit, die dann im Sichtmodell (ViewModel) an eine für die Darstellung gewünschte Form umgewandelt werden. Das Sichtmodell (ViewModel) stellt der Sicht (View) die Daten über Eigenschaften bereit, die ggf. das Ereignis &quot;PropertyChanged&quot; (INotifyPropertyChanged) auslösen, um die Sicht über Veränderungen der Werte im Sichtmodell (ViewModel) zu informieren. In der Sicht (View = XAML-Code) gibt es lediglich Bindungen des DataContext an die Ressource mit dem Sichtmodell (ViewModel) und Bindungen an die Eigenschaften des Sichtmodells (ViewModel).
  • 7.
    Die Interaktion desAnwenders mit der Sicht (View) wird entweder über einen Befehl (Command) oder als ausgelöstes Ereignis an das Sichtmodell (ViewModel) weitergeleitet. Ein Befehl kann genutzt werden, wenn das entsprechende Steuerelement über eine Command-Eigenschaft verfügt, welche bei Aktivierung (Auslösung) ein Invoke einer Methode ausführt. Bei Nutzung eines Sichtmodells (ViewModel) wird dieses Invoke über ein Delegate in das Sichtmodell (ViewModel) &quot;umgeleitet&quot;. Dazu kann eine das ICommand-Interface implemetierende Hilfsklasse dienen. Um Ereignisse der Steuerelemente der Sicht (View) im Sichtmodell (ViewModel) zu empfangen, muss im Sichtmodell (ViewModel) ein Ereignisbehandler an das Steuerelement gehangen werden. Dazu wird der Zugriff auf eine Eigenschaft im Sichtmodell (ViewModel) durch das Steuerelement genutzt, um über den &quot;sender&quot; den Zugriff auf den Verweis auf das Steuerelement zu bekommen.
  • 8.
    Vorbereitung ViewModel-Klasse usingSystem.ComponentModel; using System.Windows.Input; using System.Windows; using System.Windows.Controls; namespace CSmvvmDemoWPF { class ViewModel : INotifyPropertyChanged { } } XAML <Window x:Class=&quot;CSmvvmDemoWPF.MainWindow&quot; xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot; xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot; Title=&quot;MainWindow&quot; Height=&quot;350&quot; Width=&quot;525&quot; xmlns:local=&quot;clr-namespace:CSmvvmDemoWPF&quot;> <Window.Resources> <local:ViewModel x:Key=&quot;data&quot;/> </Window.Resources> <StackPanel DataContext=&quot;{Binding Source={StaticResource data}}&quot;> </StackPanel> </Window>
  • 9.
    VB.NET ViewModel-Klasse inVB.NET Imports System.ComponentModel Public Class ViewModel Implements INotifyPropertyChanged Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged End Class
  • 10.
    Eigenschaftsbindung <StackPanel> <LabelContent=&quot;einfache Bindung Prop1a an TextBox mit direkter Aktualisierung:&quot; /> <TextBox Text=&quot;{Binding Path=Prop1a, UpdateSourceTrigger=PropertyChanged}&quot;/> <Label Content=&quot;{Binding Path=Prop1a}&quot;/> </StackPanel> private String _prop1a; public String Prop1a { get { return this._prop1a; } set { this._prop1a = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(&quot;Prop1a&quot;)); } } } public String Prop1b { get { return String.Format(&quot;Ergebnis Prop1: {0}&quot;, this._prop1a); } }
  • 11.
    Eigenschaftsbindung in VB.NETPrivate _prop1a As String Public Property Prop1a() As String Get Return Me._prop1a End Get Set(ByVal value As String) Me._prop1a = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(&quot;Prop1a&quot;)) End Set End Property Public ReadOnly Property Prop1b() As String Get Return String.Format(&quot;Ergebnis Prop1: {0}&quot;, Me._prop1a) End Get End Property
  • 12.
    Command-Bindung <StackPanel> <LabelContent=&quot;Übergabe einer Aktion über ICommand&quot;/> <Button Command=&quot;{Binding Path=Command2}&quot;>Auslösen einer Aktion</Button> <Label Content=&quot;{Binding Path=Prop2}&quot;/> </StackPanel> public ViewModel() { cmd2 = new Action<Object>(Cmd2Exec); } private Action<Object> cmd2; public ICommand Command2 { get { return new RelayCommand(cmd2); } } private void Cmd2Exec(Object obj) { Prop2 = String.Format(&quot;Button gedrückt: {0:HH:mm:ss.fff}&quot;, DateTime.Now); } private String _prop2 = &quot;Button nicht gedrückt&quot;; public String Prop2 { get { return this._prop2; } set { this._prop2 = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(&quot;Prop2&quot;)); } } }
  • 13.
    CommandBindung in VB.NETPrivate cmd2 As New Action(Of Object)(AddressOf Cmd2Exec) Public ReadOnly Property Command2() As ICommand Get Return New RelayCommand(cmd2) End Get End Property Sub Cmd2Exec(ByVal obj As Object) Prop2 = String.Format(&quot;Button gedrückt: {0:HH:mm:ss.fff}&quot;, Now) End Sub Private _prop2 As String = &quot;Button nicht gedrückt&quot; Public Property Prop2() As String Get Return Me._prop2 End Get Set(ByVal value As String) Me._prop2 = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(&quot;Prop2&quot;)) End Set End Property
  • 14.
    angehängtes Ereignis -attached behavior <StackPanel> <Label Content=&quot;Bindung eines Ereignisses (attached behaviors)&quot; local:ViewModel.Prop3a=&quot;True&quot;/> <Label Content=&quot;{Binding Path=Prop3b}&quot;/> </StackPanel> public static bool GetProp3a(DependencyObject obj) //propa { return (bool)obj.GetValue(Prop3aProperty); } public static void SetProp3a(DependencyObject obj, bool value) { obj.SetValue(Prop3aProperty, value); } // Using a DependencyProperty as the backing store for Prop3a. This enables animation, styling, binding, etc... public static readonly DependencyProperty Prop3aProperty = DependencyProperty.RegisterAttached(&quot;Prop3a&quot;, typeof(bool), typeof(Label), new UIPropertyMetadata(false, OnProp3a));
  • 15.
    angehängtes Ereignis -Verarbeitung private static void OnProp3a(DependencyObject depObj, DependencyPropertyChangedEventArgs e) { var sb = depObj as Label; if (sb == null) return; if (e.NewValue.GetType() != typeof(bool)) return; if ((bool)e.NewValue) { sb.MouseDown += OnLblMouseDown; } else { sb.MouseDown -= OnLblMouseDown; } } private static void OnLblMouseDown(Object sender, EventArgs e) { var lbl = (Label)sender; var vm = (ViewModel)lbl.DataContext; vm.Prop3b = String.Format(&quot;rechte Maustaste gedrückt: {0:HH:mm:ss.fff}&quot;, DateTime.Now); } private String _prop3b = &quot;rechte Maustaste nicht gedrückt&quot;; public String Prop3b { get { return this._prop3b; } set { this._prop3b = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(&quot;Prop3b&quot;)); } } }
  • 16.
    angehängtes Ereignis -VB.NET Public Shared Function GetProp3a(ByVal obj As DependencyObject) As Boolean Return CType(obj.GetValue(Prop3aProperty), Boolean) End Function Public Shared Sub SetProp3a(ByVal obj As DependencyObject, ByVal value As Boolean) obj.SetValue(Prop3aProperty, value) End Sub Public Shared ReadOnly Prop3aProperty As DependencyProperty = _ DependencyProperty.RegisterAttached(&quot;Prop3a&quot;, _ GetType(Boolean), _ GetType(Label), _ New UIPropertyMetadata(False, AddressOf OnProp3a))
  • 17.
    angehängtes Ereignis -VB.NET - Verarbeitung Private Shared Sub OnProp3a(ByVal depObj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs) Dim sb = TryCast(depObj, Label) If sb Is Nothing Then Exit Sub If e.NewValue.GetType IsNot GetType(Boolean) Then Exit Sub If CType(e.NewValue, Boolean) Then AddHandler sb.MouseDown, AddressOf OnLblMouseDown Else RemoveHandler sb.MouseDown, AddressOf OnLblMouseDown End If End Sub Private Shared Sub OnLblMouseDown(ByVal sender As Object, ByVal e As EventArgs) Dim lbl = CType(sender, Label) Dim vm = CType(lbl.DataContext, ViewModel) vm.Prop3b = String.Format(&quot;rechte Maustaste gedrückt: {0:HH:mm:ss.fff}&quot;, Now) End Sub Private _prop3b As String = &quot;rechte Maustaste nicht gedrückt&quot; Public Property Prop3b() As String Get Return Me._prop3b End Get Set(ByVal value As String) Me._prop3b = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(&quot;Prop3b&quot;)) End Set End Property
  • 18.
    RelayCommand using System;using System.Windows.Input; using System.Diagnostics; namespace CSmvvmDemoWPF { 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(&quot;execute&quot;); _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 } }
  • 19.
    RelayCommand – VB.NETPublic Class RelayCommand Implements Icommand Private ReadOnly _execute As Action(Of Object) Private ReadOnly _canExecute As Predicate(Of Object) Public Sub New(ByVal execute As Action(Of Object)) Me.New(execute, Nothing) End Sub Public Sub New(ByVal execute As Action(Of Object), ByVal canExecute As Predicate(Of Object)) ' это проверка русского текста If execute Is Nothing Then Throw New ArgumentNullException(&quot;execute&quot;) End If Me._execute = execute Me._canExecute = canExecute End Sub Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute Return If(Me._canExecute Is Nothing, True, Me._canExecute(parameter)) End Function Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged AddHandler(ByVal value As EventHandler) AddHandler CommandManager.RequerySuggested, value End AddHandler RemoveHandler(ByVal value As EventHandler) RemoveHandler CommandManager.RequerySuggested, value End RemoveHandler RaiseEvent(ByVal sender As System.Object, ByVal e As System.EventArgs) End RaiseEvent End Event Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute Me._execute(parameter) End Sub End Class

Hinweis der Redaktion

  • #3 Module 0: Introduction Course ####y This introduction module provides students with an overview of the course content materials and logistics for Course xxxxy, Course Title . Required materials To teach this course, you need the following materials: Course Handbook Course Companion CD Trainer materials including: Trainer Preparation Guide Microsoft Office PowerPoint® files for this course Microsoft Virtual Server Classroom Setup Guide Virtual machines for the course Latest error logs for the course (if any) Important It is recommended that you use PowerPoint 2003 or a later version to display the slides for this course. If you use PowerPoint Viewer or an earlier version of PowerPoint, all the features of the slides might not be displayed correctly. Preparation tasks To prepare for this course, you must follow and complete the tasks outlined in the Trainer Preparation Guide. Presentation: xx minutes