Archive for the “MVC” Category

Im Teil 1 (MVP mit WinForms) habe ich die Grundgedanken zur Implementierung von MVP in WinForms vorgestellt, mit der man WinForm-Anwendungen mit UnitTests abdecken kann. In einer komplexeren WinForm-Anwendung gibt es neben dem Startform auch mehrere Unterforms, die durch das Hauptform aufgerufen werden müssen.

Das Beispielprojekt

Zur Demonstration habe ich ein Beispielprogramm mit MVP entwickelt, welches einen sehr einfachen Twitterclient darstellt. Das Beispiel wurde nach Contract-First komponentenorientiert gebaut und besteht neben der MVP-Komponente aus weiteren Komponenten.

Die weiteren Komponenten haben nichts mit MVP zu tun, sondern sollen nur zeigen, wie man MVP in diesem Umfeld integriert. -> Den kompletten Sourcecode downloaden

Die Funktionen des Twitter-Clients sollen sein:
1. Anzeige der 20 neuesten Meldungen aus der Timeline im Hauptfenster
2. Der Benutzer soll Status-Updates bei Twitter posten können
3. Die Zugangsdaten des Twitter-Accounts sollen gespeichert werden können

Die WinForm-Komponente

Um die Funktionen abzubilden, sind 3 Screens notwendig:
1. Hauptbildschirm mit der Timeline des Twitter-Accounts
2. Form für das Absenden eines Twitter-Status-Updates
3. Konfigurationsbildschirm für den Twitter-Account

Jedes WinForm besteht aus einer View-Klasse (dem WinForm), einem Model, welches als Singleton im IoC-Container konfiguriert wird und einem Presenter. Die einzelnen Funktionen in den Views sind im Beispielprojekt durch Tests abgedeckt und zeigen die notwendigen Tests für diese Art der Implementierung. Gerade durch geringen Funktionsumfang kann man das Muster der Verwendung gut erkennen.

In der MVP-Komponente befindet sich auch der “Inversion of Control”-Container, der die einzelnen Komponenten zusammenfügt. Dies könnte auch in einer extra Runner-Komponente ausgelagert sein.

Aufrufen eines weiteren WinForms

Alle Abhängigkeiten werden per Dependency-Injection-Container an den Presenter übergeben. Da das Hauptform alle weiteren Views und Presenter instanziert, müssten diese alle bereits beim Programmstart instanziert werden. Um dies zu verhindern, habe ich eine IPresenterFactory eingeführt, die zur Laufzeit weitere Presenter nachinstanzieren kann. Die Factory selbst hält eine Referenz auf den Container und wird bei Programmstart im Container hinzugefügt. Um sicherzustellen, dass weiterhin alle anderen Abhängigkeiten über den Konstruktor definiert werden, können aus dieser Factory nur Klassen instanziert werden, die IPresenter implementieren.

Fazit
Mit dieser Beispielanwendung kann man eine mögliche Implementierung von Model View Presenter in der Variante Supervising Controller sehen. Es ist also auch mit WinForms eine voll getestete MVP-Implementierung zu erstellen.

Anhang:
Kompletter Sourcecode der Beispielanwendung als ZIP

kick it on dotnet-kicks.de

Comments 3 Comments »

Wir setzen seit langer Zeit interne Tools mit WinForms um und hatten seit Anfang an Probleme bei der Testbarkeit dieser Anwendungen. Auch wenn man bei WinForms versucht, jeglichen Code aus der Codebehind-Datei zu entfernen, tut man sich mit dem Unit-Testing weiterhin schwer.

Auf der Suche nach einer Lösung zur besseren Testbarkeit stößt man immer wieder auf ein MVC- oder MVP-Modell, aber nirgends gibt es echte Beispiele in Verbindung mit WinForms. Ich möchte nun in einer Demo-Anwendung einen möglichen Ansatz zur Umsetzung des MVP-Patterns bei WinForms beschreiben.

Die einzelnen Bestandteile von MVP

