INotifyPropertyChanged – Varianten für die Implementierung

September 2nd, 2009 Bernd 6 comments

Wer mit WPF programmiert, kennt INotifyPropertyChanged. Das allgegenwärtige Interface, mit dem Änderungen z.B. von einem ViewModel zu einem daran gebunden UI Element propagiert werden. Eine typische Implementierung von INotifyPropertyChanged sieht etwa so aus:

INotifyPropertyChanged Horror

Drei Sachen fallen ins Auge

  1. jedes ViewModel muss INotifyPropertyChanged implementieren, d.h. den PropertyChanged Event anbieten und eine Methode zum Feuern des Events haben.
  2. die EventArgs für den PropertyChanged Event bekommen als Parameter einen String, der dem Namen der Property entspricht.
  3. der Code ist “zugemüllt” mit Infrastrukturcode, der eigentlich nichts zur Logik des Objekts beiträgt
    Der erste Punkt lässt sich relativ einfach lösen, indem man eine ViewModel Basisklasse macht, die diese Aufgaben übernimmt.
    Basisklasse für ViewModels
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

Beim zweiten Punkt wird es dann schon schwieriger. Hier gibt es mehrere Ansätze, die Strings loszuwerden.

Am häufigsten trifft man wohl eine Variante mit Lambda Expressions an. Die Implementierungen reichen von einer Extensionmethod für den PropertyChangedEventHandler bis zu einer generischen ViewModel Basisklasse, welche das abgeleitete ViewModel als Type Parameter bekommt. Hier ein paar Links zum Nachlesen:

J.P. Hamilton – Generische ViewModel Basisklasse

Stefan Lieser – Implementierung direkt im ViewModel

Eric De Carufel – Extensionmethod für PropertyChangedEventHandler

 

Andere Lösungen, die ich gefunden habe:

Alkampfer – INotifyPropertyChanged mit CodeDom implementieren

Ayende – INotifyPropertyChanged mit Castle Dynamic Proxy

Mike Saunders – INotifyPropertyChanged mit PostSharp Aspekt

Richard Banks – INotifyPropertyChanged mit PostSharp Aspekt

 

Dann gibt es noch die den Verfechter von UpdateControls, Michael L. Perry. UpdateControls ist eine Open Source Bibliothek auf CodePlex, die es erlaubt, Änderungen von Eigenschaften auch ohne INotifyProperyChanged zu propagieren und z.B. an WPF Controls zu binden. Eine gute Einführung in UpdateControls kann man beim CODE Magazin lesen.

 

Mir gefallen bisher die Lösungen mit PostSharp am Besten. Damit lassen sich alle drei Punkte auf einmal erschlagen.

  1. Mit einem PostSharp Attribut, das auf die ViewModel Klasse geklebt wird, lässt man die INotifyPropertyChanged Implementierung automatisch einweben.
  2. Es gibt keine Magic Strings mehr, da auch das Feuern des ProperyChanged Events automatisch eingewoben wird. Verschreiber sind dadurch ausgeschlossen, Refactoring ist kein Problem.
  3. Der Code bleibt sauber und lesbar, da der ganze Notifikationscode erst nachträglich hinzugefügt wird.
    Der nächste Schritt

Ein Kollege von mir hatte die Idee, die Verwendung von PostSharp in Verbindung mit dem MVVM Pattern noch einen Schritt weiter zu treiben. Wir verwenden jetzt ein [ViewModelAspekt] PostSharp Attribut, mit dem die ViewModels versehen werden.

[ViewModelAspect]
public class MyViewModel
{
    private string _name;

    public string Name
    {
        get{ return _name;}
        set{ _name = value;}
    }

    public void Save()
    {
        // do sth.
    }
}

Dieser Aspekt macht folgendes:

  • Implementierung von INotifyPropertyChanged
  • Für alle public Properties wird im Setter der PropertyChanged Event gefeuert
  • Für alle public void Methoden wird eine Command Property erzeugt, welche mit Hilfe des Delegate/Relay Commands wiederum diese Methode aufruft.
    Dadurch haben wir es geschafft, den Overhead für die Verwendung des MVVM Patterns sehr gering zu halten. Die nächsten Wochen werden zeigen, ob sich diese Variante bewährt und alle Use Cases damit abgedeckt werden können.
Kick it on dotnet-kicks.de

WPF Grundlagen – Wie finden Applikation und Fenster zusammen?

July 29th, 2009 Bernd 3 comments

