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

Share
5 Antworten zu “MVP mit WinForms (Model-View-Presenter)”
  1. [...] seinem Beitrag MVP mit WinForms (Model-View-Presenter) demonstriert er wie man es machen könnte. Ein zweiter Teil soll demnächst folgen, wo er sein [...]

  2. Marcus sagt:

    Hallo,

    danke für diesen sehr hilfreichen einblick.
    Wann wird der zweite Teil folgen? :)

    lg

  3. Hallo Marcus,

    der Democode zum zweiten Teil steht nun bereits, jetzt geht es an’s zusammenschreiben…

    Hast du schon offene Fragen die ich in dem zweiten Beitrag behandeln kann?

    Gruss
    Stefan

  4. Sebastian sagt:

    Für ein Einsteiger eine gute Anleitung. Vielleicht kannst du nochmal gezielt auf die Unterschiede zwischen Passive View und Supervising Controller eingehen und vorallem wo sich welcher Einsatz lohnt. Ich bevorzuge ja selber die Passive View, weil sie mir eine klarer Kapselung liefert.

  5. Hallo Sebastian,

    bei Passive View stoert mich, dass der Presenter die View exakt kennen muss. Will man mal ein Control durch ein anderes ersetzen muss man im Presenter einiges aendern, das klingt fuer mich nicht nach single responsibility. Andererseits verstehe ich schon deinen Hinweis, ich wollte erst auch mit Passive View starten, habe mich dann aber wegen obigem Grund fuer Supervising Controller entschieden.

    Du hast Recht, ich koennte dazu noch einen Blogpost schreiben.

    Gruss
    Stefan

  6.  
Hinterlasse einen Kommentar