Das Model repräsentiert den gesamten Zustand und die Logik der Ansicht. Das Model wird über den Presenter gefüllt. Die View enthält keinerlei Anwendungslogik, während der Presenter den Programmablauf steuert.

MVP gibt es in zwei Varianten – “Passive View” und “Supervising Controller”. Ich habe mich bei der Implementierung für “Supervising Controller” entschieden, da es auf den ersten Blick weniger Code erfordert. Der Unterschied von beiden Varianten besteht darin, dass bei “Passive View” die View weder Presenter noch Model kennt und als dumme View nur über den Presenter befüllt wird. Mir gefällt dabei jedoch nicht, dass der Presenter dabei die View genau kennen muss.

Bei “Supervising Controller” kennt nun jeweils die View als auch der Presenter das Model, darüber findet der Datenaustausch statt.

Die konkrete Implementierung

Der Presenter wird mit der View und dem Model instanziert.

10 public class MainPresenter : IMainPresenter

11 {

12 private readonly IMainView m_view;

13 private readonly IMainModel m_model;

14

15 public MainPresenter(IMainView view, IMainModel model)

16 {

17 m_view = view;

18 m_model = model;

19

20 InitializeModelAndRefreshView();

21 InitializeAndShowView();

Die View ist das WinForm und wird auch mit dem Model instanziert. Das Model selbst ist ein über den IoC-Container realisiertes Singleton.

10 public partial class MainView : Form, IMainView

11 {

12 private readonly IMainModel m_model;

13

14 public MainView(IMainModel model)

15 {

16 m_model = model;

17

18 InitializeComponent();

19 this.Closed += delegate { ViewClosed(this, new EventArgs()); };

Das Model beinhaltet nur Properties mit allen Daten, die zur Anzeige der View notwendig sind.

Wenn der Presenter Daten im Model ändert, ruft dieser explizit eine UpdateMethode in der View auf. Die View selbst stellt EventHandler zur Verfügung, auf die sich der Presenter hängt, um Aktionen auf der View weiter zu bearbeiten.

60 public event EventHandler<EventArgs> ViewClosed;

Im Presenter sieht dies folgendermaßen aus:

31 private void InitializeAndShowView()

32 {

33 m_view.Title = “ResourcerClient V1.0”;

34 m_view.ViewClosed += new EventHandler<EventArgs>(mainView_ViewClosed);

42 void mainView_ViewClosed(object sender, EventArgs e)

43 {

44 Application.Exit();

45 }

Damit ist die Grundlage des MVP Patterns bei WinForms angelegt. Der Presenter ist damit schon voll testbar, da er komplett von der View abgekoppelt ist. Bis jetzt sieht alles sehr einfach aus. Auch einige andere Beispiele aus dem Netz gehen soweit. Doch wie instanziert man jetzt eine weitere View bzw. einen weiteren Presenter?


Mehr dazu im zweiten Teil

kick it on dotnet-kicks.de

Comments 5 Comments »

Gestern Abend waren wir alle bei einem super Vortrag von Albert über ASP.MVC v2. Die neue Version soll am 22. März zusammen mit .NET 4.0 rauskommen.
Ich will jetzt nicht über all die Neuigkeiten sprechen, die wir gestern erfahren haben und worüber wir uns jetzt schon freuen müssen, nur über einen speziellen Teil: die Validierung der Daten durch Attribute.

Der Grund ist folgender: wir haben uns vor ca. 1 Jahr ein eigenes Attribut namens ObligatoryFieldAttribut gebaut. Dieses wird über die Properties gesetzt, die wir für die Speicherung als unerheblich markieren möchten. Die Überprüfung erfolgt dann durch Reflection.

Und was haben wir gestern erfahren? In der neue MVC-Version gibt es ein neues Attribut namens Required, das genau das tut!

Ihr könnt euch sicher vorstellen, was wir uns gestern gedacht haben: wir lagen genau richtig und wir waren unserer Zeit voraus! Oder haben unsere Büro-Nachbarn – die eine Microsoft Subsidiary sind – Kameras bei uns installiert 😉 ?

Comments No Comments »