Die Projektvorlagen dieser Welt machen es dem Entwickler heutzutage sehr einfach, zu einer lauffähigen Anwendung zu kommen. Ein paar Klicks und schon ist das Gerüst z.B. für eine WPF Applikation fertig. Dabei passiert aber auch so manches hinter den Kulissen, was auf den ersten Blick nicht so leicht ersichtlich ist. Deswegen stellen wir uns heute die Frage, wie bei einer vom Visual Studio generierten WPF Anwendung, das Applikationsobjekt und das Hauptfenster zusammenfinden.

Wie sieht die Struktur einer WPF Anwendung aus, die mit dem Projekttemplate von Visual Studio 2008 erstellt wurde?

 Struktur einer WPF Anwendung in VS 2008

Der Screenshot zeigt den Aufbau einer solchen WPF Applikation. Es fallen auf Anhieb zwei Teile auf, die jeweils aus einem XAML File und einem C# File bestehen:

  • App.* – beschreiben das Applikationsobjekt
  • Window1.* – beschreiben das Hauptfenster der Applikation
    Und, wie nicht anders zu erwarten, läuft das Programm wenn F5 im Studio gedrückt wird. Aber was passiert hier? Dazu werfen wir einen Blick auf den Sourcecode.

XAML File für das Haupfenster

<Window x:Class="WpfApplication.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
    </Grid>
</Window>

Hier gibt es nichts spektakuläres zu sehen. Es wird ein Objekt vom Typ Window definiert, ein paar Eigenschaften wie Titel, Höhe und Breite angegeben und zwei XML Namespaces eingebunden. Interessant ist der Teil “x:Class=”WpfApplication.Window1”. Mit dem Attribut x:Class wird angegeben, dass zu diesem XAML Code noch ein weiterer Teil, nämlich der C# Teil gehört. “WpfApplication” gibt hierbei den Namespace und “Window1” den Klassennamen an. Ein Blick in das zugehörige C# File zeigt dann auch eine partielle Klasse Window1.

C# File für das Hauptfenster

using System.Windows;

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

Bei einem frisch erstellten Projekt ist diese Code-Behind Datei bis auf den Aufruf von “InitializeComponent()” ziemlich leer (die überflüssigen “using” Anweisungen habe ich gleich vom Resharper entfernen lassen).

 

XAML File für die Applikation

<Application x:Class="WpfApplication.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <Application.Resources>
    </Application.Resources>
</Application>

Der Aufbau ist ähnlich wie bei dem Window. Hier taucht erstmals eine Verbindung zwischen der Applikation und dem Fenster auf, indem das StartupUri Attribut auf den Dateinamen des XAML Files des Fensters gesetzt wird.

C# File für die Applikation

using System.Windows;

namespace WpfApplication
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
    }
}

Hier herrscht gähnende Leere. Die partielle Klasse des Applikationsobjektes ist komplett leer. Jetzt stellt sich die Frage, wo denn die “Main” Methode unserer Applikation ist. Irgendwie muss die Anwendung ja gestartet werden. Hier hilft uns der “Show All Files” Button im Solution Explorer weiter:

/page/2/Show_all_files_in_Solution_Explorer/index.html

Jetzt werden auch alle temporären Dateien angezeigt, die während des Kompiliervorgangs entstanden sind. Aus dieser Vielzahl sehen wir uns ein File ein bisschen genauer an:

App.g.cs

Das ‘g’ im Dateinamen steht für “generated”. Es handelt sich hier also um einen generierten Teil der Applikationsklasse. Ich picke mal den interessanten Teil heraus:

...
public void InitializeComponent() {

    #line 4 "..\..\App.xaml"
    this.StartupUri = new System.Uri("Window1.xaml", System.UriKind.Relative);

    #line default
    #line hidden
}

/// <summary>
/// Application Entry Point.
/// </summary>
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static void Main() {
    WpfApplication.App app = new WpfApplication.App();
    app.InitializeComponent();
    app.Run();
}
...

Et voilà, hier findet sich auch eine Main() Methode welche den Einstiegspunkt für das Programm darstellt. In InitializeComponent() findet sich auch wieder die StartupUri Eigenschaft, die in App.xaml gesetzt wurde. Durch das setzen dieser Eigenschaft wird das von der URI referenzierte Fenster beim Start der Applikation angezeigt und als dessen Hauptfenster gesetzt (ist also über Application.Current.MainWindow erreichbar).

