Ein WPF MVVM Projekt aufsetzen (VB.NET & C#) – 2024 Guide

WPF MVVM Projekt in VB.NET und C# aufsetzen
WPF MVVM Projekt in VB.NET und C# aufsetzen

Moderne Software durch WPF MVVM Projekte erstellen

Viele mich anschreibende Zuschauer und Kunden haben sich gewünscht, dass ich mal einen Projektaufbau nach Model-View-ViewModel-Manier zeige – von Beginn an und ohne anderes Zeug. Also hier kommt er nun, der Beitrag, wie man ein VB.NET, bzw. ein C# WPF Projekt anhand der MVVM-Struktur aufsetzt und durch ein Projekttemplate sogar wiederverwendbar macht. In erster Linie sind hier die Ordnerstruktur, die Konfiguration des Start-Prozesses und einige kleine / weitere Dinge relevant, aber genug gequasselt – let’s go 🤓!

Kurzfassung – WPF MVVM Projekt aufsetzen

Grundsätzlich kann man die Schritte wie folgt zusammenfassen, allerdings ist dies natürlich nur extrem kukrz gefasst und Bedarf sicherlich einer genaueren Beschreibung. Diese findest Du selbstverständlich weiter unten, wenn Dir die groben Schritte nicht ausreichen sollten – wovon ich ausgehe, da Diese nur einer Art Leitfaden darstellen.

Die Schritte wären an sich wie folgt:

  • Erstelle die MVVM-typischen Ordner: Views, ViewModels, Models, Utils (optional)
  • Verschiebe das MainWindow über den Visual Studio Projektmappenexplorer in den „Views„-Ordner
  • Passe den Namen des MainWindows zu MainViewan
  • Sorge dafür, dass das MainView in einem passenden Namespace ist – Achtung: Code behind Datei, sowie auch die XAML-Datei
  • Setze im MainView einen DataContext (entweder im XAML oder Code behind)
  • Passe die StartupUri in Deiner Application.xaml Datei an: „Views/MainView.xaml“
  • Implementiere die INotifyPropertyChanged-Schnittstelle in einer Basisklasse – für die Vererbung an ViewModel-Klassen (in den Utils-Ordner damit)
  • Erstelle eine passende MainViewModelKlasse, Welche von Deiner „PropertyChanged“-Implementierung erbt (häufig auch ShellViewModel genannt)

💡 Hinweis: Nutze gerne das Inhaltsverzeichnis, wenn Du es eilig hast und einfach drauf los coden möchtest. Ich würde Dir allerdings empfehlen, auch die Details hinter dem Ganzen zu verstehen und ggf. ein wenig mehr Zeit zu investieren.

Details zur INotifyPropertyChanged-Schnittstelle

Beachte, dass ich nicht genauer auf das „INotifyPropertyChanged“-Interface eingehen werden, dies habe ich im Beitrag „Der ultimative INotifyPropertyChanged Guide“ getan. Klicke auf den Link, falls Du die Basisklasse oder auch detaillierte Informationen zum Thema benötigst – der Link schickt Dich direkt zur Basisklasse.

Kurzgesagt ist diese Schnittstelle eine Art Vertrag (eine Schnittstelle eben..), damit die „WPF-Engine“ – so nenne ich Sie jetzt einfach mal – weiß: „Hey, wann und wie werden mir Änderungen kommuniziert?“. Es ist daher unsere Aufgabe als Entwickler, Sie korrekt zu implementieren und an den notwendigen Stellen das „PropertyChanged“-Ereignis auszulösen. Somit weiß die Oberfläche dann: „Aha, da ist was passiert, also muss ich aktiv werden“.

Mehr über das MVVM-Entwurfsmuster selbst

Falls Du eventuell völlig neu im Themenbereich MVVM bist, kann ich Dir hier auch meinen Beitrag über das „Model-View-ViewModel-Entwurfsmuster“ empfehlen. Lass Dich hier bitte nicht von der „Spezialisierung“ auf C# verwirren, letztendlich ist hier alles analog und die Erkenntnisse helfen Dir in beiden .NET-Sprachen gleichermaßen.

Schritt 1: MVVM-Ordner anlegen

Projekt und Ordnerstruktur – WPF MVVM Projekt aufsetzen
Projekt und Ordnerstruktur – WPF MVVM Projekt aufsetzen

Wenn Du noch keine passenden Ordner für die üblichen MVVM-Bestandteile erstellt hast, machen wir dies nun zuerst. Verwende dafür die Werkzeuge aus Visual Studio, damit die Ordner auch von Visual Studio selbst korrekt erfasst werden. Führe dazu einfach z. B. einen Rechtsklick auf Deine Projektmappe (nicht auf die Lösung / Solution) aus und wähle „Hinzufügen->Ordner“.

Erstelle nun innerhalb Deiner Projektmappe unter anderem einen Ordner namens „ViewModels„, hier kommen – wie der Name schon sagt – unsere ViewModels rein. Füge dann bitte noch einen weiteren Ordner namens „Views“ hinzu, dort werden wir die grafischen Gegenstücke – also unsere visuellen Bedien-Oberflächen – zu unseren ViewModels ablegen. Dazu könnten übrigens auch kleinere Komponenten, wie z. B. eine Navigationsleiste gehören (ergo NavigationBarView).

Achtung: Wenn Du MVVM-Hilfs-Frameworks wie „Caliburn Micro“ verwendest, könntest Du allerdings ein wenig an Namenskonventionen gebunden sein. Hierüber jedoch auch noch zu berichten, würde bekanntlich den Rahmen des Beitrages sprengen, schätze ich. Verlasse Dich daher am Anfang auf die in diesem Beitrag angepeilte Routine.

Im letzten Schritt benötigen wir noch einen weiteren kleinen „Hilfs-Ordner„, dort packen wir nützliche Helferlein rein, Welche uns den Alltag in MVVM versüßen. Nenne den Ordner daher einfach „Utils“ (Utilities/Hilfsmittel), später kommt dort dann die wiederverwendbare „PropertyChangedBase“-Klasse hinein. Wenn Du auch den Beitrag zur „INotifyPropertyChanged“-Schnittstelle besucht hast, hast Du hier auch schon die notwendige „PropertyChangedBase“-Basisklasse drin. Besuche ansonsten einfach den Link, ziehe Dir den Code (wo Du direkt auskommen solltest) und packe die Klasse in den „Utils“-Ordner.

Unsere finale Struktur sollte also nun wie folgt aussehen:

Finale Ordnerstruktur im Projekt – WPF MVVM Projekt aufsetzen
Finale Ordnerstruktur im Projekt – WPF MVVM Projekt aufsetzen

PropertyChangedBase im „Utils“-Ordner nicht vergessen!

💡 Hinweis: Wir werden in diesem Beitrag die „PropertyChangedBase“-Basisklasse aus meinem Beitrag zum Thema „Die INotifyPropertyChanged-Schnittstelle – Änderungen kommunizieren“ verwenden. Stelle sicher, dass Du die Klasse also im „Utils“-Ordner und dem passenden Namespace ablegst! Klicke einfach auf den Link und Du kommst sofort zur passenden Klasse im Beitrag (VB.NET & C# Code).

Schritt 2: MainWindow verschieben & umbenennen

MainWindow verschieben & umbenennen – WPF MVVM Projekt aufsetzen
MainWindow verschieben & umbenennen – WPF MVVM Projekt aufsetzen

Im folgenden Schritt müssen wir auch noch daran denken, das „MainWindow“ MVVM-gemäß umzubenennen und zu verschieben. Dies führt natürlich aufgrund der Standard-Konfiguration des Projektes zu Fehlern. Weder weiß die „Application.xaml“-Datei nach dem Umzug, wo unser Hauptfenster ist, noch, dass es nicht mehr im Root-Namespace ist (im Namensraum unseres Projektes).

Ab in den richtigen Ordner

Schiebe das MainWindow nun in den Ordner namens „Views“, verwende dazu am besten den Drag & Drop-Vorgang im Visual Studio selbst. Wenn Du dies außerhalb machst, kann es zu Problemen führen, da Visual Studio es ggf. nicht korrekt erkennt. Nun befindet sich unsere grafische Oberfläche (potenziell Eine von Vielen) im richtigen Ordner, allerdings fehlt noch was.

Einen MVVM entsprechenden Namen & Namespace

Benenne im nächsten Schritt das „MainWindow“ in „MainView“ um und achte darauf, dass dies auch anschließend korrekt in der ersten Zeile des XAML-Codes widergespiegelt wird. Verwende dazu einfach die F2-Taste, während Du Dein MainWindow im Projektmappen-Explorer ausgewählt (und den Fokus darauf) hast. Passe – wie hier drunter dargestellt – auch gleich den Namespace an, also schreibe das „Views.“-Prefix vor die eigentliche Bezeichnung.

DataContext durch XAML setzen

Beachte hier, dass Du diese beiden Zeilen (mit x:Class & xmlns:vm) separat in Dein Projekt kopierst / Sie abänderst, sonst zerstörst Du ggf. Dein bestehendes Projekt. Dort stehen ja auch noch andere Dinge, wie z. B. die Fenstergröße, usw. Diese habe ich hier bewusst ausgelassen! Den ViewModels Namespace kannst Du aktuell außer acht lassen, bzw. als Fehler drin lassen – darum kümmern wir uns später. Durch die später erstellte Klasse wird der Namespace hier verfügbar – ggf. musst Du hierfür einmal das Projekt debuggen/builder, damit „er“ es kapiert.

Dann setzen wir noch im letzten Schritt den Fenster-Datenkontext via XAML, wir erstellen also eine Instanz der MainViewModel-Klasse via XAML-Code. Dies könntest Du auch – wie gleich angemerkt – via „Code behind“-Datei durchführen.

<Window x:Class="Views.MainView"
        xmlns:vm="clr-namespace:WpfCommandsVbTutorial.ViewModels">

    <Window.DataContext>
        <vm:MainViewModel />
    </Window.DataContext>

    <!-- restlicher XAML-Code -->
</Window>

Diese Änderungen werden wir nun auch im sogenannten „Code behind“-File übernehmen / sicherstellen. Gehe dazu einfach in diese Datei, indem Du die F7-Taste drückst, während Du Dich im XAML-Designer des MainViews (ehemals MainWindows) befindest. Danach springt die Visual Studio IDE via Hotkey in die „Code behind“-Datei und Du solltest folgenden Code einfügen – also das MainView mit einem Namespace umgeben.

Anmerkung zum DataContext

Optional könntest Du die DataContext-Eigenschaft hier festlegen, wir werden dies allerdings im XAML-Code machen, daher entfällt es hier weg, bzw. ist es hier optional. Es geht also an dieser Stelle hier erstmal um den Namespace und die Klasse selbst, sieh‘ Dir aber auch gern an, wie Du auch hier den Datenkontext festlegen könntest.

Mach‘ Dir hier übrigens keine Sorgen über das „MainViewModel“, dabei handelt es sich um eine Klasse, Welche wir gleich noch erstellen werden!

Namespace Views

    Class MainView
        
        '' entfällt durch View-seitige DataContext-Konfiguration
        'Sub New()
            'InitializeComponent()
            '' Import bei Bedarf nicht vergessen!!
            'DataContext = New MainViewModel()
        'End Sub

    End Class

End Namespace
namespace Views
{
    class MainView
    {

        //// entfällt durch View-seitige DataContext-Konfiguration
        //public MainView()
        //{
            //InitializeComponent();
            //// Import bei Bedarf nicht vergessen!!
            //DataContext = new MainViewModel();
        //}

    }
}

Schritt 3: Start-Prozess der Software anpassen (Bootstrapping)

Start-Prozess anpassen – WPF MVVM Projekt aufsetzen
Start-Prozess anpassen – WPF MVVM Projekt aufsetzen

Nun müssen wir ein wenig Feintuning betreiben, da das Programm nach unseren Änderungen mehr oder weniger ins Leere laufen würde. Das liegt daran, dass wir das MainWindow erstens umbenannt und zweitens verschoben haben (und denke an die Namespace-Änderung). Nun muss die Zeile mit der „StartupUri“ in der „Application.xaml / App.xaml“-Datei angepasst werden.

Achte bitte darauf, dass ich mein Projekt „WpfCommandsVbTutorial“ genannt hatte und Du dies durch Deinen eigenen Projektnamen ersetzen musst. Dadurch gibst Du praktisch Bescheid: „Hey, hier ist nun das Start-Fenster/View, um die Anwendung zu starten“.

<Application x:Class="Application"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfCommandsVbTutorial"
             StartupUri="Views/MainView.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

Schritt 4: Ein passendes ViewModel erstellen

Ein passendes ViewModel erstellen
Ein passendes ViewModel erstellen

Im nächsten und letzten Schritt müssen wir für das oben konfigurierte View nun ein passendes ViewModel erstellen. Das View ist ja wie Du vermutlich weißt (oder gelernt hast) das grafische Gegenstück (ohne Geschäftslogik) zum View. Es mag also im wahrsten Sinne des Wortes „cool“ aussehen, aber letztendlich nichts „können“.

Eine wiederverwendbare Basisklasse

Um uns nicht immer wiederholen zu müssen, machen wir hier Gebrauch von der schon mehrfach erwähnten „PropertyChangedBase“-Basisklasse aus meinem anderen Beitrag. Gehe daher also bitte hin und erstelle diese Klassen-Datei im oben angelegten „Utils“-Ordner. Einen detaillierten Guide findest Du dazu im oben verlinkten Beitrag.

Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Namespace Utils
    Public MustInherit Class PropertyChangedBase
        Implements INotifyPropertyChanged
        Protected Sub NotifyOfPropertyChange(<CallerMemberName> Optional propertyName As String = Nothing)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    End Class
End Namespace
using System.Runtime.CompilerServices;
using System.ComponentModel;
namespace Utils;
public abstract class PropertyChangedBase : INotifyPropertyChanged
{
    protected void NotifyOfPropertyChange([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

Das MainViewModel

Nun erstellen wir unser MainViewModel, Welches die aufbereiteten Elemente für das View beinhaltet – darunter auch passende Logik, wie z. B. für einen „Button1_Click“. Warum diese typische Ereignishandler aus Winforms (Windows Forms) Zeiten schon lange nicht mehr modern ist und nicht ins MVVM-Entwurfsmuster passt, erfährst Du in einem passenden, baldigen Beitrag.

Da wir dieses beispielhaft aufgesetzte Projekt hier wie initial erwähnt gleich noch als Projektvorlage anlegen möchten, werde ich hier auch keine großen Eigenschaften realisieren. Das MainViewModel bleibt daher also eher karg und leer. Achte auch hier bitte wieder daran, dass Du oben den korrekten Projektnamen für Deine Anwendung verwendest:

Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class NewMainViewModel
        Inherits PropertyChangedBase

        Sub New()
            
        End Sub

    End Class

End Namespace
using WpfCommandsVbTutorial.Utils;

namespace ViewModels
{

    public class NewMainViewModel : PropertyChangedBase
    {

        public NewMainViewModel()
        {
            
        }

    }

}

Bonus: WPF MVVM Projektvorlage erstellen

Bonus: NET MVVM Projektvorlage
Bonus: NET MVVM Projektvorlage

Als kleines – wie sagt man so schön – Schmankerl, erstellen wir uns aus der gemachten Arbeit nun eine Projektvorlage. Wir möchten ja schließlich vermeiden, diesen ganzen Aufwand für jedes einzelne MVVM-Projekt zu betreiben. Im Endeffekt geht dies nach getaner Arbeit sehr einfach und schnell, mit Hilfe der Visual Studio IDE.

Wenn nun alles nach Deinen Vorstellungen ist, gehe oben im Visual Studio Menü auf „Projekt->Vorlage exportieren“. Dann zeigt sich folgender Dialog und Du kannst ein paar weitere Einstellungen treffen. Wähle im ersten Schritt allerdings einfach nur „Projektvorlage“ – das ist schließlich, was wir wollen, right!?

Projektvorlagen-Assistent Schritt 1
Projektvorlagen-Assistent Schritt 1

Wenn Du auf weiter geklickt hast, kommt jetzt der nächste Schritt. Dort kannst Du wohl die beiden essenziellsten Informationen festlegen: Den Namen & die Beschreibung für das Template – wähle hier daher vor allem einen sinnvollen Namen, wie: „<C#> / <VB.NET> MVVM Projekttemplate“, je nachdem für welche Sprache Du Dich ggf. entscheidest. Lege Dir doch auch alternativ für beide Sprachen ein entsprechendes Template an?

💡 Hinweis: Hake hier am besten das Kästchen „Vorlage automatisch in Visual Studio importieren“ an, dann brauchst Du Dich darum nicht manuell kümmern.

Projektvorlagen-Assistent Schritt 2
Projektvorlagen-Assistent Schritt 2

Wenn Du nun ein neues Projekt anlegst, findest Du Dein Template ganz einfach wieder:

Projektvorlagen-Assistent Schritt 3
Projektvorlagen-Assistent Schritt 3

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert