Laden...

Windows Forms MVVM

Letzter Beitrag vor einem Jahr 11 Posts 995 Views
Windows Forms MVVM

Guten Tag zusammen,

ich bin neu hier im Forum und habe in der Vergangenheit immer mal kleine Tools mit Windows Forms erstellt. Nicht unbedingt schön aber funktioniert.
Jetzt erstelle ich eine Applikation aus einer MainForm welche ein Panel mit Buttons als Menü besitzt und ein Hauptpanel daneben in das verschiedene Views als UserControl angezeigt werden. Dort können dann verschiedene Aufgaben erledigt werden wie zb etwas über den SerialPort schicken etc.

Jetzt möchte ich das ganze sauberer machen und habe mich in MVVM eingelesen und auch schon viel darüber dass man es auch in WinForms umsetzen kann. Ich weiß das WPF hier das Mittel der Wahl wäre, aber die Winforms App steht soweit.

Es stellt auch kein Problem dar Bindings etc zu erstellen. Meine Frage wäre aber jetzt ob jede UserControl eine View mit eigenem ViewModel darstellt oder man ein einziges ViewModel für die Form und die UserControls erstellt?

Wie ich das verstanden habe Zeigt die View durch die Bindings nur die Daten an, das ViewModel modelliert die Daten für die Anzeige und die Models sind quasi die BusinessLogic um die Daten zu besorgen.
Beispiel bei mir:

Ein Gerät kann mir seinen Batteriestatus per USB (SerialPort) mitteilen und ich möchte das anzeigen:

  • Im Menü kann man auf "Gerät" klicken und die UserControl mit Batterie Status (TextBox) wird angezeigt
  • Als Model gibts ne Klasse die mit dem Gerät redet und einer Methode GetBattery();
  • Die ViewModel ruft GetBattery() auf und bringt die Daten in ein tolles Format z.B. "14,4V". Dieser String ist dann eine Property.
  • Die View TextBox hat als Binding den Batterie Status vom ViewModel und zeigt es so an wie vom ViewModel aufbereitet.

Ist die Vorgehensweise korrekt so?

Wenn ich das ganze mit WPF mache hätte ich ja quasi das selbe nur halt eben mit einer XML View und kann das ViewModel von oben genauso verwenden oder?

Die Projektstruktur sieht folgendermaßen aus:

  • Solution "DeviceReaderApp"
    • Dll Projekt "USBDevice"
    • Dll Projekt "Database" <- Beispiel für irgendeine andere Komponente
    • etc...
    • WinForms Projekt "MainWindow"
      • ViewModels
        • MainViewModel
      • Views
        • MainForm
        • UserControl1
        • Usercontrol2

Bitte nicht steinigen, das ist meine erste größere Applikation die ich schreibe.

Grüße!

In Windows Forms ist MVVM in der Form kaum möglich. Ist dafür nicht konzipiert.
In WinForms ist der MVP (Model-View-Presenter) Pattern eher üblich, sobald man Binding möchte (was richtig ist).

Deine Projektstruktur kannst so starten, aber eigentlich ist das nicht im Sinne vom Projektdesign in .NET (respektive den Namespaces).
.NET architecture - Names of Assemblies and DLLs
.NET architecture - Names of Namespaces

Hallo Abt und Toby42,

MVP bei WinForms würde ich eher nicht empfehlen, s.a. (besonders meine Beiträge in) MVP Winforms : verstehen und lernen, ist es so richtig?

Zitat von Toby42

Wenn ich das ganze mit WPF mache hätte ich ja quasi das selbe nur halt eben mit einer XML View und kann das ViewModel von oben genauso verwenden oder?

Technisch kann man zwar MVVM auch für WinForms benutzen, jedoch sind View und ViewModel meistens doch logisch voneinander abhängig, so daß man für eine neue UI-Technologie auch häufig die VMs anpassen muß (wenn es um mehr geht als das Binden von Strings und Zahlenwerten, z.B. UI-technologische Datentypen).

Edit:

Als Beispiel für einen UI-technologischen Datentyp die Anzeige eines Bildes:

  • für WinForms: System.Drawing.Image/Bitmap
  • für WPF: System.Windows.Media.ImageSource

Hallo,

generell habe ich mir das dann auch so vorgestellt dass ich MVVM (auch wenn es nicht so perfekt für MVVM ist) umsetzen kann und nachher vll die UI auf WPF umzuziehen wenn ich mich da etwas mehr eingearbeitet habe.

Hierzu habe ich zb auch diesen Forum Eintrag gelesen, bei dem auch hervorging dass es ganz gut geht:

Kann man MVVM mit Windows Forms verwenden? | myCSharp.de

Dazu gibt es noch das CommunityToolkit.Mvvm als NuGet was einem die Sache schon eher einfacher macht. Selbst wenn das ganze mit Winforms nicht perfekt ist, finde ich das schon sauberer und aufgeräumter.

Wenn es natürlich absolut Bad Practice ist, verstehe ich natürlich das eher nicht so umzusetzen. Der meiste Aufwand sind sowieso die einzelnen Komponenten (DLL Projekte) in der Solution. Das mache ich einfach deshalb so damit sie sehr einfach widerverwendbar sind.
Habe mich auch damals belesen dass man das durchaus so machen kann um einzelne funktionale Bestandteile schön voneinander zu trennen.

Zitat von Toby42

Der meiste Aufwand sind sowieso die einzelnen Komponenten (DLL Projekte) in der Solution. Das mache ich einfach deshalb so damit sie sehr einfach widerverwendbar sind.
Habe mich auch damals belesen dass man das durchaus so machen kann um einzelne funktionale Bestandteile schön voneinander zu trennen.

Eine Trennung und Wiederverwendbarkeit kannst Du auf viele Arten herstellen; die Trennung der Projekte ist durchaus für die Verantwortlichkeiten da.

  • MyCompany.MyProduct
    Hier drin liegt der gesamte Kern Deiner Anwendung, darunter Namespaces wie
    MyCompany.MyProduct.Database
    MyCompany.MyProduct.Database.Repositories
    MyCompany.MyProduct.Database.Entities
    MyCompany.MyProduct.Models
    MyCompany.MyProduct.Configuration
    Es ist also alles enthalten, um diese Anwendung zu beitreiben
  • MyCompany.MyProduct.ConsoleApp
    Ist nun zum Beispiel die Consolen Anwendung und alle Bestandteile dazu
  • MyCompany.MyProduct.WebApp
    eben die WebApp
  • MyCompany.MyProduct.DesktopApp
    Eben die Desktop App

Und dann hast eben auch Dinge wie

  • MyCompany.MyProduct.DesktopApp.FeatureA
    Alle Inhalte für ein spezifisches Feature
    MyCompany.MyProduct.DesktopApp.FeatureA.Views
    MyCompany.MyProduct.DesktopApp.FeatureA.ViewModels
    MyCompany.MyProduct.DesktopApp.FeatureA.Mappers

So hast Du eine Modularisierung und eine hohe Wiederverwendbarkeit.


Das ist die Idee von Namespaces und Projekte.

Man legt aber nicht jede Sicht in ein eigenes Projekt. Kannst so anfangen, wirst aber merken, dass das auf Dauer nich so der Bringer ist.
Les Dir ruhig die Konzepte durch, wie .NET funktioniert und wie das Zeug gedacht ist.

Zitat von Th69

Technisch kann man zwar MVVM auch für WinForms benutzen, jedoch sind View und ViewModel meistens doch logisch voneinander abhängig, so daß man für eine neue UI-Technologie auch häufig die VMs anpassen muß (wenn es um mehr geht als das Binden von Strings und Zahlenwerten, z.B. UI-technologische Datentypen).

Edit:

Als Beispiel für einen UI-technologischen Datentyp die Anzeige eines Bildes:

  • für WinForms: System.Drawing.Image/Bitmap
  • für WPF: System.Windows.Media.ImageSource

Wenn man im ViewModel Datentypen aus dem UI-Framework verwendet, dann hat man schon im Ansatz etwas falsch gemacht. So etwas sollte bei jedem Review sofort gerügt werden.

Nehmen wir mal das Beispiel mit dem Bild und wie man das bei WPF/MAUI macht:

