Diskussionsthread: MVVM mit WinForms - kleiner Einstieg für Anfänger

  • VB.NET
  • .NET 7–8

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Diskussionsthread: MVVM mit WinForms - kleiner Einstieg für Anfänger

    ausgelagert aus MVVM mit WinForms - kleiner Einstieg für Anfänger ~VaporiZed

    Für mich ist an MVVM genau dieser Punkt, den du ansprichst noch das Unverständlichste.
    Konkret: Warum soll denn überhaupt der Button-Klick nicht mehr über Button.Click laufen?
    Ja DataBinding ist ganz cool. Mit dem Relaycommand macht man eine extra Property, die dann über interne Wege dieser ominösen Command-Eigenschaft wie ein Eventhandler gesteuert wird.
    CanExecute ein extra goody, das spart einem Arbeit, aber wenn man so nen Button nicht disablen muss, dann ist es für mich ein "so gehts auch", aber warum, kein Plan.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Nicht verwirrt sein: Wir als Team haben uns vor ner Weile dazu entschieden, Fragen zu z.B. Tipps&Tricks-Threads auszulagern, damit wir nicht jeden Post freigeben müssen.

    Ja, es klingt erstmal nach Pfeil-Rücken-Brust-Auge, hilft aber bei der Entkopplung von UI und ("Geschäfts"-)Logik. Wenn das UI nix mehr weiß, kann man es auch ersetzen, umbauen, sonstewas. Und wenn die anderen Klassen sich um alles außer fast allen UI-Angelegenheiten kümmern, kann man diese (besser) testen. Stichwort kontinuierliche Testung des Projekts.
    Das Thema hatte ich mal hier: WinForms Projektentwicklung bzgl. der Rolle des Formulars mit dem Hintergrund: Wie beseitigt man Zuständigkeiten der Formklasse.

    Dort werd ich zeitnah auch noch einen Post zum Thema MVVM in WinForms machen, eben aufgrund meiner neuen Erkenntisse, und da das gezeigte Spiel mit diesem neuen DataBinding versehen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Also ich finde das komisch. Man entwicklt erst eine neue Technik(WPF) um das Databinding und so möglich zu machen,weil die alte sich nicht eignete. Jetzt gehts wieder zurück und man versucht das Neue in die alte Technologie rein zu Hämmern.
    Jetzt stellt sich die frage ob man das nicht gleich richtig macht und sich die Zeit erspart bis man merkt das es mit WPF doch besser ist .

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Amro“ ()

    Erklär mal der Chefetage eines Großkonzerns, dass alle WinForms-Programme, die seit Jahren/Jahrzehnten laufen, nun auf WPF umgestellt werden müssen, um neue Features und Testszenarien zu ermöglichen.
    Aber es ist eben ein weiterer Schritt in Richtung mehr Bewegungsfreiheit.
    1. Umstellung der Projekte von .NET-Framework auf .NET (oder erst Schritt 2, nach Belieben)
    2. Auslagern von Funktionalität von der Formklasse in andere Klassen
    3. weitere Auslagerung durch das neue DataBinding
    4. Austausch des UI von WinForms auf WPF, WinUI, MAUI oder wie sie alle heißen, da im Projekt UI und Rest soweit voneinander entkoppelt sind, dass der Austausch relativ zügig geht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    (Mal ein vorläufiger Schnellschuss:)
    Sieht mir sehr interessant aus.
    MVVM ist für mich ja das wesentliche an Wpf.
    Auf Klicki-Bunti-Kram, gebastelt aus Styles, ControlTemplates, Animationen, etc. ... - kann ich bislang überwiegend gut verzichten.
    Ich wär ja gottfroh(!), wenn man von diesem vermaledeitem Xaml-Gestammel iwie wegkommen könnte, (zurück) hin zu einem Form-Designer, der dieser Bezeichnung wieder würdig ist.

    Allerdings muss ich noch erforschen, inwieweit das neue WinForms ComplexBinding, Listen, und sowas angemessen umsetzt. Dassis in Wpf ja sehr genial, und zähle ich zum MVVM-Support.
    So spontan tätich denken, nur mit einem RelayCommand-Binding isses noch beiweitem nicht getan.
    Ich glaub, ich meld mich noch dazu.
    :thumbup:

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @VaporiZed
    Ich habe bei deinem Projekt versucht, einen 2. Button in der Form anzulegen, der eine andere Aktion anzeigen soll...
    Dazu habe ich die Klasse Foo um ein 2. Command erweitert:

    VB.NET-Quellcode

    1. Property RelayCommandX As New RelayCommand(AddressOf ShowMessageX, Function() IsEnabled)
    2. Private Sub ShowMessageX()
    3. MessageBox.Show("Second box was clicked!")
    4. End Sub

    Beim Binden wird dieses RelayCommand aber nicht angezeigt und meckert irgend etwas mit Vorschaufunktion an...


    Wobei ich diese Zeile in der ProjektDatei eingefügt habe, kann ich die Bindung nicht herstellen?

    XML-Quellcode

    1. <EnablePreviewFeatures>True</EnablePreviewFeatures>

    Vlt. mache ich hier grundlegend etwas falsch :whistling:
    Ich verwende VS2022 mit NET 7.
    @VB1963: Ja, da komm ich auch noch nicht ganz klar. Notfalls kann ich bei mir noch auf .NET 8 stellen, dann klappt es nach nem VS-Neustart.
    Oder man setzt das Binding in der FormX.Designer.vb. Nicht schön, funktioniert aber.
    Das wär aber eine Frage @loeffel.
    Ach, was soll's. ich mach noch nen Issue-Thread bei Microsoft auf.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    @Haudruferzappeltnoch

    Nicht getestet:
    Spoiler anzeigen

    XAML
    Spoiler anzeigen

    XML-Quellcode

    1. d:DataContext="{x:Static local:Singleton.Instance}"



    Spoiler anzeigen

    VBNET

    VB.NET-Quellcode

    1. Public Class Singleton
    2. Private Shared _Instance As Singleton
    3. Public Shared ReadOnly Property Instance As Singleton
    4. Get
    5. If _Instance Is Nothing Then _Instance = New Singleton
    6. Return _Instance
    7. End Get
    8. End Property
    9. Public Property BindMe As String
    10. Private Sub New()
    11. BindMe = "Hello"
    12. End Sub
    13. End Class




    Wobei ich nicht verstehe warum es unbedingt Singleton sein soll

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Amro“ ()

    Wir haben im selbigen Thread auch Umgehungsmöglichkeiten gefunden. Mir gings drum, dass möglicherweise diese Probleme von WinForms, nicht auf WinForms zurückzuführen sind, sondern tiefer im Kern der Sache verbuddelt sind.

    Amro schrieb:

    Wobei ich nicht verstehe warum es unbedingt Singleton sein soll
    Wird vermutlich auch aus dem Gesamtkontext des genannten Threads hervorgehen. Es nutzt bei diesem Einzelfall nix, dient aber dem Verständnis.

    VaporiZed schrieb:

    Das wär aber eine Frage @loeffel.


    Es gibt eine Regression im Build System, so wie es ausschaut. Hat nichts direkt mit WinForms zu tun - die genauen Ursachen recherchieren wir noch.
    Jedenfalls sollte zusaetzliches Einfuegen von folgendem fuer Abhilfe sorgen:

    <GenerateRequiresPreviewFeaturesAttribute>true</GenerateRequiresPreviewFeaturesAttribute>

    In .NET 8 ist es GA (general available), da braucht es diese Attribute dann nicht mehr.

    HTH,

    Gruss aus Redmond,

    Klaus
    Jou, die Zeile hat mir in meinen Projekten in .NET 7 gefehlt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Bei mir auch...
    Die Action funktioniert jetzt auch beim 2. Button aber das CanExecute wirkt sich beim 2. Button im RelayCommand nicht aus? :whistling:
    Übersehe ich da etwas?

    VB.NET-Quellcode

    1. Class Foo
    2. Property RelayCommand As New RelayCommand(AddressOf ShowMessage, Function() IsEnabled)
    3. Private Sub ShowMessage()
    4. MessageBox.Show("Box was clicked!")
    5. End Sub
    6. Property RelayCommandX As New RelayCommand(AddressOf ShowMessageX, Function() IsEnabled)
    7. Private Sub ShowMessageX()
    8. MessageBox.Show("Second box was clicked!")
    9. End Sub
    10. Private _IsEnabled As Boolean
    11. Property IsEnabled As Boolean
    12. Get
    13. Return _IsEnabled
    14. End Get
    15. Set
    16. _IsEnabled = Value
    17. RelayCommand.NotifyCanExecuteChanged()
    18. End Set
    19. End Property
    20. End Class
    Dateien
    Dir fehlt nach Zeile#18: RelayCommandX.NotifyCanExecuteChanged()
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Amro schrieb:

    Also ich finde das komisch. Man entwicklt erst eine neue Technik(WPF) um das Databinding und so möglich zu machen,weil die alte sich nicht eignete. Jetzt gehts wieder zurück und man versucht das Neue in die alte Technologie rein zu Hämmern.
    Jetzt stellt sich die frage ob man das nicht gleich richtig macht und sich die Zeit erspart bis man merkt das es mit WPF doch besser ist .



    Das sieht auf den ersten Blick tatächlich so aus, das ist richtig. Du darfst aber Folgendes nicht vergessen:
    • Es gibt hundertausende von mittelgroßen und großen Business-Anwendungen, die, sagen wir, in zwischen 2002 und 2022 in WinForms geschrieben worden sind. 5 Mio Zeilen Code sind dabei wirklich nicht selten.
    • Die Anwendungen sind inzwischen so komplex geworden, dass die nächste Generation von Entwicklern sich nicht mehr traut, Änderungen an den alten Systemen zu machen, weil sie nicht wissen, was das für Auswirkungen hat.
    • Natürlich sind genau dazu die Unit-Tests da. Du schreibst einen Test, der sicherstellt, dass eine Funktion so funktioniert, wie sie funktioniert. Wenn du dann was "aus Versehen am Verhalten änderst", läuft der Test natürlich nicht mehr. Dann weißt du sofort, "UPS!"
    • Das ist aber das Problem mit WinForms Apps: Sie haben oft keine Unit-Tests, da gibt es einen großen Nachholbedarf. ABER: Für Unit-Tests willst du in erster Linie mal die Algorithmen deiner Businesslogik testen, nicht die UI. Die erst in zweiter Linie, aber das sind dann mehr Integrations-Tests oder Coded-UI-Tests. Aber Abhängigkeiten ZUM eigentlich UI-Stack sind dabei wirklch hinderlich. So hinderlich, dass sie Unit Tests oft unmöglich machen. Und das ist einer der Hauptgründe, dass wir über das Einführen dieses Features nachgedacht, und uns dann dafür entschieden haben. Du kannst nunmehr die Business-Logik von der UI trennen, und dann deine Logik super-komfortabel Unit-testen.
    • Es gibt aber noch weitere Gründe, und das ist die Wiederverwendbarkeit von Business-Logik. Immer mehr LOB (Line Of Business) Apps benötigen einen "Mobile Spin-Off", wenn du so willst. Ich habe beispielsweise meine Frau bei einem meiner ehemaligen Kunden gekennengelernt, die in der Immobilienwirtschaft gearbeitet hat. Deswegen habe ich als technischer Berater natürlich auch super-viel über dieses domänenspezifische Thema gelernt: Klassische Verwaltungsapps in dieser Größe (waren damals schon so etwa wie 600 Forms und über 1 Mio Zeilen Code), haben meistens bei den Kunden eine lokale SQL/App-Server Installation. Und für die Außendienstler in der Wohnungswirtschaft waren Datenaustausch oder ßMobilität schwierig zu realisieren, da die Hauptanwendung eben auf dieser tzpischen WinForms/SQL-Anwendungs-Server Architektur basierte. Das ist damit ein Paradebeispiel für unsere (Microsoft's) Migrations-/Modernisierungsempfehlungen fuer WinForms Apps:
    • - Einführung von sauber getrennten Layers von UI-Controller, UI Stack und Anwendungsserver auf Basis von MVVM (oder anderen UI-Controller-Pattern), dort und in der Reihenfolge, in der es Sinn ergibt.
      - Einführung von Unit-Tests in der Reihenfolge Kritscher Code-->Unkritischer Code
      - Auslagern der UI-Seitigen Businesslogik in die ViewModels/ViewController
      - Auslagern der allgemeinen Business-Logik in ein Backend
      - Migrieren des Backends in die Cloud, in der Reihenfolge "Code wichtig für Mobile Anwendungen" --> "weniger wichtig für mobile Anwendungen"
      - Wiederverwenden der ViewModels für mobile Anwendungen mit MAUI.NET oder WinUI.
    Damit macht das Retro-Fitten von Features wie DataBinding (more to come!!) deswegen Sinn für WinForms, weil es natürlich wirtschaftlich Blödsinn ist, 5 Millionen Zeilen Code wegzuschmeissen, und in WPF oder mit einem anderen UI Stack neuzuschreiben. Das ist nicht nur zu teuer, es ist auch total praxisfremd. Wenn du ein Team mit 10 Entwicklern hast, schaukeln die sich ja nicht den ganzen Tag ihre Konferenz-Badges, und warten darauf, mit einer Migration zu beginnen. Sie haben ja mit dem Tagesgeschäft mehr als zu tun. Wichtig ist also, eine bestehende Anwendung so modernisieren zu können, dass es für ein Team wirklich MACHBAR wird und ueber mehrere Iterationen erfolgen kann.

    Und das haben wir uns im WinForms Team auf die Fahne geschrieben: Was können wir tun, damit die Arbeit mit WinForms für die Entwickler draußen weniger stressig wird auf Dauer mit diesen Dingen im Hinterkopf. Manchmal schaut es so aus, als wenn wir dabei Features von einem anderen unserer UI Stacks "klauen", klar, aber das ergäbe natürlich keinen Sinn. Wir möchten, dass es immer einfacher wird, erst zu .NET (6, 7, 8, 9...) zu wechseln, weil .NET Framework langfristig natürlich eine Sackgasse ist. Da wird außer den wichtigen Security-Patches absolut nichts mehr Featuremäßiges in WinForms passieren. Null. Nada. (Auch nicht in WPF.) Und dass mit den neuen Framework-Versionen die Modernisierung von Apps wirtklich darstellbar wird.

    Ich hoffe, das hilft ein wenig zur Orientierung bei den UI-Stacks!

    Falls ihr Fragen habt, ihr bekommt mich jederzeit per Twitter (@loeffelmann) oder E-Mail an vorname . nachname at microsoft punkt com. (Ich schaue hier nur ab und zu rein, wegen chronischem Zeitmangel).

    Ich behalte diesen Thread aber auch erstmal ein wenig im Auge, also wenn ihr hier zum Thema Fragen habt (oder zum Thema WinForms generell oder Best Practices bei Microsoft), haut rein!

    LG aus Redmond unfd happy new year!

    Klaus
    ich bekomme Error BC2014 the value 'Preview' is invalid for option 'langversion' WinFormsNetVB | E:\NoGit\FormsVb\WinFormsNetVB\WinFormsNetVB\vbc
    wenn ich <EnablePreviewFeatures>True</EnablePreviewFeatures> in der .vbproj drinne habe.
    Das gilt auch für das angehängte projekt aus post#15

    Gibts da eine Lösung für, oder ist .Net7 einfach nichts für mich?

    :(

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Was hast Du denn für eine VS-Version? Habe Version 17.9.0 Preview 2.1, da läuft das problemlos.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.