Auch wenn es den erfahrenen WPF Entwickler vielleicht gelangweilt haben mag – ich finde solche Grundlagen wichtig. Eventuell war ja für den einen oder anderen WPF Einsteiger etwas Neues/Interessantes dabei.

Kick it on dotnet-kicks.de

.NET Open Space Süd 2009

July 13th, 2009 Bernd No comments


.NET Open Space vom 11.07. bis 12.07.2009 in Ulm

Wow! Das war wirklich ein gelungenes Wochenende. Die Rede ist vom ersten .NET Open Space Süd, welcher vom 11.09. – 12.09. in Blaustein bei Ulm stattfand. Nach dem Vorbild der ALT.NET Konferenz in London und dem .NET Open Space in Leipzig haben Thomas Schissler und Alexander Zeitler auch für den Süden der Republik eine Communityveranstaltung der besonderen Art organisiert.

Eine Konferenz ohne Agenda, ohne geplante Vorträge? Kann das funktionieren? Ja, und zwar sehr gut! Die Teilnehmer organisieren sich selbst, machen Themenvorschläge und finden sich dann in Gruppen zusammen um die Themen zu diskutieren. Eine wunderbare Abwechslung zur Berieselung bei den herkömmlichen Veranstaltungen. In Ulm haben auf diese Weise ca. 60 Teilnehmer ihr Wissen und ihre Erfahrung ausgetauscht.

Dabei wurden sowohl technische Themen wie ASP.Net MVC, WPF, ORM, AOP,… unter die Lupe genommen als auch Bereiche wie SCRUM oder Getting Things Done ausführlich diskutiert. Danke an alle Teilnehmer, durch die solch ein Event erst möglich wird.

Um den Kopf wieder frei zu bekommen, darf natürlich auch ein entsprechendes Rahmenprogramm nicht fehlen. Auch hier haben sich Thomas und Alex nicht lumpen lassen und haben uns den Abend mit Bauchtanz und Feuershow verschönt. Wenn dann auch noch das Catering vom lokalen Sportverein so perfekt vonstatten geht, gibt’s wirklich nichts zu meckern.

Wer sich ein Bild machen möchte, findet Bilderserien dazu von Peter, Jan und Albert hier, hier und hier. Weiteres Feedback und zusätzliche Informationen gibt es auf dem Schwarzen Brett.

Bis zum nächsten .NET Open Space – vielleicht schon in Leipzig.

Kick it on dotnet-kicks.de
Categories: Verschiedenes Tags:

Wie kriege ich mit, ob der Rechner gelockt wird?

June 24th, 2009 Bernd No comments

Ja, ja, wenn man es mal weiß, dann ist alles einfach und sonnenklar.  Ich wollte vor kurzem wissen, wie ich in einem Programm darauf reagieren kann, wenn der Computer gesperrt/gelockt wird. Das rauszufinden, hat überraschenderweise recht lange gedauert. Dabei hätte ich nur nach “SystemEvents” googeln müssen. Aber das wusste ich zu dem Zeitpunkt natürlich nicht.

Die SystemEvents Klasse aus dem Microsoft.Win32 Namespace bietet einen Sack voll Events an, um auf Systemereignisse reagieren zu können. Unter anderem gibt es ein SessionSwitch Event:

image

Mit einem kleinen Testprogramm sieht man auch sofort, dass dieses Event gefeuert wird, wenn der Computer gesperrt wird:

static void Main(string[] args)
{
    SystemEvents.SessionSwitch +=
    	(s, e) => Console.WriteLine("Event {0} received...",
                                	e.Reason);
    Console.ReadLine();
}

Ein Sperren und Entsperren ergibt folgende Ausgabe:

Event SessionLock received…

Event SessionUnlock received…

War doch gar nicht so schwer. Im realen Leben solltet ihr aber auf keinen Fall vergessen euch wieder von dem Event abzumelden. Ansonsten kann das Objekt, welches sich an dem Event angemeldet hat, nicht vom Garbage Collector abgeräumt werden.

Kick it on dotnet-kicks.de

Fünf Freunde: Action, Predicate, Comparison, Converter und Lambda Ausdrücke

May 21st, 2009 Bernd 5 comments

Ich habe den Eindruck, dass die generischen Delegates aus dem .Net Framework vielerorts immer noch ein Schattendasein fristen. Mit ein paar einfachen Beispielen die zeigen, wofür man Action, Predicate und Co. verwenden kann, möchte ich Lust auf mehr machen.

