Beispiel Model-View-Presenter mit WinForms
Geschrieben von Stefan Kölle in How-To, MVC, tags: Contract-First, MVP, WinFormsIm 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
Hallo,
ich finde die Anwendung sehr schön und es sind die Eine oder Andere Anregung für mich auch enthalten .
Die Konfiguration über Xml würde ich vielleicht noch versuchen zu eliminieren, es wird ja schönes Benennungsmuster eingehalten (CoC).
Ich habe es zwar noch nicht laufen lassen, es sah aber im TimelinePresenter so aus, als wenn noch ein versehentliches Verlassen verhindert werden könnte…
Viele Grüße,
Jan
Hallo Jan,
danke fuer deinen Input, das Container.xml ist wirklich nicht schoen und koennte man sicher eleganter loesen. Du hast mich da auf eine gute Idee gebracht.
Was meinst du mit versehenliches Verlassen?
Gruss
Stefan
Hallo nochmal,
freut mich, wenn ich damit einen Impuls geben konnte.
Zu dem versehentlichen Verlassen:
Ich habe vor Kurzem etwas über das “graceful exit” einer Anwendung gelesen. Deine Anwendung hatte ich nicht gestartet, sondern mir nur den Quellcode quergelesen. Dabei ist mir aufgefallen, dass nur ein Application.Exit beim Close ausgeführt wird, der Anwender erhält keine Chance doch in der Anwendung zu bleiben. Eventuell habe ich es auch einfach nicht gesehen (habe es ja auch nicht laufen lassen)…
Soll kein Mäkeln an Kleinigkeiten sein, sondern eher ein Beispiel dafür, dass mir die Anwendung recht gut gefällt.
Viele Grüße,
Jan