Im ViewModel eine Eigenschaft vom Typ byte[] (Bild-Rohdaten) oder string (Verweis auf Bild per Dateiname oder URL) erstellen und diese Eigenschaft in der View an die Source Eigenschaft des ImageControls binden.

qed

Hat die Blume einen Knick, war der Schmetterling zu dick.

Wenn man im ViewModel Datentypen aus dem UI-Framework verwendet, dann hat man schon im Ansatz etwas falsch gemacht.

Das ist aber auch nur reine Theorie.

Es ist "völlig normal" dass ein ViewModel durchaus paar Sachen hat, die ne Bindung an das UI-Framework erfordern.
Das kannst in sehr vielen Fällen gar nich vermeiden, ohne das Rad neu zu erfinden / ineffizient zu werden / inperformant zu werden...

Zitat von BlonderHans

Nehmen wir mal das Beispiel mit dem Bild und wie man das bei WPF/MAUI macht:

Im ViewModel eine Eigenschaft vom Typ byte[] (Bild-Rohdaten) oder string (Verweis auf Bild per Dateiname oder URL) erstellen und diese Eigenschaft in der View an die Source Eigenschaft des ImageControls binden.

qed

Leider nix qed, denn für Windows Forms (um das es hier geht), wird das nämlich nicht funktionieren, da man z.B. bei der PictureBox nur den Datentyp System.Drawing.Image für die Eigenschaft Image binden kann.

Edit: Es gibt aber zumindestens seit .NET 7 (in der Vorschau) und dann (geplant) für .NET 8 standardmäßig aktiviert, bei WinForms nun die Möglichkeit ebenfalls der Nutzung von ICommand und DataContext(denn das war ja bisher nur WPF/MAUI vorbehalten): Windows Forms Binding Improvements in .NET 7 for MVVM Support . Nun kann man also using System.Windows.Inputauch bei WinForms-Viewmodels dafür nutzen.

Halten wir fest, bei mir fliegt so etwas im Review heraus. Sollte die Implementierung nach Lehrbuch Schwierigkeiten machen (zu aufwendig, zu langsam, ...) dann würde ich auch einen pragmatischen Ansatz verfolgen. Aber erst dann.

Hat die Blume einen Knick, war der Schmetterling zu dick.

Wenn es auch was kosten darf... Schaust Du hier: MVVM Framework for WinForms (devexpress.com)

Vielen Dank Abt für diese kleine Übersicht und auch an alle anderen für die Diskussion! Namespaces habe ich natürlich auch an meine Struktur angepasst.
Ich hatte mich mal irgendwo belesen dass es durchaus üblich ist die Solution als ganzes Projekt zu sehen und die verschiedenen Teile der Anwendung als Projekte in der Solution zu machen.

Meine Solution und Projektstruktur schien mir doch bisher ziemlich logisch und vernünftig. Jedes der Projekte für eine bestimmte logische Funktionalität bekommt auch ein Interface, (zb. wenn ich mit 2 Geräten reden muss die die selben Funktionen bieten aber anders angesprochen werden).

Es wird auch unter keinen erdenklichen Umständen ein zweites User Interface in Form von zb einer WebApp oder sowas geben. Das ist eine reine Desktop Anwendung, die mit Geräten und Datenbanken redet.

Ich komme aus der Mikrocontroller Entwicklung bei der natürlich ganz anders aufgebaut wird. Ich versuche jetzt nur eine möglichst praktikable und übersichtliche "Architektur" zu schaffen, damit einzelne Änderungen an verschiedenen Stellen sehr gut machbar sind ohne alles direkt anzufassen.

Ich verstehe auch dass WPF für MVVM viel besser geeignet ist und beschäftige mich nebenbei damit. WPF ist ja auch kein Hexenwerk, ich habe nur mit Forms angefangen, da ich damit schon öfter kleine "Test-Tools" erstellt habe, die absolut keinen Anspruch auf perfekte Strukturierung gesetzt haben. Wenn die Projektzeit es zulässt würde ich auch das User Interface auf WPF umziehen, was auch nicht der meiste Aufwand wäre bei dem Umfang den diese Anwendung hat. Die meiste Arbeit ist eben die Ebene unter dem User Interface.

Viele Grüße!