Generische Delegates ersparen dem Entwickler die Arbeit eigene Delegates zu deklarieren und kommen häufig in Verbindung mit Containerklassen zur Anwendung.

Als Spielzeugklasse habe ich mir diesmal etwas ganz aussergewöhnliches einfallen lassen. Und zwar eine Klasse Person:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public bool IsCool { get; set; }

    public override string ToString()
    {
        return String.Format( "{0} is {1}.", Name, IsCool ? "cool" : "not cool" );
    }
}

Dazu erzeugen wir uns noch ein paar "Versuchspersonen":

List<Person> persons = new List<Person>();

persons.Add( new Person {Name = "Karin", Age = 39} );
persons.Add( new Person {Name = "Simon", Age = 23} );
persons.Add( new Person {Name = "Fritz", Age = 34} );
persons.Add( new Person {Name = "Georg", Age = 56} );
persons.Add( new Person {Name = "Susi", Age = 67} );
persons.Add( new Person {Name = "Toni", Age = 45} );

Action<T> Delegate

Der Action<T> Delegate kapselt eine Methode die einen Parameter übergeben bekommt und keinen Wert zurückgibt. Mit .Net 3.5 wurden noch zusätzliche Action Delegates eingeführt, die bis zu vier Parameter bekommen (Action<T1, T2>, Action<T1, T2, T3> und Action<T1, T2, T3, T4>).

Ein Action Delegate wird z.B. als Parameter für die ForEach Methode der Klasse List<T> benötigt. ForEach iteriert über die gesamte Liste und führt für jedes Element die übergebene Methode aus.

Action<T> delegate

Hier ein paar Beispiele:

Informationen über alle unsere Personen auf der Console ausgeben:

persons.ForEach(Console.WriteLine);

In Verbindung mit einem Lambdaausdruck werden alle Personen ganz schnell cool:

persons.ForEach(p => p.IsCool = true);

Predicate<T> Delegate

Der Predicate<T> Delegate kapselt eine Methode die einen Parameter (vom Typ T) übergeben bekommt und true oder false zurückgibt. Es steckt aber auch Semantik in dem Predicate Delegate: er definiert einen Satz von Kriterien und überprüft ob das übergebene Objekt diese Kriterien erfüllt. Das klingt erstmal ziemlich geschwollen, aber ein Beispiel macht das schnell klar.

Predicate<T> delegate

Um z.B. alle Personen die älter als 50 sind zu entfernen, schreiben wir:

persons.RemoveAll( p => p.Age > 50 );

Mit der Methode Exists kann überprüft werden, ob in der Liste Element enhalten sind, die eine bestimmte Bedingung erfüllen:

if (persons.Exists(p => p.Name == "Toni"))
{
    Console.WriteLine("A person with name Toni exists");
}

Comparison<T> Delegate

Der Comparison<T> Delegate kapselt eine Methode die zwei Objekte gleichen Typs vergleicht.

public delegate int Comparison<T>
(
	T x,
	T y
)

Als Rückgabewert dient ein Integer der anzeigt, ob die beiden Objekte gleich sind:

Rückgabewert Bedingung
Kleiner als 0 x ist kleiner als y
0 x und y sind gleich
Größer als 0 x ist größer als y

Um die Liste von Personen nach dem Alter aufsteigend zu sortieren, übergebe ich der Sort() Methode einen Comparison Delegate:

image

persons.Sort( (person1, person2) => person1.Age.CompareTo( person2.Age ) );

Converter<TInput, TOutput> Delegate

Der Converter<TInput, TOutput> Delegate repräsentiert eine Methode die ein Objekt vom Typ TInput als Parameter bekommt und ein Objekt vom Typ TOutput zurückgibt. Der Hauptanwendungsfall ist das Konvertieren von Elementen in einem Array oder einer Liste.

Die Liste von Personen kann z.B. einfach in eine Liste von Namen konvertiert werden:

List<string> names = persons.ConvertAll( p => p.Name );

Durch das Naming der Methode ConvertAll geht auch sehr schön hervor, dass es sich um eine Konvertierung handelt. Dadurch entsteht lesbarer, verständlicher Code.

 

Die generischen Delegates des.Net Frameworks, bieten eine elegante Möglichkeit mit den Containerklassen zu arbeiten. Durch die Verwendung von Lambda Ausdrücken führt das Finden, Sortieren usw. von Listen zur sehr schönem, lesbaren Code. Ich finde die generischen Delegates klasse!

Kick it on dotnet-kicks.de