<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>mvvm Archive - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/tag/mvvm/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Wed, 25 Mar 2026 12:45:11 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://robbelroot.de/wp-content/uploads/2020/12/cropped-favicon-32x32.png</url>
	<title>mvvm Archive - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Windows Forms zu WPF migrieren: Der vollständige Guide (2026)</title>
		<link>https://robbelroot.de/blog/windows-forms-zu-wpf-migrieren/</link>
					<comments>https://robbelroot.de/blog/windows-forms-zu-wpf-migrieren/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Mon, 16 Mar 2026 16:54:04 +0000</pubDate>
				<category><![CDATA[Legacy-Modernisierung]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[legacy]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[modernisierung]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[refactor]]></category>
		<category><![CDATA[refactoring]]></category>
		<category><![CDATA[rewrite]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=19528</guid>

					<description><![CDATA[<p>Wer eine gewachsene Windows-Desktop-Anwendung von Windows Forms zu WPF migrieren möchte, steht vor einer der häufigsten und lohnendsten Modernisierungsaufgaben in der .NET-Welt. Die Ausgangslage ist dabei fast immer dieselbe: eine Anwendung, die seit Jahren zuverlässig läuft – aber bei jeder neuen Anforderung mehr Widerstand leistet, weil die Architektur nicht für &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/windows-forms-zu-wpf-migrieren/">Windows Forms zu WPF migrieren: Der vollständige Guide (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2026/03/windows-forms-zu-wpf-migrieren.png"><img fetchpriority="high" decoding="async" width="1536" height="1024" src="https://robbelroot.de/wp-content/uploads/2026/03/windows-forms-zu-wpf-migrieren.png" alt="Windows Forms zu WPF migrieren – Vorher/Nachher Vergleich" class="wp-image-19534" title=""/></a><figcaption class="wp-element-caption">Windows Forms zu WPF migrieren – Vorher/Nachher Vergleich</figcaption></figure>






<p class="intro-lead">
Wer eine gewachsene Windows-Desktop-Anwendung von <strong>Windows Forms zu WPF migrieren</strong> möchte, steht vor einer der häufigsten und lohnendsten Modernisierungsaufgaben in der .NET-Welt. Die Ausgangslage ist dabei fast immer dieselbe: eine Anwendung, die seit Jahren zuverlässig läuft – aber bei jeder neuen Anforderung mehr Widerstand leistet, weil die Architektur nicht für Wachstum gebaut wurde.
</p>



<p>
Windows Forms existiert seit dem Jahr 2002. Für seine Zeit war es revolutionär – einfach, schnell, produktiv. Heute, mehr als zwei Jahrzehnte später, zeigt die Technologie deutliche Schwächen:
</p>



<ul class="wp-block-list">
<li><strong>Keine echte Trennung von UI und Logik</strong> – Business-Code, Datenbankzugriffe und UI-Events landen in denselben Klassen. Das Ergebnis: schwer testbarer, eng gekoppelter Code.</li>



<li><strong>Eingeschränkte UI-Möglichkeiten</strong> – Animationen, moderne Controls, adaptive Layouts und High-DPI-Support sind in WinForms entweder unmöglich oder aufwendig zu erkaufen.</li>



<li><strong>Kein Datenbinding auf Augenhöhe</strong> – WPF bietet ein mächtiges, bidirektionales Binding-System. In Windows Forms ist Datenbinding ein nachträglicher Gedanke.</li>



<li><strong>Technische Schulden häufen sich</strong> – Jede neue Anforderung wird teurer, weil die Architektur nicht skaliert.</li>



<li><strong>Nachwuchsmangel</strong> – Entwickler, die neu ins Team kommen, kennen WinForms kaum noch. WPF und MVVM hingegen sind Standard.</li>
</ul>



<p>
Das bedeutet nicht, dass Windows Forms <em>morgen</em> abgekündigt wird – Microsoft pflegt es noch. Aber die Innovationskurve ist flach, und der Abstand zu modernen Technologien wächst täglich.
</p>



<h2 class="wp-block-heading">WPF + MVVM: Was Sie konkret gewinnen</h2>



<p>
WPF (Windows Presentation Foundation) ist seit .NET 3.0 – also seit 2006 – Microsofts Antwort auf die Schwächen von WinForms. Kombiniert mit dem <strong>MVVM-Pattern (Model–View–ViewModel)</strong> entsteht eine Architektur, die skaliert, testbar ist und echte Wartbarkeit liefert.
</p>



<figure class="wp-block-table"><table><thead><tr><th>Kriterium</th><th>Windows Forms</th><th>WPF + MVVM</th></tr></thead><tbody><tr><td>UI / Logik getrennt</td><td>&#x274c; Kaum möglich</td><td>&#x2705; Konsequent durch MVVM</td></tr><tr><td>Unit-Tests</td><td>&#x274c; Schwer bis unmöglich</td><td>&#x2705; ViewModels vollständig testbar</td></tr><tr><td>Datenbinding</td><td>&#x26a0;&#xfe0f; Rudimentär</td><td>&#x2705; Mächtig, bidirektional</td></tr><tr><td>Design-Flexibilität</td><td>&#x274c; Stark eingeschränkt</td><td>&#x2705; Vollständig über XAML steuerbar</td></tr><tr><td>High-DPI / 4K</td><td>&#x26a0;&#xfe0f; Nachträgliche Patches nötig</td><td>&#x2705; Nativ unterstützt</td></tr><tr><td>Animationen</td><td>&#x274c; Kaum vorhanden</td><td>&#x2705; Erstklassig integriert</td></tr><tr><td>Langzeitpflege</td><td>&#x26a0;&#xfe0f; Wenig Innovation</td><td>&#x2705; Aktiv weiterentwickelt (.NET 9/10)</td></tr></tbody></table></figure>



<p class="has-small-font-size">(High-DPI: Seit .NET 6+ hat WinForms Application.SetHighDpiMode() als native Unterstützung.)</p>



<h2 class="wp-block-heading">Die drei Migrationsstrategien im Überblick</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2026/03/windows-forms-zu-wpf-migrieren-strategien.png"><img decoding="async" width="1264" height="842" src="https://robbelroot.de/wp-content/uploads/2026/03/windows-forms-zu-wpf-migrieren-strategien.png" alt="Drei Migrationsstrategien Windows Forms zu WPF: Big Bang, Strangler Fig und Hybrid-Hosting im Vergleich" class="wp-image-19546"/></a></figure>



<p>
Es gibt nicht <em>einen</em> richtigen Weg. Welche Strategie passt, hängt von Größe, Risikotoleranz und Budget Ihrer Anwendung ab.
</p>



<h3 class="wp-block-heading">Strategie 1: Big Bang – Komplett-Neuentwicklung</h3>



<p>
Die gesamte Anwendung wird von Grund auf neu in WPF + MVVM entwickelt. Die alte WinForms-Anwendung läuft parallel, bis die neue fertig ist.
</p>



<p>
<strong>Geeignet für:</strong> Kleine bis mittelgroße Anwendungen (unter ~20.000 LOC), bei denen der bestehende Code so stark verwachsen ist, dass eine Überarbeitung länger dauern würde als eine Neuentwicklung.
</p>



<p>
<strong>Vorteil:</strong> Sauberste Lösung, kein technischer Ballast.<br>
<strong>Nachteil:</strong> Hohes Risiko, hohe Kosten, lange Zeit ohne produktive Verbesserungen.
</p>



<h3 class="wp-block-heading">Strategie 2: Strangler Fig – Schrittweise Migration</h3>



<p>
Benannt nach dem Würgefeigenbaum, der langsam den alten Baum ersetzt: Module werden Schritt für Schritt durch WPF-Äquivalente ausgetauscht. Die Anwendung läuft durchgehend produktiv.
</p>



<p>
<strong>Geeignet für:</strong> Große Anwendungen (50.000+ LOC), die ständig weiterentwickelt werden müssen. Schrittweise Migration reduziert das Risiko massiv.
</p>



<p>
<strong>Vorteil:</strong> Geringes Risiko, kontinuierliche Lieferung, ROI entsteht schon während der Migration.<br>
<strong>Nachteil:</strong> Längerer Gesamtzeitraum, parallele Pflege beider Technologien nötig.
</p>



<h3 class="wp-block-heading">Strategie 3: Hybrid-Hosting – WPF als Shell um WinForms</h3>



<p>
WPF übernimmt die äußere Struktur (Navigation, Menü, Fenster-Management), während bestehende WinForms-Controls über <code>WindowsFormsHost</code> eingebettet bleiben und nach und nach ersetzt werden.
</p>



<p>
<strong>Geeignet für:</strong> Tight Budget oder sehr komplexe Einzelkomponenten (z.B. proprietäre Steuerelemente), die kurzfristig nicht neu gebaut werden können.
</p>



<p>
<strong>Vorteil:</strong> Geringste initiale Kosten, sofort moderner Look.<br>
<strong>Nachteil:</strong> Technische Schulden bleiben vorerst bestehen, Grenzen der Hybrid-Lösung werden spürbar.
</p>



<h2 class="wp-block-heading">Schritt-für-Schritt: So läuft eine WinForms zu WPF Migration in der Praxis ab</h2>



<p>
Hier beschreibe ich meinen eigenen Prozess, den ich bei Kundenprojekten anwende – von der ersten Analyse bis zur Übergabe.
</p>



<h3 class="wp-block-heading">Phase 1: Analyse &amp; Bewertung (1–3 Tage)</h3>



<ul class="wp-block-list">
<li>Code-Analyse: Wie viele Lines of Code, wie tief ist die Kopplung, gibt es bereits Tests?</li>



<li>Identifikation der Module und ihrer Abhängigkeiten</li>



<li>Bewertung: Welche Strategie (Big Bang / Strangler / Hybrid) ist sinnvoll?</li>



<li>Roadmap und Kostenabschätzung</li>
</ul>



<h3 class="wp-block-heading">Phase 2: Architektur-Setup (2–5 Tage)</h3>



<ul class="wp-block-list">
<li>Neues WPF-Projekt anlegen (.NET 8 oder .NET 9)</li>



<li><strong><a href="https://robbelroot.de/blog/ein-wpf-mvvm-projekt-aufsetzen-guide/" target="_blank" rel="noreferrer noopener">MVVM-Grundstruktur aufsetzen</a></strong>: <code>ViewModels</code>, <code>Models</code>, <code>Views</code>, <code>Services</code></li>



<li><strong><a href="https://robbelroot.de/blog/net-dependency-injection-di-mit-autofac/" target="_blank" rel="noreferrer noopener">Dependency Injection</a></strong> konfigurieren (z.B. mit <code>Microsoft.Extensions.DependencyInjection</code>)</li>



<li>Basis-ViewModel mit <code><strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/" target="_blank" rel="noreferrer noopener">INotifyPropertyChanged</a></strong></code> und Command-Implementierungen</li>



<li>Navigation-Konzept festlegen</li>
</ul>



<h3 class="wp-block-heading">Phase 3: Schichtweise Migration</h3>



<ul class="wp-block-list">
<li><strong>Business-Logik zuerst</strong> – Diese kann oft 1:1 übernommen werden, da sie (im Idealfall) nicht UI-abhängig ist</li>



<li><strong>Datenzugriffsschicht</strong> – Repository-Pattern einführen, Datenbankzugriffe kapseln</li>



<li><strong>ViewModels</strong> – Für jede View ein passendes ViewModel erstellen</li>



<li><strong>Views (XAML)</strong> – Windows Forms-Formulare als XAML-Views neu aufbauen, Bindings setzen</li>
</ul>



<h3 class="wp-block-heading">Phase 4: Testing &amp; Review</h3>



<ul class="wp-block-list">
<li>Unit-Tests für ViewModels und Services schreiben</li>



<li>Funktionale Abnahme mit dem Kunden (Verhalten identisch mit altem System?)</li>



<li>Performance-Check (WPF-Rendering, Memory-Profiling)</li>
</ul>



<h2 class="wp-block-heading">Was kostet eine Windows Forms zu WPF Migration?</h2>



<p>
Eine pauschale Aussage ist hier seriöserweise nicht möglich – aber folgende Orientierungswerte helfen:
</p>



<figure class="wp-block-table"><table><thead><tr><th>Anwendungsgröße</th><th>Strategie</th><th>Zeitaufwand (grob)</th></tr></thead><tbody><tr><td>Klein (&lt;10.000 LOC, ~5–10 Formulare)</td><td>Big Bang</td><td>2–6 Wochen</td></tr><tr><td>Mittel (10.000–50.000 LOC)</td><td>Strangler oder Big Bang</td><td>2–6 Monate</td></tr><tr><td>Groß (&gt;50.000 LOC)</td><td>Strangler Fig</td><td>6–18+ Monate</td></tr></tbody></table></figure>



<p>
Entscheidend für die Kosten sind neben der Codegröße vor allem: <strong>Qualität des bestehenden Codes</strong> (wie stark ist die Logik in den UI-Events vergraben?), <strong>Testabdeckung</strong> (gibt es Tests, die Regressions abfangen?) und die <strong>fachliche Komplexität</strong> (wie viele Sonderfälle gibt es in der Business-Logik?).
</p>



<p>
Das Strangler Fig Pattern geht auf Martin Fowler zurück – eine ausführliche Erklärung findest du in seinem <a href="https://martinfowler.com/bliki/StranglerFigApplication.html" target="_blank" rel="noopener noreferrer">Original-Artikel auf martinfowler.com</a>.
</p>



<div class="wp-block-group has-white-color has-text-color has-background" style="background-color:#1a1a2e;padding-top:2rem;padding-right:2rem;padding-bottom:2rem;padding-left:2rem"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h3 class="wp-block-heading has-text-color" style="color:#F7941D">&#x1f4a1; <strong>Sie wissen noch nicht, in welche Kategorie Ihr Projekt fällt?</strong></h3>



<p><strong>Schicken Sie mir kurz, was Sie haben</strong>:</p>



<ul class="wp-block-list">
<li>&#x27a1;&#xfe0f; Technologie</li>



<li>&#x27a1;&#xfe0f; Grobe Codegröße</li>



<li>&#x27a1;&#xfe0f; Grober Zustand des Codes</li>
</ul>



<p>und ich sage Ihnen in einem kurzen Gespräch, welche Strategie sinnvoll ist und was das realistisch bedeutet.</p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link has-white-color has-text-color has-background has-link-color wp-element-button" href="https://robbelroot.de/kontakt/" style="background-color:#F7941D"><strong>Jetzt kostenloses Erstgespräch anfragen →</strong></a></div>
</div>



<p style="font-size:0.85rem">Oder zuerst einen Blick ins <strong><a href="https://robbelroot.de/portfolio" style="color:#F7941D;">Portfolio</a></strong> mit abgeschlossenen Projekten werfen</p>
</div></div>



<h2 class="wp-block-heading">Die häufigsten Fehler bei der Migration – und wie man sie vermeidet</h2>



<p>In meiner Praxis sehe ich immer wieder dieselben Stolperfallen – besonders bei Teams, die WPF zum ersten Mal einsetzen. Das folgende Beispiel zeigt einen typischen WinForms-Code aus einem echten Legacy-Projekt und das WPF-MVVM-Äquivalent nach der Modernisierung: </p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2026/03/VORHER-—-Typischer-WinForms-Spaghetti-Code.png"><img decoding="async" width="2048" height="2980" src="https://robbelroot.de/wp-content/uploads/2026/03/VORHER-—-Typischer-WinForms-Spaghetti-Code.png" alt="Windows Forms Legacy Code – SQL Injection, God Class, kein async/await" class="wp-image-19539"/></a><figcaption class="wp-element-caption">&#x274c; Vorher: WinForms Code-Behind mit 18 Problemen in 50 Zeilen</figcaption></figure>
</div>
</div>



<h3 class="wp-block-heading">Was im Vorher-Code konkret schiefläuft</h3>



<ol class="wp-block-list">
<li><strong>SQL Injection</strong> – Benutzereingaben werden direkt in SQL-Strings konkateniert (<code>"SELECT * FROM Kunden WHERE id = " + textBox1.Text</code>). Ein Angreifer kann damit die gesamte Datenbank auslesen, manipulieren oder löschen. Je nach firmeninternen Netzwerk-Aufbau häufig eher eine Schnittstelle zur Datenbank sinnvoller, da sicherer.<br></li>



<li><strong>Passwort im Klartext</strong> – Der Datenbankzugang inklusive Passwort steht direkt im Source Code (<code>Password=1234;</code>). Landet dieser Code in einem Repository, ist die Datenbank kompromittiert. Wird die Anwendung dekompiliert &#8211; gleiches Problem.<br></li>



<li><strong>Alles in einer Klasse</strong> – <code>Form1</code> enthält gleichzeitig UI-Logik, Datenbankzugriffe und Geschäftslogik. Kein Teil davon ist isoliert testbar oder wiederverwendbar.<br>  </li>



<li><strong>Leeres <code>catch {}</code></strong> – Fehler beim Speichern werden vollständig verschluckt. Die Anwendung tut so, als wäre alles gut – der Nutzer merkt nicht, dass seine Daten nicht gespeichert wurden.<br>  </li>



<li><strong>Kein <code>async/await</code></strong> – Jeder Datenbankaufruf blockiert den UI-Thread. Die Anwendung friert ein, solange die Abfrage läuft.<br>  </li>



<li><strong>Hardcodierte Pfade</strong> – <code>C:\\bilder\\aktiv.png</code> funktioniert ausschließlich auf dem Rechner des ursprünglichen Entwicklers.<br>  </li>



<li><strong>Nichtssagende Namen</strong> – <code>button1</code>, <code>label5</code>, <code>textBox2</code> – kein Entwickler versteht ohne Laufzeit, was diese Controls bedeuten.<br>  </li>



<li><strong>Kein Connection-Management</strong> – <code>SqlConnection</code> und <code>SqlDataReader</code> werden nicht in <code>using</code>-Blöcken verwendet. Bei einer Exception bleiben Datenbankverbindungen offen.<br>  </li>
</ol>



<h3 class="wp-block-heading">Weitere gängige Fehler / Probleme</h3>



<ol class="wp-block-list">
<li><strong>Code-Behind-Sucht</strong> – Der größte Fehler: Logik aus den WinForms-Events einfach 1:1 in den WPF Code-Behind kopieren. Dann haben Sie WPF-Code, der wie WinForms aussieht – und keinen der Vorteile.<br> <br><em>Lösung: Konsequent MVVM, Commands statt Click-Events.</em><br></li>



<li><strong>Kein sauberes Binding</strong> – <code>x:Name</code> und direkter Code-Behind-Zugriff auf Controls statt Datenbinding.<br> <br><em>Lösung: Jede UI-Interaktion läuft über Bindings und Commands.</em><br></li>



<li><strong>Alles auf einmal migrieren wollen</strong> – Ohne klare Phaseneinteilung wird das Projekt unüberschaubar.<br> <br><em>Lösung: Modulweise vorgehen, lieferfähige Zwischenstände einplanen.</em><br></li>



<li><strong>Dispatcher-Probleme ignorieren</strong> – WPF ist threading-sensitiv. UI-Updates aus Hintergrund-Threads ohne <code>Dispatcher</code> führen zu Crashes.<br> <br><em>Lösung: Von Anfang an asynchrone Patterns (<code>async/await</code>) und korrekte Dispatcher-Aufrufe implementieren.</em><br></li>



<li><strong>XAML-Performance vernachlässigen</strong> – Zu tiefe Visual Trees, fehlende Virtualisierung in Listen, zu viele Converter-Chains.<br> <br><em>Lösung: <code>VirtualizingStackPanel</code> für Listen, regelmäßiges Performance-Profiling.</em></li>
</ol>



<p>
Das Nachher-Bild zeigt dasselbe fachliche Verhalten – aber in einem <code>KundeViewModel</code> mit sauberer Dependency Injection, <code>async/await</code> durchgängig, benannten Properties statt anonymer Controls, und ohne eine einzige Datenbankzeile im ViewModel selbst.
</p>



<p>Das ViewModel delegiert nur, funktioniert als &#8222;vernetzende Schicht&#8220;. Natürlich könnten weitere Anregungen, wie z. B. MediatR, dem CommunityToolkit, etc. eingefügt werden, dies lasse ich aber erstmal bewusst weg &#x1f609;.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2026/03/NACHHER-—-Sauberes-WPF-MVVM.png"><img loading="lazy" decoding="async" width="1752" height="1832" src="https://robbelroot.de/wp-content/uploads/2026/03/NACHHER-—-Sauberes-WPF-MVVM.png" alt="WPF MVVM ViewModel – sauber, testbar, async" class="wp-image-19540"/></a><figcaption class="wp-element-caption">&#x2705; Nachher: Sauberes WPF MVVM – testbar, sicher, lesbar</figcaption></figure>



<h2 class="wp-block-heading">Planung mit Event Storming: Warum Domänenwissen vor der ersten Codezeile entscheidet</h2>



<p>
Einer der häufigsten Gründe, warum Migrationsprojekte länger dauern als geplant oder teurer werden als kalkuliert, hat nichts mit Technologie zu tun. Er liegt früher: im fehlenden gemeinsamen Verständnis darüber, <em>was das System eigentlich tun soll – und wer welche Rolle dabei spielt.</em>
</p>



<p>
In meinen Projekten setze ich deshalb bewusst auf <strong>Event Storming</strong> als Planungsmethode, bevor eine einzige Zeile neuer Code geschrieben wird. Event Storming ist ein kollaborativer Workshop-Ansatz aus dem Domain-Driven Design (DDD), bei dem Entwickler und Fachexperten gemeinsam die Prozesse eines Systems visualisieren – mit Klebezetteln, klar definierten Ereignissen und expliziten Rollen. Das Ergebnis: ein gemeinsames Bild davon, wer im System was tut, wer was darf, und wo die echten Schmerzpunkte und Hotspots liegen.
</p>



<p>
Gerade bei Legacy-Anwendungen, die über Jahre gewachsen sind, steckt enormes implizites Wissen in den Köpfen der Anwender – aber nirgends im Code. Event Storming holt dieses Wissen heraus und macht es greifbar. Aus einem solchen Workshop entstehen klare Domänen-Grenzen: Welche Module gehören zusammen? Wo überschneiden sich Verantwortlichkeiten? Welche Teile der alten Anwendung wurden &#8222;missbraucht&#8220;, weil die eigentlich vorgesehene Lösung fehlte?
</p>



<h3 class="wp-block-heading">Die &#8222;Common Language&#8220;: Unterschätzt, aber projektentscheidend</h3>



<p>
Ein Thema, das in der Theorie simpel klingt, aber in der Praxis regelmäßig Probleme verursacht, ist die <strong>gemeinsame Sprache</strong> – in DDD-Terminologie die <em>Ubiquitous Language</em>. Alle Beteiligten – Auftraggeber, Fachanwender, Entwickler – müssen dieselben Begriffe mit derselben Bedeutung verwenden. Klingt selbstverständlich. Ist es nicht.
</p>



<p>Ein konkretes Beispiel aus meiner eigenen Praxis: Ich hatte einen Kunden, der während der Planungsphase abwechselnd von einem <strong>&#8222;Plugin&#8220;</strong> und einer <strong>&#8222;Extension&#8220;</strong> sprach. Ich hörte beide Begriffe, ordnete sie aus Entwicklersicht selbstverständlich als Synonyme ein – und arbeitete entsprechend. Erst im <a href="https://eventstorming.com/" target="_blank" rel="noreferrer noopener"><strong>Event-Storming</strong></a>-Workshop stellte sich heraus: Der Kunde meinte mit <em>Plugin</em> und <em>Extension</em> <strong>zwei völlig verschiedene Konzepte</strong> mit unterschiedlichen Verantwortlichkeiten, unterschiedlichen Lebenszyklen und unterschiedlichen Benutzergruppen. Ohne diesen Workshop wäre die Fehlentwicklung erst Wochen später – und nach vielen Stunden unnötiger Arbeit – aufgefallen.</p>



<p>
Genau solche Missverständnisse sind in Legacy-Projekten besonders gefährlich, weil der alte Code die falsche Terminologie oft bereits zementiert hat. Eine saubere Migrations-Planung definiert deshalb frühzeitig ein <strong>Glossar</strong>: Jeder Begriff, der im Projekt verwendet wird, bekommt exakt eine Bedeutung – schriftlich festgehalten, für alle sichtbar, für alle verbindlich.
</p>



<h3 class="wp-block-heading">Praxisbeispiel: Software für Strafverfolgungsbehörden</h3>



<p>
Dass dieser strukturierte Ansatz in der Praxis funktioniert, zeigt ein Projekt, das seit 2023 zu meinen prägendsten Erfahrungen zählt: Ein Strafverfolgungsbeamter wandte sich an mich mit dem Wunsch, interne Arbeitswerkzeuge softwaretechnisch zu verbessern. Was folgte, waren <strong>sechs verschiedene Softwarelösungen</strong>, die ich gemeinsam mit ihm entwickelt und modernisiert habe.
</p>



<p>
Der Ausgangszustand war typisch für gewachsene Fachanwendungen: sogenannte <em>God-Files</em> – einzelne Klassen oder Dateien mit tausenden Zeilen Code, die alles auf einmal taten – kombiniert mit classic WinForms-Code, bei dem Datenbankzugriffe, Geschäftslogik und UI-Events untrennbar vermischt waren. Das Ergebnis war Code, den man nicht lesen, nicht testen und kaum erweitern konnte.
</p>



<p>
Nach der Modernisierung: saubere, wartbare WPF-MVVM-Architekturen mit klarer Schichtentrennung, automatisierten Tests und Code, der sich – wie ich es meinen Kunden beschreibe – <strong>wie ein Buch liest: von oben nach unten, linear, ohne Überraschungen</strong>. Jede Methode tut genau eine Sache. Jede Klasse hat genau eine Verantwortlichkeit. Neue Anforderungen lassen sich einfügen, ohne die bestehende Funktionalität zu gefährden. Dass dieser Anspruch an Code-Qualität in einem sicherheitskritischen Umfeld besonders zählt, versteht sich dabei von selbst.
</p>



<h3 class="wp-block-heading">NuGet-Pakete als Qualitätsbeweis: 60.000+ Downloads</h3>



<p>Clean Code und wartbare Architektur sind keine leeren Versprechen – sie lassen sich an öffentlich zugänglichen Ergebnissen messen. Neben Kundenprojekten veröffentliche ich aktiv Bibliotheken auf NuGet, dem zentralen Paket-Repository für .NET-Entwickler. Meine Pakete – <strong>darunter </strong><code><strong><a href="https://robbelroot.de/blog/rskibbe-i18n-translate-create-multilanguage-winforms-wpf-apps/">rskibbe.I18n</a></strong></code> für Internationalisierung und <code><strong><a href="https://robbelroot.de/blog/rskibbe-i18n-translate-create-multilanguage-winforms-wpf-apps/" target="_blank" rel="noreferrer noopener">rskibbe.Ini</a></strong></code> für die Arbeit mit INI-Konfigurationsdateien – haben inzwischen über <strong>60.000 Downloads</strong> durch andere Entwickler weltweit gesammelt.</p>



<p>
Der Ursprung dieser Pakete ist dabei typisch für Probleme, die ich in der Praxis immer wieder antreffe: In zahlreichen Projekten habe ich selbstgebastelten Übersetzungs-Code und selbstgestrickte INI-Parser vorgefunden – jedes Mal neu erfunden, jedes Mal leicht anders, jedes Mal mit denselben Schwächen. Kein einheitliches Verhalten, keine Tests, keine Dokumentation. Ein klassisches Symptom fehlender Wiederverwendbarkeit.
</p>



<p>
Mir war an einer <strong>funktionalen, zentralisierten Lösung</strong> gelegen – etwas, das einmal sauber gebaut wird und dann projekt­übergreifend verlässlich funktioniert, ohne dass man dasselbe Problem immer wieder von vorne lösen muss. Genau das habe ich mit <code>rskibbe.I18n</code> und <code>rskibbe.Ini</code> geschaffen: durchdachte, testbare Bibliotheken, die das jeweilige Problem ein für alle Mal lösen – und die andere Entwickler seither in tausenden eigener Projekte einsetzen.
</p>



<p>
Wer Pakete veröffentlicht, die andere Entwickler freiwillig in ihre eigenen Projekte einbinden, muss liefern: sauberes API-Design, verlässliches Verhalten, gute Dokumentation. Es ist gewissermaßen die härteste Form der Qualitätsprüfung – durch tausende unabhängige Nutzer. Für Sie als Kunde bedeutet das: Die Qualitätsmaßstäbe, die ich an meine eigenen Pakete anlege, gelten genauso für Ihren Code.
</p>



<h2 class="wp-block-heading">FAQ: Häufige Fragen zur Windows Forms zu WPF Migration</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-question-1773848963391"><strong class="schema-faq-question"><strong>Kann man Windows Forms direkt zu WPF konvertieren?</strong></strong> <p class="schema-faq-answer">Nein, es gibt kein automatisches Konvertierungstool, das eine WinForms-Anwendung 1:1 in WPF überführt. Die Technologien unterscheiden sich grundlegend: WinForms basiert auf GDI+, WPF auf DirectX und XAML. Eine Migration bedeutet, die UI neu zu bauen – aber die Business-Logik lässt sich in den meisten Fällen weitgehend übernehmen, sofern sie sauber von der UI getrennt ist.</p> </div> <div class="schema-faq-section" id="faq-question-1773849006406"><strong class="schema-faq-question"><strong>Wie lange dauert eine WinForms zu WPF Migration?</strong></strong> <p class="schema-faq-answer">Das hängt von der Codegröße und Codequalität ab. Als Orientierung: Kleine Anwendungen unter 10.000 LOC benötigen 2–6 Wochen, mittlere Projekte (10.000–50.000 LOC) 2–6 Monate, große Anwendungen über 50.000 LOC 6–18+ Monate. Der größte Einflussfaktor ist nicht die Größe, sondern wie stark Business-Logik und UI miteinander verwoben sind.</p> </div> <div class="schema-faq-section" id="faq-question-1773849196181"><strong class="schema-faq-question"><strong>Was kostet eine WinForms zu WPF Migration?</strong></strong> <p class="schema-faq-answer">Eine pauschale Aussage ist seriöserweise nicht möglich. Die Kosten hängen von Codegröße, Codequalität, Testabdeckung und fachlicher Komplexität ab. Entscheidend ist eine sorgfältige Erstanalyse: Wer ohne Analyse kalkuliert, kalkuliert falsch. Eine kostenlose Einschätzung für Ihr konkretes Projekt erhalten Sie im <a href="https://robbelroot.de/kontakt/" target="_blank" rel="noreferrer noopener"><strong>Erstgespräch</strong></a>.</p> </div> <div class="schema-faq-section" id="faq-question-1773849261951"><strong class="schema-faq-question"><strong>Muss ich alles auf einmal migrieren?</strong></strong> <p class="schema-faq-answer">Nein – und bei größeren Anwendungen ist das auch nicht empfehlenswert. Das Strangler-Fig-Pattern ermöglicht eine schrittweise Migration: Modul für Modul wird durch WPF ersetzt, während die Anwendung durchgehend produktiv bleibt. So entsteht ROI bereits während der Migration, und das Risiko bleibt beherrschbar.</p> </div> <div class="schema-faq-section" id="faq-question-1773849267805"><strong class="schema-faq-question"><strong>WPF oder .NET MAUI – was ist besser für Windows Desktop?</strong></strong> <p class="schema-faq-answer">Für reine Windows-Desktop-Anwendungen ist WPF die reifere Wahl: stabiles Ökosystem, breite MVVM-Unterstützung, umfangreiche Drittanbieter-Controls, direkte .NET-Integration. .NET MAUI ist für plattformübergreifende Anwendungen (Windows, macOS, iOS, Android) konzipiert – sinnvoll, wenn dieselbe App auf mehreren Plattformen laufen soll. Wer nur Windows-Desktop entwickelt, ist mit WPF besser bedient.</p> </div> <div class="schema-faq-section" id="faq-question-1773849278760"><strong class="schema-faq-question"><strong>Kann ich eine VB.NET WinForms Anwendung zu WPF migrieren?</strong></strong> <p class="schema-faq-answer">Ja – aber hier kommen zwei Herausforderungen zusammen: die Migration der UI-Technologie (WinForms → WPF) und optional der Sprachwechsel (VB.NET → C#). VB.NET und WPF lassen sich technisch kombinieren, allerdings ist MVVM in VB.NET umständlicher. In der Praxis empfehle ich, den Wechsel zu C# mit der WPF-Migration zu verbinden – der Mehraufwand ist überschaubar, der langfristige Vorteil erheblich.</p> </div> <div class="schema-faq-section" id="faq-question-1773849290319"><strong class="schema-faq-question"><strong>Lohnt sich WPF noch 2026?</strong></strong> <p class="schema-faq-answer">Ja. WPF wird aktiv weiterentwickelt – zuletzt mit .NET 9 und bald .NET 10. Für Windows-Desktop-Anwendungen bleibt WPF der beste Kompromiss aus Reife, Ökosystem und Zukunftssicherheit. Alternativen wie Avalonia oder .NET MAUI sind interessant, aber noch nicht annähernd so ausgereift für komplexe Business-Anwendungen.</p> </div> <div class="schema-faq-section" id="faq-question-1773849305073"><strong class="schema-faq-question"><strong>Was ist der Unterschied zwischen Code-Behind und MVVM in WPF?</strong></strong> <p class="schema-faq-answer">Code-Behind bedeutet: Logik landet direkt in der XAML-Code-Behind-Datei – exakt wie in WinForms, nur mit anderer Syntax. MVVM (Model–View–ViewModel) trennt UI und Logik konsequent: Das ViewModel enthält den gesamten Zustand und die Logik, die View bindet sich per Datenbinding daran. Ergebnis: testbarer Code, klare Verantwortlichkeiten, wartbare Architektur. Code-Behind in WPF ist ein häufiger Migrationsfehler – man hat dann WPF-Code, der sich wie schlechter WinForms-Code verhält.</p> </div> </div>



<h2 class="wp-block-heading">Fazit: Lohnt sich die Migration zu WPF?</h2>



<p>
In nahezu allen Fällen: <strong>Ja</strong>. Nicht weil WPF die einzige moderne Option ist – aber weil es für echte Windows-Desktop-Anwendungen mit .NET der beste Kompromiss aus Reife, Ökosystem und Zukunftssicherheit bleibt.
</p>



<p>
Was sich ändert, nachdem eine Migration abgeschlossen ist:
</p>



<ul class="wp-block-list">
<li>Neue Features lassen sich deutlich schneller implementieren</li>



<li>Entwickler finden sich im Code zurecht – auch wenn sie neu ins Projekt kommen</li>



<li>Unit-Tests werden erstmals möglich, was Regressions reduziert</li>



<li>Die Anwendung ist wartbar, die technischen Schulden sind abgebaut</li>
</ul>



<p>
Der richtige Zeitpunkt ist <strong>jetzt</strong> – bevor die Anwendung noch weiter wächst und die Migrations-Kosten steigen.
</p>



<hr class="wp-block-separator has-css-opacity"/>



<div class="wp-block-group has-white-color has-text-color has-background" style="background-color:#1a1a2e;padding-top:2rem;padding-right:2rem;padding-bottom:2rem;padding-left:2rem"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h3 class="wp-block-heading has-text-color" style="color:#F7941D">&#x1f680; Ihre Windows Forms Anwendung modernisieren?</h3>



<p>
    <strong>Ich analysiere Ihre Anwendung kostenlos und sage Ihnen in 30 Minuten:</strong>
  </p>



<ul class="wp-block-list">
<li>&#x2705; Welche Migrationsstrategie für Ihr Projekt sinnvoll ist</li>



<li>&#x2705; Was die Migration realistisch kostet und dauert</li>



<li>&#x2705; Welche Quick Wins sofort möglich sind</li>
</ul>



<p>
    Kein Verkaufsgespräch. Kein Overhead. Direkte Einschätzung von einem Entwickler, der solche Projekte täglich umsetzt.
  </p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link has-white-color has-text-color has-background has-link-color wp-element-button" href="https://robbelroot.de/kontakt/" style="background-color:#F7941D"><strong>Jetzt kostenloses Erstgespräch anfragen →</strong></a></div>
</div>



<p style="font-size:0.85rem">Oder zuerst einen Blick ins <strong><a href="https://robbelroot.de/portfolio" style="color:#F7941D;">Portfolio</a></strong> mit abgeschlossenen Projekten werfen</p>
</div></div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/windows-forms-zu-wpf-migrieren/">Windows Forms zu WPF migrieren: Der vollständige Guide (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/windows-forms-zu-wpf-migrieren/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>rskibbe.UI.Dialogs.Wpf.CommunityToolkit – A CommunityToolkit implementation</title>
		<link>https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-communitytoolkit/</link>
					<comments>https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-communitytoolkit/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 12 Mar 2025 01:10:33 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[NuGet Packages]]></category>
		<category><![CDATA[rskibbe]]></category>
		<category><![CDATA[rskibbe.UI]]></category>
		<category><![CDATA[rskibbe.UI.Dialogs]]></category>
		<category><![CDATA[rskibbe.UI.Dialogs.Wpf]]></category>
		<category><![CDATA[rskibbe.UI.Dialogs.Wpf.CommunityToolkit]]></category>
		<category><![CDATA[community toolkit]]></category>
		<category><![CDATA[dialog]]></category>
		<category><![CDATA[dialogs]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[view]]></category>
		<category><![CDATA[viewmodel]]></category>
		<category><![CDATA[window]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=19472</guid>

					<description><![CDATA[<p>What is rskibbe.UI.Dialogs.Wpf.CommunityToolkit? The goal – An MVVM friendly implementation for WPF The goal of rskibbe.UI.Dialogs.Wpf.CommunityToolkit is to provide an implementation basis for WPF MVVM based dialogs using the well-known &#8222;CommunityToolkit&#8220;. Installation Use the NuGet Package Manager of Visual Studio to install the base package (and corresponding sub-packages if wanted/needed). The easiest &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-communitytoolkit/">rskibbe.UI.Dialogs.Wpf.CommunityToolkit – A CommunityToolkit implementation</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[





<h2 class="wp-block-heading">What is rskibbe.UI.Dialogs.Wpf.CommunityToolkit?</h2>


<p class="rr-alert info" style="background:#e3f7fc;"><img decoding="async" alt="Info notice" src="https://robbelroot.de/wp-content/themes/pinboard-child/imgs/info.png"><span style="color:black;align-self: center;">The documentation is still a work in progress. Please understand that I do this for free and in my free time.</span></p>



<h2 class="wp-block-heading">The goal – An MVVM friendly implementation for WPF</h2>



<p>The goal of <strong>rskibbe.UI</strong>.<strong>Dialogs</strong>.<strong>Wpf.CommunityToolkit</strong> is to provide an implementation basis for WPF MVVM based dialogs using the well-known &#8222;CommunityToolkit&#8220;.</p>



<h2 class="wp-block-heading">Installation</h2>



<p>Use the <strong>NuGet Package Manager</strong> of Visual Studio to install the base package (and corresponding sub-packages if wanted/needed). The easiest way to access the Manager, is by clicking the „Extra“ menu tool strip menu item, or by right-clicking your project inside the project explorer. Then click something like „Manage NuGet Packages“. There you should be easily able to search for „rskibbe.UI.Dialogs“ and see all possible packages.</p>



<p>Or you can use the following NuGet Package Manager Console command for the newest version:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Install-Package rskibbe.UI.Dialogs
Install-Package rskibbe.UI.Dialogs.Wpf
Install-Package rskibbe.UI.Dialogs.Wpf.CommunityToolkit</pre>



<h2 class="wp-block-heading">Usage in project</h2>



<p>To use this package in your project, you just need to install all mentioned dependencies from above. In general, you can refer to &#8222;rskibbe.UI.Dialogs.Wpf&#8220; for setup instructions. The only difference here is the base class your deriving from. Instead of using the &#8222;DialogViewModelBase&#8220; from &#8222;rskibbe.UI.Dialogs.Wpf&#8220; you will be using the &#8222;CtDialogViewModelBase&#8220; so that you are able to use the source generators of the &#8222;CommunityToolkit&#8220;.</p>



<h2 class="wp-block-heading">Future plans / Todos</h2>



<p>Here are some future plans and potential tasks I hope to tackle in the near future. However, please keep in mind that this project is a passion project done in my free time, so I can’t guarantee if or when these updates will be completed.</p>



<ul class="wp-block-list">
<li>More documentation</li>



<li>More sub packages</li>
</ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-communitytoolkit/">rskibbe.UI.Dialogs.Wpf.CommunityToolkit – A CommunityToolkit implementation</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-communitytoolkit/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>rskibbe.UI.Dialogs.Wpf – An extension package for MVVM dialog implementation in WPF</title>
		<link>https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-an-extension-package-for-dialog-implementation-in-wpf/</link>
					<comments>https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-an-extension-package-for-dialog-implementation-in-wpf/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Mon, 10 Mar 2025 00:38:29 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[NuGet Packages]]></category>
		<category><![CDATA[rskibbe]]></category>
		<category><![CDATA[rskibbe.UI]]></category>
		<category><![CDATA[rskibbe.UI.Dialogs]]></category>
		<category><![CDATA[rskibbe.UI.Dialogs.Wpf]]></category>
		<category><![CDATA[dialogs]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[window]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=19423</guid>

					<description><![CDATA[<p>What is rskibbe.UI.Dialogs.Wpf? The goal – An MVVM friendly implementation for WPF The goal of rskibbe.UI.Dialogs.Wpf.CommunityToolkit is to provide an implementation basis for WPF MVVM based dialogs. Keep in mind, that this is an extension package of rskibbe.UI.Dialogs &#8211; so you will need this package as well &#8211; it&#8217;s providing &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-an-extension-package-for-dialog-implementation-in-wpf/">rskibbe.UI.Dialogs.Wpf – An extension package for MVVM dialog implementation in WPF</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[





<h2 class="wp-block-heading">What is rskibbe.UI.Dialogs.Wpf?</h2>


<p class="rr-alert info" style="background:#e3f7fc;"><img decoding="async" alt="Info notice" src="https://robbelroot.de/wp-content/themes/pinboard-child/imgs/info.png"><span style="color:black;align-self: center;">The documentation is still a work in progress. Please understand that I do this for free and in my free time.</span></p>



<h2 class="wp-block-heading">The goal – An MVVM friendly implementation for WPF</h2>



<p>The goal of <strong>rskibbe.UI</strong>.<strong>Dialogs.Wpf.CommunityToolkit</strong> is to provide an implementation basis for WPF MVVM based dialogs. Keep in mind, that this is an extension package of <strong><a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-a-base-package-for-dialog-infrastructure/">rskibbe.UI.Dialogs</a></strong> &#8211; so you will need this package as well &#8211; it&#8217;s providing the infrastructure for dialogs, creating a common ground.</p>



<h2 class="wp-block-heading">Installation</h2>



<p>Use the <strong>NuGet Package Manager</strong> of Visual Studio to install the base package (and corresponding sub-packages if wanted/needed). The easiest way to access the Manager, is by clicking the „Extra“ menu tool strip menu item, or by right-clicking your project inside the project explorer. Then click something like „Manage NuGet Packages“. There you should be easily able to search for „rskibbe.UI.Dialogs“ and see all possible packages.</p>



<p>Or you can use the following NuGet Package Manager Console command for the newest version:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Install-Package rskibbe.UI.Dialogs
Install-Package rskibbe.UI.Dialogs.Wpf</pre>



<h2 class="wp-block-heading">Usage in project</h2>



<p>To use this package in your project, you just need to install both mentioned dependencies from above. In the next step, you should register the WpfDialogService during your bootstrapping routine in the DI container. In my example, I&#8217;m using the &#8222;Autofac&#8220; and &#8222;Autofac.Extensions.DependencyInjection&#8220; nuget packages for dependency injection.</p>



<h3 class="wp-block-heading">DI registration (Usually at app startup / bootstrap process)</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="di-registration">        // somewhere before
        var builder = new ContainerBuilder();

        // register different dependencies, for example our DialogService
        builder.Register(c =>
        {
            var lifetimeScope = c.Resolve&lt;ILifetimeScope>();
            var autofacServiceProvider = new AutofacServiceProvider(lifetimeScope);
            var dialogService = DialogServiceBuilder
                .New
                .UseServiceProviderForViewModels(autofacServiceProvider)
                .Build();
            return dialogService;
        })
        .As&lt;IDialogService>()
        .SingleInstance();</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="di-registration">        ' somewhere before
        Dim builder = New ContainerBuilder()

        ' register different dependencies, for example our DialogService
        builder.Register(Function(c)
               Dim lifetimeScope = c.Resolve(Of ILifetimeScope)()
               Dim autofacServiceProvider = New AutofacServiceProvider(lifetimeScope)
               Dim dialogService = DialogServiceBuilder _
                   .New _
                   .UseServiceProviderForViewModels(autofacServiceProvider) _
                   .Build()
               Return dialogService
           End Function) _
        .As&lt;IDialogService>() _
        .SingleInstance()</pre>



<h3 class="wp-block-heading">Creating a DialogViewModel implementation</h3>



<p>To use the WpfDialogService&#8217;s &#8222;ShowDialogAsync&#8220; method, <strong>it needs an implementation of &#8222;IDialogViewModel&#8220;</strong>. The provided &#8222;DialogViewModelBase&#8220; from the &#8222;rskibbe.UI.Dialogs.Wpf&#8220;-package will help as base class. If your are used to build your WPF MVVM apps using the typical &#8222;CommunityToolkit&#8220; package, <strong>there&#8217;s also support for</strong> this, installing &#8222;rskibbe.UI.Dialogs.Wpf.<strong>CommunityToolkit</strong>&#8220; &#8211; then you could use the source generators.</p>



<p>In this example, we will create a dialog using the &#8222;DialogViewModelBase&#8220; base class. After creating the example ViewModel from below, fill it &#8211; as usual &#8211; with life (like commands, properties, etc.) and <strong>create a corresponding View</strong> for it like &#8222;MyDialogView&#8220;.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="creating-dialog-vm">// don't forget to import the base class
using rskibbe.UI.Dialogs.Wpf;

public class MyDialogViewModel : DialogViewModelBase
{

   // your DialogViewModel logic
   // create properties to bind from view
   // create commands to bind from view

}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="creating-dialog-vm">' don't forget to import the base class
Imports rskibbe.UI.Dialogs.Wpf

Public Class MyDialogViewModel
   Inherits DialogViewModelBase

   ' your DialogViewModel logic
   ' create properties to bind from view
   ' create commands to bind from view

End Class</pre>



<h3 class="wp-block-heading">Using the injected DialogService</h3>



<p>After like typical constructor dependency injection, you can use the dialog service like the following. You can either use the generic method overload, or you could first resolve a ViewModel for yourself from the dependency injection container.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="injection-example">// don't forget the imports
using rskibbe.UI.Dialogs;

public class YourViewModel
{

  IDialogService _dialogService;

  public YourViewModel(IDialogService dialogService)
  {
      _dialogService = dialogService;
  }

  // should be an ICommand, of course...
  private void Bla()
  {
      bool? dialogResult = _dialogService.ShowDialogAsync&lt;MyDialogViewModel>();
      // do something with the result
  }

}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="injection-example">' don't forget the imports
Imports rskibbe.UI.Dialogs

Public Class YourViewModel

  Private _dialogService As IDialogService

  Sub New(dialogService As IDialogService)
      _dialogService = dialogService;
  End Sub

  ' should be an ICommand, of course...
  Private Sub Bla()
      Dim dialogResult As Boolean? = _dialogService.ShowDialogAsync&lt;MyDialogViewModel>();
      ' do something with the result
  End Sub

End Class</pre>



<h2 class="wp-block-heading">Key takeaways</h2>



<p>Here I will talk about the key takeaways of this package, explaining classes, important stuff, the thoughts behind and so on.</p>



<h3 class="wp-block-heading" id="icanbeshownmodal-interface">IDialogViewModel</h3>



<p>The MVVM friendly base-interface for implementing / extending IDialog from the base package.</p>



<h3 class="wp-block-heading" id="icanbeshownmodal-interface">DialogViewModelBase</h3>



<p>A custom ViewModelBase implementation for IDialog / IDialogViewModel (and INotifyPropertyChanged behind the scenes).</p>



<h3 class="wp-block-heading" id="icanbeshownmodal-interface">WpfDialogServiceBuilder</h3>



<p>A helper class to build &#8222;WpfDialogServiceBase&#8220; for WPF MVVM apps using &#8222;Window&#8220; as dialogs (or based on).</p>



<h3 class="wp-block-heading">WpfDialogServiceBase</h3>



<p>A base class for constructing your own IDialogService implementation.</p>



<h3 class="wp-block-heading">WpfDialogService</h3>



<p>A standard implementation of an IDialogService for typical WPF MVVM apps. (You can use another package called &#8222;rskibbe.UI.Dialogs.Wpf.CommunityToolkit&#8220; if you need an implementation supporting the commonly used CommunityToolkit and &#8211; for example &#8211; its source generators).</p>



<h2 class="wp-block-heading">Future plans / Todos</h2>



<p>Here are some future plans and potential tasks I hope to tackle in the near future. However, please keep in mind that this project is a passion project done in my free time, so I can’t guarantee if or when these updates will be completed.</p>



<ul class="wp-block-list">
<li>More documentation</li>



<li>More sub packages</li>
</ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-an-extension-package-for-dialog-implementation-in-wpf/">rskibbe.UI.Dialogs.Wpf – An extension package for MVVM dialog implementation in WPF</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-an-extension-package-for-dialog-implementation-in-wpf/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>rskibbe.UI.Dialogs – A base package for dialog infrastructure</title>
		<link>https://robbelroot.de/blog/rskibbe-ui-dialogs-a-base-package-for-dialog-infrastructure/</link>
					<comments>https://robbelroot.de/blog/rskibbe-ui-dialogs-a-base-package-for-dialog-infrastructure/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sat, 08 Mar 2025 12:04:52 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[NuGet Packages]]></category>
		<category><![CDATA[rskibbe]]></category>
		<category><![CDATA[rskibbe.UI]]></category>
		<category><![CDATA[rskibbe.UI.Dialogs]]></category>
		<category><![CDATA[dialog]]></category>
		<category><![CDATA[dialogs]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[ui]]></category>
		<category><![CDATA[window]]></category>
		<category><![CDATA[windows forms]]></category>
		<category><![CDATA[winforms]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=19411</guid>

					<description><![CDATA[<p>What is rskibbe.UI.Dialogs? In my daily work as a freelance developer, I encounter a wide range of customer requirements, user stories, and technologies. When it comes to technologies—where we’ll dive deeper in a moment—I’m particularly referring to foundational concepts such as: I was frustrated by having to repeat the same &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-a-base-package-for-dialog-infrastructure/">rskibbe.UI.Dialogs – A base package for dialog infrastructure</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[





<h2 class="wp-block-heading">What is rskibbe.UI.Dialogs?</h2>


<p class="rr-alert info" style="background:#e3f7fc;"><img decoding="async" alt="Info notice" src="https://robbelroot.de/wp-content/themes/pinboard-child/imgs/info.png"><span style="color:black;align-self: center;">The documentation is still a work in progress. Please understand that I do this for free and in my free time.</span></p>



<p>In my daily work as a freelance developer, I encounter a wide range of customer requirements, user stories, and technologies. When it comes to technologies—where we’ll dive deeper in a moment—I’m particularly referring to foundational concepts such as:</p>



<ul class="wp-block-list">
<li>Windows (UI &#8211; not the Operating System)</li>



<li>Modal and non modal dialogs</li>



<li>Screens (stuff that gets displayed inside the Windows, etc.)</li>



<li>and more&#8230;</li>
</ul>



<p>I was frustrated by having to repeat the same tasks over and over. It wasn’t the work itself that bothered me, but rather the repetitive, tedious tasks—the &#8222;monkey work.&#8220; The kind of work that&#8217;s necessary, but always leaves you thinking, &#8222;There must be a faster, better way to do this.&#8220;</p>



<p>That&#8217;s exactly why I created my own little package: &#8222;…the UI stuff I always need.&#8220; I decided to make it freely available for everyone, so others can benefit from it and save time on repetitive tasks too.</p>



<p>So, feel free to use it or one of the (soon to follow) sub packages for corresponding technologies like WPF , Winforms, etc.</p>



<h2 class="wp-block-heading">The goal – A common ground for WPF, Winforms, Consoles &amp; more</h2>



<p>The goal of <strong>rskibbe.UI</strong>.<strong>Dialogs</strong> is to provide a unified infrastructure package that addresses the fundamental needs across various UI technologies like WPF, Windows Forms (WinForms), and even Console Apps. The aim is to consolidate &#8222;what&#8217;s commonly required&#8220; into a single, versatile package.</p>



<h2 class="wp-block-heading">Installation</h2>



<p>Use the&nbsp;<strong>NuGet Package Manager</strong>&nbsp;of Visual Studio to install the base package (and corresponding sub-packages if wanted/needed). The easiest way to access the Manager, is by clicking the „Extra“ menu tool strip menu item, or by right-clicking your project inside the project explorer. Then click something like „Manage NuGet Packages“. There you should be easily able to search for „rskibbe.UI.Dialogs“ and see all possible packages.</p>



<p>Or you can use the following NuGet Package Manager Console command for the newest version:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Install-Package rskibbe.UI.Dialogs</pre>



<h2 class="wp-block-heading">Key takeaways</h2>



<p>Here I will talk about the key takeaways of this package, explaining classes, important stuff, the thoughts behind and so on.</p>



<h3 class="wp-block-heading" id="icanbeshownmodal-interface">DialogState Enum</h3>



<p>Represents the different states (lifecycle) of a dialog.</p>



<h3 class="wp-block-heading" id="icanbeshownnonmodal-interface">ICloseAsync Interface</h3>



<p>Denotes something that can be closed async &#8211; the closing process itself could take some time.</p>



<h3 class="wp-block-heading" id="icanbeshownnonmodal-interface">IClosedAsync Interface</h3>



<p>An interface denoting something which has been closed async &#8211; the closing itself has been completely finished and this is the &#8222;after state&#8220; before being cleaned up.</p>



<h3 class="wp-block-heading" id="icanbeshownnonmodal-interface">IDialog Interface</h3>



<p>An internface denoting a typical Dialog implementing &#8222;INotifyPropertyChanged&#8220; to propagate state changes. Important: It contains a &#8222;DialogResult&#8220;, &#8222;DialogState&#8220; and &#8222;IsBusy&#8220; properties to represent the states / results of a typical dialog.</p>



<h3 class="wp-block-heading" id="icanbeshownnonmodal-interface">IDialogService Interface</h3>



<p>Denotes something that handles showing dialogs like &#8222;ShowDialogAsync&#8220;, etc.</p>



<h3 class="wp-block-heading" id="icanbeshownnonmodal-interface">IInitializeAsync Interface</h3>



<p>Denotes something that can be Initialized async &#8211; initialization should be rather quick than slow (still enabled for like loading a quick file, whatever).</p>



<h3 class="wp-block-heading" id="icanbeshownnonmodal-interface">IShowAsync Interface</h3>



<p>Denotes something that can be shown &#8211; put code here, that is executed during the &#8222;show&#8220; process itself (like loading a customer from database, showing an indicator meanwhile, etc.).</p>



<h3 class="wp-block-heading" id="icanbeshownnonmodal-interface">IShownAsync Interface</h3>



<p>Denotes something that can be shown async &#8211; put code here, that should be executed, after the &#8222;showing&#8220; process of like loading a customer has been completed and should be run afterwards.</p>



<h2 class="wp-block-heading">Sub packages</h2>



<p>Here, you&#8217;ll find the freely available sub-packages that complement the main package. These sub-packages are tailored to support specific technology stacks, such as WPF MVVM or Windows Forms (WinForms), helping to establish a solid foundation for developing your applications.</p>



<h3 class="wp-block-heading">rskibbe.UI.Dialogs.Wpf</h3>



<p>One of the sub packages which is responsible for providing the WPF MVVM related infrastructure is: &#8222;<strong><a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-an-extension-package-for-dialog-implementation-in-wpf/" target="_blank" rel="noreferrer noopener">rskibbe.UI.Dialogs.Wpf</a></strong>&#8222;.</p>



<h3 class="wp-block-heading">rskibbe.UI.Dialogs.Wpf.CommunityToolkit</h3>



<p>One of the sub packages which adds easy support for using the well-known &#8222;CommunityToolkit&#8220;: &#8222;<strong><a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-wpf-communitytoolkit/" target="_blank" rel="noreferrer noopener">rskibbe.UI.Dialogs.Wpf.CommunityToolkit</a></strong>&#8222;.</p>



<h2 class="wp-block-heading">Future plans / Todos</h2>



<p>Here are some future plans and potential tasks I hope to tackle in the near future. However, please keep in mind that this project is a passion project done in my free time, so I can’t guarantee if or when these updates will be completed.</p>



<ul class="wp-block-list">
<li>More documentation</li>



<li>More sub packages</li>
</ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-ui-dialogs-a-base-package-for-dialog-infrastructure/">rskibbe.UI.Dialogs – A base package for dialog infrastructure</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/rskibbe-ui-dialogs-a-base-package-for-dialog-infrastructure/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>rskibbe.UI.Screens.Wpf – A common ground for WPF MVVM related UI infrastructure</title>
		<link>https://robbelroot.de/blog/rskibbe-ui-screens-wpf-a-common-ground-for-wpf-mvvm-related-ui-infrastructure/</link>
					<comments>https://robbelroot.de/blog/rskibbe-ui-screens-wpf-a-common-ground-for-wpf-mvvm-related-ui-infrastructure/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Fri, 04 Oct 2024 14:32:04 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[NuGet Packages]]></category>
		<category><![CDATA[rskibbe]]></category>
		<category><![CDATA[rskibbe.UI]]></category>
		<category><![CDATA[rskibbe.UI.Screens]]></category>
		<category><![CDATA[rskibbe.UI.Screens.Wpf]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[dialogs]]></category>
		<category><![CDATA[infrastructure]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[screen]]></category>
		<category><![CDATA[screens]]></category>
		<category><![CDATA[ui]]></category>
		<category><![CDATA[ux]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=19320</guid>

					<description><![CDATA[<p>What is rskibbe.UI.Screens.Wpf? This is a sub package for the base NuGet package extending the infrastructure provided by &#8222;rskibbe.UI.Screens&#8222;. This package is dependent on CommunityToolkit.MVVM package, as it&#8217;s the most commonly used one in terms of WPF and MVVM. I decided to not stripe it away, as I think, that &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-ui-screens-wpf-a-common-ground-for-wpf-mvvm-related-ui-infrastructure/">rskibbe.UI.Screens.Wpf – A common ground for WPF MVVM related UI infrastructure</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[





<h2 class="wp-block-heading">What is rskibbe.UI.Screens.Wpf?</h2>



<p>This is a sub package for the base NuGet package extending the infrastructure provided by &#8222;<a href="https://robbelroot.de/blog/rskibbe-ui-screens-a-base-package-for-ui-infrastructure/" target="_blank" rel="noreferrer noopener"><strong>rskibbe.UI.Screens</strong></a>&#8222;. This package is dependent on <strong><a href="https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/" target="_blank" rel="noreferrer noopener">CommunityToolkit.MVVM</a></strong> package, as it&#8217;s the most commonly used one in terms of WPF and MVVM. I decided to not stripe it away, as I think, that this is the absolute core of using MVVM &#8211; therefore I&#8217;m currently not planning to remove it in the near future. </p>



<p>Currently, this package is also dependent on the <strong><a href="https://autofac.org/" target="_blank" rel="noreferrer noopener">Autofac</a></strong> &#8222;Dependency Injection Library&#8220; as I&#8217;m using it in almost every app I build. I spent some time making it based on the &#8222;<strong><a href="https://learn.microsoft.com/en-us/dotnet/api/system.iserviceprovider?view=net-8.0" target="_blank" rel="noreferrer noopener">IServiceProvider</a></strong>&#8220; interface, but as it&#8217;s not as powerful, I decided to drop it &#8211; especially in terms of my own time. Maybe I&#8217;ll change that in the future, but currently, this isn&#8217;t planned as well.</p>



<p>Keep these two things in mind, when using the package!</p>


<p class="rr-alert info" style="background:#e3f7fc;"><img decoding="async" alt="Info notice" src="https://robbelroot.de/wp-content/themes/pinboard-child/imgs/info.png"><span style="color:black;align-self: center;">The documentation is still a work in progress. Please understand that I do this for free and in my free time.</span></p>



<h2 class="wp-block-heading">Installation</h2>



<p>Use the&nbsp;<strong>NuGet Package Manager</strong>&nbsp;of Visual Studio to install the base package (and corresponding sub-packages if wanted/needed). The easiest way to access the Manager, is by clicking the „Extra“ menu tool strip menu item, or by right-clicking your project inside the project explorer. Then click something like „Manage NuGet Packages“. There you should be easily able to search for „rskibbe.UI.Screens.Wpf“ and see all possible packages.</p>



<p>Or you can use the following NuGet Package Manager Console commands for the newest versions:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Install-Package rskibbe.UI.Screens
Install-Package rskibbe.UI.Screens.Wpf</pre>



<h2 class="wp-block-heading">Key Takeaways</h2>



<ul class="wp-block-list">
<li><a href="#wpfappclass"><strong>WpfApp Class</strong></a></li>



<li><strong><a href="#wpfwindowclass">WpfWindow Class</a></strong></li>



<li><strong><a href="#viewmodelbaseclass">ViewModelBase Class</a></strong></li>



<li><strong><a href="#screenviewmodelbaseclass">ScreenViewModelBase Class</a></strong></li>
</ul>



<h2 class="wp-block-heading" id="wpfappclass">WpfApp Class</h2>



<p>In general, the &#8222;System.Windows.Application&#8220; class is the core of each WPF application. For my use cases I mostly have recurring things I have to do, like:</p>



<ul class="wp-block-list">
<li>Registering Dependencies</li>



<li>Defining the start window</li>



<li>Instantiating the starting viewmodel</li>



<li>Overriding &#8222;OnStartup&#8220; method</li>



<li>etc&#8230;</li>
</ul>



<p>To make these steps easier I created this class which combines / wraps these &#8222;every time I start a new WPF app&#8220; steps. Let your own App derive from the WpfApp class and override the abstract methods to kickstart everything.</p>



<p>There are some conventions going on behind the scenes, to avoid overhead, repetitive and annoying duplications:</p>



<h4 class="wp-block-heading">RegisterViewModels</h4>



<p>This method gets called automatically behind the scenes to register the ViewModels of your application. Take a look at it&#8217;s description to learn more about finetuning these aspects.</p>



<p>Primarily there are 3 important methods to be overriden:</p>



<h3 class="wp-block-heading">RegisterAdditionalDependencies</h3>



<p>Use this method to like register services, repositories and anything else.</p>



<h3 class="wp-block-heading">GetMainWindowType</h3>



<p>This method should return the type of the MainWindow, as my app can&#8217;t know which Window-Class you&#8217;re going to use for your individual project. The class needs to have an empty constructor to be instantiated.</p>



<h3 class="wp-block-heading">GetMainWindowViewModelType</h3>



<p>This method should return the type of the MainViewModel class, as my app can&#8217;t know which ViewModel class you&#8217;re going to use for your individual project.</p>



<h2 class="wp-block-heading" id="wpfwindowclass">WpfWindow Class</h2>



<p>The WpfWindow class represents the MainWindow of the app. It implements &#8222;IWpfWindow&#8220; from above, is therefore having a &#8222;CurrentScreen&#8220; implementing &#8222;IScreen&#8220;. It inherits the typical &#8222;System.Windows.Window&#8220; WPF class. In modern app development, it&#8217;s usual to have some sort of main window which is just switching between different sub-screens.</p>



<p>Usually, you should use a derived class of the &#8222;HostScreenViewModelBase&#8220; if you want that navigation-ish app style, or you could use derived class of the &#8222;ScreenViewModelBase&#8220; if you want like a one-screen app.</p>



<h2 class="wp-block-heading" id="viewmodelbaseclass">ViewModelBase Class</h2>



<p>Nothing big to be seen here, the &#8222;ViewModelBase&#8220; class is just &#8211; as it&#8217;s suggesting &#8211; a base class for any kind of ViewModel. It depends on the &#8222;CommunityToolkit.MVVM&#8220; ObservableObject class.</p>



<h2 class="wp-block-heading" id="screenviewmodelbaseclass">ScreenViewModelBase Class</h2>



<p>&lt;more to come&gt;</p>



<h2 class="wp-block-heading">Future plans / Todos</h2>



<p>Here are some future plans and potential tasks I hope to tackle in the near future. However, please keep in mind that this project is a passion project done in my free time, so I can&#8217;t guarantee if or when these updates will be completed.</p>



<ul class="wp-block-list">
<li>More documentation</li>



<li>Getting rid of unnecessary dependencies</li>



<li>Logging without Debugger (something like Microsoft.Extensions.Logging.ILogger)</li>
</ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-ui-screens-wpf-a-common-ground-for-wpf-mvvm-related-ui-infrastructure/">rskibbe.UI.Screens.Wpf – A common ground for WPF MVVM related UI infrastructure</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/rskibbe-ui-screens-wpf-a-common-ground-for-wpf-mvvm-related-ui-infrastructure/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>INotifyPropertyChanged in .NET automatisch implementieren</title>
		<link>https://robbelroot.de/blog/inotifypropertychanged-in-net-automatisch-implementieren-fuer-winforms-und-wpf/</link>
					<comments>https://robbelroot.de/blog/inotifypropertychanged-in-net-automatisch-implementieren-fuer-winforms-und-wpf/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 01 Mar 2023 11:51:09 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[C# (C Sharp)]]></category>
		<category><![CDATA[C# Problemlösungen]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[WPF Problemlösungen]]></category>
		<category><![CDATA[bindung]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[datenbindung]]></category>
		<category><![CDATA[fody]]></category>
		<category><![CDATA[inotifypropertychanged]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[notification]]></category>
		<category><![CDATA[notify]]></category>
		<category><![CDATA[propertychanged]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=14475</guid>

					<description><![CDATA[<p>Kennst Du das auch: Du sitzt vor Deinen .NET Klassen und musst für WPF und Co. die INotifyPropertyChanged-Schnittstelle das gefühlte tausendste Mal implementieren? Eigentlich hättest Du Besseres zu tun und der Kunde (oder Dein Chef) sitzt Dir schon im Nacken? Damit ist nun Schluss – also mit dem repetitiven implementieren &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/inotifypropertychanged-in-net-automatisch-implementieren-fuer-winforms-und-wpf/">INotifyPropertyChanged in .NET automatisch implementieren</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/03/INotifyPropertyChanged-in-.NET-automatisch-implementieren.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/03/INotifyPropertyChanged-in-.NET-automatisch-implementieren.png" alt="INotifyPropertyChanged in .NET automatisch implementieren" class="wp-image-14501" title="INotifyPropertyChanged in .NET automatisch implementieren"/></a><figcaption class="wp-element-caption">INotifyPropertyChanged in .NET automatisch implementieren</figcaption></figure>






<p>Kennst Du das auch: Du sitzt vor Deinen .NET Klassen und musst für WPF und Co. die INotifyPropertyChanged-Schnittstelle das gefühlte tausendste Mal implementieren? Eigentlich hättest Du Besseres zu tun und der Kunde (oder Dein Chef) sitzt Dir schon im Nacken? Damit ist nun Schluss – also mit dem repetitiven implementieren der Schnittstelle –, denn dafür gibt es Abhilfe!</p>



<p><strong>Installiere dazu einfach die beiden NuGet-Pakete &#8222;PropertyChanged.Fody&#8220; und &#8222;Fody&#8220;. Konfiguriere Diese mit einer passenden &#8222;FodyWeavers.xml&#8220;-Datei und erstelle eine Klasse, Welche die INotifyPropertyChange-Schnittstelle implementiert, fertig!</strong></p>



<h2 class="wp-block-heading">Keine Lust auf &#8222;Monkey Work&#8220; &#8211; Hilfe muss her!</h2>



<p>Jeder .NET Entwickler, Welcher mit Daten und dessen Änderungen in Verbindung kommt, kennt es. Man muss der grafischen Oberfläche &#8222;Hey, der Vorname hier, der hat sich geändert, bitte zeige Den einmal aktualisiert an!&#8220;, mitteilen. Für gewöhnlich passiert das im .NET-Umfeld über die <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.componentmodel.inotifypropertychanged?view=net-7.0" target="_blank" rel="noreferrer noopener">INotifyPropertyChanged-Schnittstelle</a></strong>. Diese kann nicht wirklich viel – wie auch als Interface –, Sie gibt uns jedoch den Schlachtplan für genau diese Frage: &#8222;Welche Eigenschaft hat sich geändert?&#8220;.</p>



<p>Wie oben schon erwähnt kann es aber nun ziemlich langweilig und vor Allem nervig werden. Schließlich besteht unsere Anwendung für gewöhnlich aus zig Klassen, Welche alle gewisse Daten beinhalten, dessen Änderungen nach außen mitgeteilt werden möchten. Tun wir dies nicht, bekommt die grafische Oberfläche davon nichts mit und kann die aktualisierten Daten auch nicht anzeigen.</p>



<p>Uns bleibt also nichts Anderes übrig, als die Schnittstelle in jeder benötigten Klasse zu implementieren, oder? Zum Glück ist dem nicht so! Wie das funktioniert, erfährst Du im weiteren Verlauf.</p>



<h2 class="wp-block-heading">Im Videoformat</h2>



<p>Möchtest Du etwas auf die Augen und die Ohren bekommen? Ist Dir der Text eventuell zu träge? Dann schaue Dir gerne das passende Video auf meinem YouTube-Kanal an. Beachte, dass das deutsche Video VB.NET als Sprache verwendet, allerdings ist dies natürlich genauso gut auf C# anwendbar. Ich empfehle Dir trotzdem, den Beitrag ebenso anzuschauen, da ich hier nochmal in mehr Detail auf die einzelnen Dinge eingehen kann.</p>


<div class="async-youtube" data-embed="FQBWu_fiKO4" data-alt="">
    <div class="play-button"></div>      
  </div>



<h2 class="wp-block-heading">Einfacher, ja, aber &#8222;ich dachte da ist mehr drin&#8220;</h2>



<p>Wenn Du meinen <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/" target="_blank" rel="noreferrer noopener">detaillierten Beitrag über die INotifyPropertyChanged-Schnittstelle</a></strong> gelesen / gesehen hast, kennst Du vermutlich schon eine Vereinfachung. Diese haben wir erreicht, indem wir eine mehr oder weniger generischere Variante geschrieben haben. Dort gab es eine gewisse Methode (NotifyOfPropertyChange) innerhalb einer Klasse, Welche den Namen der geänderten Eigenschaft entgegengenommen hat. Das hat uns zumindest das Auslösen des &#8222;PropertyChanged&#8220;-Ereignisses vereinfacht.</p>



<p>Das Tolle daran war auch, dass wir den Namen der geänderten Eigenschaft nicht manuell angeben mussten. Dies konnte durch das <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.runtime.compilerservices.callermembernameattribute?view=net-7.0" target="_blank" rel="noreferrer noopener">&#8222;CallerMemberName&#8220;-Attribut</a></strong> des übergebenen Parameters automatisch bestimmt werden – insofern die Methode aus dem Setter der Eigenschaft aufgerufen wurde. Wenn man dann noch den <strong>&#8222;NameOf&#8220;-Ausdruck</strong> verwendet, hat man schon eine wirklich solide Basis.</p>



<p>Letztendlich stinkt es einem dennoch, wenn man folgenden Code sieht, Dieser ist einfach nur repetitiv und somit nicht gerade <strong><a href="https://de.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself" target="_blank" rel="noreferrer noopener">DRY</a></strong> getreu. Ebenso bläht er den Code unnötig auf und man hat fast gar keine Lust mehr, Diesen zu lesen. Das ist natürlich fatal..</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="wiederholender-notify-code"> Public Class SomeThing
    Inherits PropertyChangedBase

    Private _company As String

    Public Property Company As String
        Get
            Return _company
        End Get
        Set(value As String)
            If _company = value Then
                Return
            End If
            _company = value
            NotifyOfPropertyChange()
        End Set
    End Property

    ' property 2...

    ' property 3...

    ' ...

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="wiederholender-notify-code">public class SomeThing : PropertyChangedBase
{
    private string _company;

    public string Company
    {
        get => _company;
        set
        {
            if (_company == value)
                return;
            _company = value;
            NotifyOfPropertyChange();
        }
    }

    // property 2...

    // property 3...

    // ...

}</pre>



<h2 class="wp-block-heading">Fody installieren</h2>



<p>Das NuGet-Paket des Vertrauens, Welches uns die Arbeit erleichtern wird, nennt sich &#8222;Fody&#8220;. Also zumindest das Haupt-Paket, zusätzlich brauchen wir ein Sub-Paket namens &#8222;PropertyChanged.Fody&#8220;. Installiere nun also bitte beide Pakete, indem Du entweder die grafische Oberfläche des NuGet Paket-Managers, oder dessen Konsole verwendest.</p>



<p>Die Entwickler von Fody empfehlen es, die Konsolen-Variante zu verwenden, ich hatte bisher aber ehrlich gesagt noch nie Probleme mit der GUI-Variante. Gehe oben in Visual Studios Menüleiste auf &#8222;Extras&#8220; und wähle &#8222;NuGet-Paket-Manager&#8220;. Dann wählst Du &#8222;Paket-Manager-Konsole&#8220;, schon sollte sich ebendiese Konsole öffnen.</p>



<p>Kopiere nun die beiden Befehle und führe Sie einzeln in der Paket-Manager-Konsole aus:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Install-Package Fody
Install-Package PropertyChanged.Fody</pre>



<h2 class="wp-block-heading">Fody konfigurieren</h2>



<p>Leider sind wir noch nicht fertig, nachdem wir die notwendigen Pakete installiert haben, noch nicht! Wir müssen die installierten Pakete noch konfigurieren. Fody weiß ansonsten nicht, was es tun soll, bzw. Welche Sub-Pakete (es gibt noch mehr..) verwendet werden sollen.</p>



<p>Wir haben für unseren Bedarf ja das &#8222;PropertyChanged.Fody&#8220;-Sub-Paket installiert, Dieses konfigurieren wir nun als &#8222;wir möchten das gerne verwenden&#8220;. Lege dazu im nächsten Schritt eine <strong>XML-Datei</strong> in Deinem Projektverzeichnis an. Klicke dazu einfach mit einem Rechtsklick auf Deine Projektmappe und wähle &#8222;Hinzufügen-&gt;Neues Element&#8220;. Beachte bitte, dass die neuste Version von Visual Studio eine neue Darstellung – die Kompaktansicht – gewählt hat.</p>



<p>Diese Kompaktansicht kannst Du ganz einfach &#8222;ausklappen&#8220;, indem Du die jeweilige Option unten links anklickst. Erstelle mit Hilfe des Dialoges nun die XML-Datei und betitle Sie als &#8222;<strong>FodyWeavers.xml</strong>&#8222;. In diese Datei gibst Du nun folgenden Text, für unser Beispiel ein:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="FodyWeavers.xml" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  &lt;PropertyChanged />
&lt;/Weavers></pre>



<p>Ich hatte hier übrigens ursprünglich nur das &#8222;Weavers&#8220;-Tag und das Kind &#8222;PropertyChanged&#8220; eingefügt. Der Rest wurde später automatisch ergänzt (ehrlich gesagt, keine Ahnung woher, vermutlich durch VS oder Fody selbst). Das sah vorher so aus und reichte wohl auch:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="FodyWeavers.xml" data-enlighter-group="">&lt;Weavers>
  &lt;PropertyChanged />
&lt;/Weavers></pre>



<h2 class="wp-block-heading">Unsere finale Klasse</h2>



<p>Im letzten Schritt reicht es aus, dass Du einfach nur eine Klasse erstellst, Welche die &#8222;INotifyPropertyChanged&#8220;-Schnittstelle implementiert &#8211; das war&#8217;s! Dies kann z. B. durch Vererbung der im anderen Beitrag gezeigten &#8222;PropertyChangedBase&#8220;-Klasse passieren, oder Du machst es manuell. Ebenso stellt Fody ein Klassen-Attribut zur Vereinfachung bereit.</p>



<h3 class="wp-block-heading">Beispiel 1 &#8211; Vererbung (nach wie vor):</h3>



<p>Hier verwenden wir die ganz &#8222;normale&#8220; Vererbung, mit der <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/#PropertyChangedBase-Klasse" target="_blank" rel="noreferrer noopener">Klasse aus dem anderen Beitrag</a></strong>. Der Vorteil hier ist: Falls wir doch eigene Setter o Ä. schreiben, können wir immer noch auf die Hilfs-Methode &#8222;NotifyOfPropertyChange&#8220; zugreifen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="finale-klasse-bsp-1"> Public Class SomeThing
    Inherits PropertyChangedBase

    Public Property Company As String

    ' property 2...

    ' property 3...

    ' ...

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="finale-klasse-bsp-1">public class SomeThing : PropertyChangedBase
{

    public string Company { get; set; }

    // property 2...

    // property 3...

    // ...

}</pre>



<h3 class="wp-block-heading">Beispiel 2 &#8211; Mit Attribut von Fody &amp; ohne Vererbung</h3>



<p>Hier benötigen wir keine zusätzliche Klasse! Durch das Attribut über der Klasse, weiß Fody, dass hier am Ende die INPC-Schnittstelle automatisch implementiert werden soll &#8211; nice!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="finale-klasse-bsp-2"> Imports PropertyChanged

 &lt;AddINotifyPropertyChangedInterface>
 Public Class SomeThing
    Inherits PropertyChangedBase

    Public Property Company As String

    ' property 2...

    ' property 3...

    ' ...

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="finale-klasse-bsp-2">using PropertyChanged;

[AddINotifyPropertyChangedInterface]
public class SomeThing
{

    public string Company { get; set; }

    // property 2...

    // property 3...

    // ...

}</pre>



<h2 class="wp-block-heading">&#8222;PrivateAssets&#8220;-Meldung / Warnung</h2>



<p>Durch die Verwendung der vorgestellten Vorgehensweise mit Fody, sparen wir uns (wie Du sicherlich gemerkt haben wirst) eine Menge an Aufwand. Leider kommt es hier und dann noch zu einer kleinen Warnung. Diese Warnung sieht in etwa wie folgt aus:</p>



<p><strong><em>Warnung FodyPackageReference &#8222;Fody: The package reference for PropertyChanged.Fody does not contain PrivateAssets=&#8217;All'&#8220;</em></strong></p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/03/PackageFodyReference-The-package-reference-does-not-contain-PrivateAssets-All.png"><img loading="lazy" decoding="async" width="686" height="170" src="https://robbelroot.de/wp-content/uploads/2023/03/PackageFodyReference-The-package-reference-does-not-contain-PrivateAssets-All.png" alt="PackageFodyReference - The package reference does not contain PrivateAssets All" class="wp-image-14536" title="PackageFodyReference - The package reference does not contain PrivateAssets All"/></a><figcaption class="wp-element-caption">PackageFodyReference &#8211; The package reference does not contain PrivateAssets All</figcaption></figure>



<p>In meiner aktuellen Installation für diesen Beitrag und dem zugehörigen Video, hatte ich dieses Problem nicht. Vielleicht nimmt das dem ein oder anderen Tester die Angst vor Neuem &#8211; es lohnt sich wirklich.</p>



<h3 class="wp-block-heading">Was bedeutet die &#8222;PrivateAssets&#8220;-Warnung?</h3>



<p>Bevor wir uns an die Problemlösung wagen, sollten wir vielleicht erstmal verstehen, was die Warnung überhaupt bedeutet. Kurzum ist dieses sogenannte &#8222;Metadata-Tag&#8220; (ein Schlüsselwort / Stichwort in den Metadaten) dazu da, um Abhängigkeiten zu steuern.</p>



<p>Ich zitiere dazu einfach mal den Punkt aus der <strong><a href="https://learn.microsoft.com/de-de/nuget/consume-packages/package-references-in-project-files#controlling-dependency-assets" target="_blank" rel="noreferrer noopener">offiziellen Dokumentation</a></strong>, wo Du natürlich gerne reinschauen darfst:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Sie verwenden eine Abhängigkeit möglicherweise rein als Entwicklungsumgebung und möchten diese nicht für Projekte verfügbar machen, die Ihr Paket nutzen. In diesem Szenario können Sie dieses Verhalten über die&nbsp;<code>PrivateAssets</code>-Metadaten steuern.</p>
</blockquote>



<p>Kurzum heißt das: Wenn wir nicht möchten, dass unsere verwendeten Helferlein (PropertyChanged.Fody, Fody) nach außen sichtbar sind, verwenden wir dieses Metadaten-Tag. Letztendlich brauchen wir Fody nur zur Entwicklung, daher ist es weniger nach außen relevant.</p>



<h3 class="wp-block-heading">Wie beheben?</h3>



<p>Die Warnung dementsprechend zu beheben ist nicht wirklich schwer, es ist letztendlich nur eine Konfigurationssache. <strong>Klicke </strong>dazu einfach mit einem <strong>Rechtsklick auf Dein Projekt</strong> und wähle &#8222;<strong>Projektdatei bearbeiten</strong>&#8222;. Danach fügst Du einfach das Tag wie im Bild markiert hinzu – schon sollte die Meldung verschwinden!</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/03/PrivateAssets-All-fuer-Fody-NuGet-Paket-festlegen.png"><img loading="lazy" decoding="async" width="792" height="140" src="https://robbelroot.de/wp-content/uploads/2023/03/PrivateAssets-All-fuer-Fody-NuGet-Paket-festlegen.png" alt="PrivateAssets All für Fody NuGet Paket festlegen" class="wp-image-14550" title="PrivateAssets All für Fody NuGet Paket festlegen"/></a><figcaption class="wp-element-caption">PrivateAssets All für Fody NuGet Paket festlegen</figcaption></figure>



<h2 class="wp-block-heading">Downloads</h2>



<p>Keine Lust alles abzutippen und manuell ran zu gehen? Verständlich! Lade Dir einfach das passende Beispielprojekt herunter und starte ohne Verzögerung.</p>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=2fc6b841-79d9-407e-b9d2-e1954dd793a1" target="_blank" rel="noreferrer noopener">InpcAutomatischImplementierenVB.zip</a></div>


</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/inotifypropertychanged-in-net-automatisch-implementieren-fuer-winforms-und-wpf/">INotifyPropertyChanged in .NET automatisch implementieren</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/inotifypropertychanged-in-net-automatisch-implementieren-fuer-winforms-und-wpf/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>The WPF ListView Control – the complete Guide in 2026</title>
		<link>https://robbelroot.de/blog/the-wpf-listview-control-the-complete-guide/</link>
					<comments>https://robbelroot.de/blog/the-wpf-listview-control-the-complete-guide/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sun, 08 Jan 2023 22:20:21 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET (EN)]]></category>
		<category><![CDATA[basic]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[control]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[foundation]]></category>
		<category><![CDATA[guide]]></category>
		<category><![CDATA[item]]></category>
		<category><![CDATA[items]]></category>
		<category><![CDATA[list]]></category>
		<category><![CDATA[listing]]></category>
		<category><![CDATA[listview]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[presentation]]></category>
		<category><![CDATA[repeat]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[view]]></category>
		<category><![CDATA[visual]]></category>
		<category><![CDATA[visual basic]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=14035</guid>

					<description><![CDATA[<p>The WPF ListView – listing items / things In today&#8217;s post, we are going to talk about one of the most basic controls: The WPF ListView. We will take a look at the different use cases of the ListView and we will try out some of the architectural styles. As &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/the-wpf-listview-control-the-complete-guide/">The WPF ListView Control – the complete Guide in 2026</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-Control-the-complete-Guide-640px.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-Control-the-complete-Guide-640px.png" alt="WPF ListView Control - the complete Guide" class="wp-image-14042" title="WPF ListView Control - the complete Guide"/></a><figcaption class="wp-element-caption">WPF ListView Control &#8211; the complete Guide</figcaption></figure>






<h2 class="wp-block-heading">The WPF ListView – listing items / things</h2>



<p>In today&#8217;s post, we are going to talk about one of the most basic controls: The WPF ListView. We will take a look at the different use cases of the ListView and we will try out some of the architectural styles. As MVVM is like the &#8222;way to go&#8220; in WPF, I will definitely examine this, but we won&#8217;t forget the &#8222;old way&#8220;. Like always, I will provide different source code examples in the two most used .NET languages, being C# and VB.NET.</p>



<p>This guide and all examples are compatible with .NET 8 and .NET 9.</p>



<p>Speaking of languages: Make sure Visual Studio is set up correctly → <strong><a href="https://robbelroot.de/blog/how-to-change-the-visual-studio-installer-language/" type="post" id="16369">Change VS Installer Language</a></strong>.</p>


<p class="rr-alert info" style="background:#e3f7fc;"><img decoding="async" alt="Info notice" src="https://robbelroot.de/wp-content/themes/pinboard-child/imgs/info.png"><span style="color:black;align-self: center;">Need quick help? Jump to the corresponding sections by using the <a href="#toc_container">table of contents</a>. When you are using the <a href="#code-behind-approach">code behind based approach</a>, jump there. If you are more the MVVM guy, you could jump and start with the <a href="#working-with-real-data">&#8222;MVVM approach&#8220; section</a>.</span></p>



<h2 class="wp-block-heading">What is a WPF ListView?</h2>



<p>When stumbling upon this control, the first question coming to your mind could be: &#8222;Well, what is a ListView – in the Windows Presentation Foundation – in the first place?&#8220;. I mean, by the name, you could just assume, that it&#8217;s something for displaying like a &#8222;list&#8220; of something, right? I mean, you are pretty much on the right side, but what makes it different from like a DataGrid, or even a ListBox? Don&#8217;t worry, we will cover this is a few minutes, further down below.</p>



<h3 class="wp-block-heading">The definition, I guess?</h3>



<p>Let&#8217;s first define, what a ListView really is by like definition:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em>A WPF ListView provides the basic tools needed, to help you displaying a set of data items. This can be easily done in like different views or layouts, depending on your usecase. Each item of those ListViews are displayed, using something called ListViewItem. A ListViewItem iteself  is – more or less – just another template-ish element, being a ContentControl.</em></p>
</blockquote>



<h3 class="wp-block-heading">Examining the ListView</h3>



<p>Let&#8217;s take a quick sneak peek into the inheritance-tree, of the WPF ListView Control, by pressing F12, while being on one of those with your mouse cursor. There you can see, that it actually inherits from the class ListBox.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-Control-Class-inheriting-from-ListBox.png"><img loading="lazy" decoding="async" width="809" height="363" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-Control-Class-inheriting-from-ListBox.png" alt="WPF ListView Control Class - inheriting from ListBox" class="wp-image-14056" title="WPF ListView Control Class - inheriting from ListBox"/></a><figcaption class="wp-element-caption">WPF ListView Control Class &#8211; inheriting from ListBox</figcaption></figure>



<h3 class="wp-block-heading">Inheritance tree</h3>



<p>Going further down, there are some other classes in the inheritance tree as well, like the Selector &amp; the ItemsControl class. I think, for most persons, it&#8217;s actually a surprise / a &#8222;good to know&#8220;-thing, that the ListView actually inherits from the ListBox class.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-Inheritance-Tree-640px.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-Inheritance-Tree-640px.png" alt="WPF ListView Inheritance Tree" class="wp-image-14088" title="WPF ListView Inheritance Tree"/></a><figcaption class="wp-element-caption">WPF ListView Inheritance Tree</figcaption></figure>



<p>At this point, you can see, that there&#8217;s pretty much going on in the background. The ListView itself is actually derived from a few levels of control hierarchy and is therefore bringing a lot &#8222;to the table&#8220;. For sure, we can&#8217;t go to every level in detail, but I think the most important ones for you are beginning at the ItemsControl.</p>



<p>I mean, in a real application scenario, you would most likely fetch some data like the &#8222;charts&#8220; or something like that. Those could then be displayed inside your ListView by specifying what should actually appear. The chart object could be composed from many different objects and therefore you would need to specify a bit further. </p>



<h2 class="wp-block-heading" id="code-behind-approach">A first example – with XAML &amp; code behind</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/A-first-WPF-ListView-example-–-hardcoded-in-XAML-640px.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/01/A-first-WPF-ListView-example-–-hardcoded-in-XAML-640px.png" alt="A first WPF ListView example – hardcoded in XAML" class="wp-image-14094" title="A first WPF ListView example – hardcoded in XAML"/></a><figcaption class="wp-element-caption">A first WPF ListView example – hardcoded in XAML</figcaption></figure>



<p>Let&#8217;s now focus on creating an actual first example of the ListView Control. To do so, we usually need to first have some kind of data to display. At this point, we will just create some hardcoded items, to see, how the ListView and its ListViewItems are created in the first place. Keep in mind, that we will do this and more in an MVVM manner, later – which is the preferred way for me personally.</p>



<p>We will surround the ListView by a GroupBox Control, to have some kind of labelling, etc. So go ahead and create a GroupBox XAML markup inside your MainWindow.xaml (inside the root Grid). You can write something like &#8222;Music stars&#8220;, etc. inside the Header Property of that GroupBox, like this, we have some kind of heading for our list.</p>



<p>After that, we can add some sort of styling like padding, a width and alignments to that GroupBox, to make it look less bruised. The final, but first testing XAML code could therefore look like this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    &lt;Grid>
        &lt;GroupBox Header="Some items" Padding="8" Width="200" VerticalAlignment="Center" HorizontalAlignment="Center">
            &lt;ListView>
                &lt;ListView.Items>
                    &lt;ListViewItem Content="Jimmy Hendrix" />
                    &lt;ListViewItem Content="Michael Jackson" />
                    &lt;ListViewItem Content="The Beatles" />
                &lt;/ListView.Items>
            &lt;/ListView>
        &lt;/GroupBox>
    &lt;/Grid></pre>



<p>The visual representation of that XAML code from above, will just look as simple as this.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-–-Displaying-Music-stars-as-simple-list.png"><img loading="lazy" decoding="async" width="789" height="449" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-–-Displaying-Music-stars-as-simple-list.png" alt="ListView – Displaying Music stars as simple list" class="wp-image-14099" title="ListView – Displaying Music stars as simple list"/></a><figcaption class="wp-element-caption">WPF ListView – Displaying Music stars as simple list</figcaption></figure>



<h3 class="wp-block-heading">How to add items to the WPF ListView?</h3>



<p>To add some items to the ListView in a &#8222;code behind&#8220;-manner, we need to specify a usual handler for like the click event, of for example a button. We can then react to that click inside of the handler and actually add a new item to the ListView. Go ahead and add a button inside of your MainWindow (Grid) and specify the &#8222;Click&#8220;-Property.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;Button Click="Button_Click" /></pre>



<p>It will suggest, to create an actual handler, you can confirm this and press F12 while being on the &#8222;Button_Click&#8220; text. After that, it will automatically jump to the corresponding part in your code – the code behind file. Feel free to rename that handler (in XAML &amp; code) to pick a better name, like &#8222;btnAddItem_Click&#8220;.</p>



<p>Inside of the click handler, we need to somehow say: &#8222;Hey, ListView, please remove an item!&#8220;. And we are only able to do so, if we have something to talk to. Currently, the ListView doesn&#8217;t have a name, so you should go back and specify a name for it:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;ListView x:Name="MusicArtistList" ....>
    &lt;!-- .... -->
&lt;/ListView></pre>



<p>The button click handler itself could just look like the following. We are just telling the property of the &#8222;MusicArtistList&#8220;, called &#8222;Items&#8220;: &#8222;Hey, please add another entry to yourself, thanks!&#8220;.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="btn-add-item-code-behind">    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MusicArtistList.Items.Add("Sam Smith");
    }</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="btn-add-item-code-behind">    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        MusicArtistList.Items.Add("Sam Smith")
    End Sub</pre>



<h3 class="wp-block-heading">How to remove items from the ListView again?</h3>



<p>If you have followed the above steps to actually add an item inside of our ListView, then you could be ready to remove it again. Keep in mind, that you should have like the click handler ready (by specifying the Buttons click property with like &#8222;btnRemove_Click&#8220;) and that the ListView needs a name. Otherwise, we wouldn&#8217;t be able to target it from the code behind file.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="btn-remove-item-code-behind">    private void btnRemove_Click(object sender, RoutedEventArgs e)
    {
        // this only works that easy due to our current "strings" example
        MusicArtistList.Items.Remove("Sam Smith");
    }</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="btn-remove-item-code-behind">    Private Sub btnRemove_Click(sender As Object, e As RoutedEventArgs)
        ' this only works that easy due to our current "strings" example
        MusicArtistList.Items.Remove("Sam Smith")
    End Sub</pre>



<h3 class="wp-block-heading">How to delete the selected item in the ListView?</h3>



<p>This one here is a bit different, because we can&#8217;t know at compile time, which one of the items, the user will select. We can&#8217;t therefore hardcode like a specific string thing, to be deleted later. We need a possibility, to get the currently selected item and delete it somehow.</p>



<p>This is actually pretty easy, as we get everything we need to know, from the ListView itself. We will first check, if there&#8217;s an actual selection and if so, we will delete that item by providing its index.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="btn-remove-selecteditem-code-behind">    private void btnRemoveSelectedItem_Click(object sender, RoutedEventArgs e)
    {
        bool noItemSelected = MusicArtistList.SelectedIndex == -1;
        if (noItemSelected)
            return;
        MusicArtistList.Items.RemoveAt(MusicArtistList.SelectedIndex);
    }</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="btn-remove-selecteditem-code-behind">Private Sub btnRemoveSelectedItem_Click(sender As Object, e As RoutedEventArgs)
    Dim noItemSelected As Boolean = MusicArtistList.SelectedIndex = -1
    If noItemSelected Then
        Return
    End If
    MusicArtistList.Items.RemoveAt(MusicArtistList.SelectedIndex)
End Sub</pre>



<h3 class="wp-block-heading">Okay, but not flexible, nor practical – imo</h3>



<p>So in the end, we just created a small ListView representation with like 3 entries for our music stars / artists. Currently, this isn&#8217;t really good, as it&#8217;s not dynamic or based on &#8222;real data&#8220;. We just hardcoded those ListViewItems inside the ListView and this isn&#8217;t pretty much practical.</p>



<p>The other problem with our current example is, that it&#8217;s not pretty flexible, currently we are having only like &#8222;1 Column&#8220;. With that, we can only display one &#8222;thing&#8220; per item and we are not really different from a ListBox. What if we wanted to publish some sort of &#8222;year of birth&#8220; information? I mean sure, we could just pump it into one string, but nah, that doesn&#8217;t feel right.</p>



<p>What we really need are some sort of columns and guess what, the ListView supports this out of the box, by just specifying the View property.</p>



<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">
    <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Need a WPF developer?</div>
    <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Got a WPF project that needs professional hands?</p>
    <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">I build WPF applications with clean MVVM architecture in C# and VB.NET — professionally and efficiently. Just send me a message.</p>
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">
      <a href="https://robbelroot.de/contact/" style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;white-space:nowrap;" onmouseover="this.style.background='#cf6d17'" onmouseout="this.style.background='#e67e22'">→ Get in touch</a>
    </div>
  </div>
</div>



<h2 class="wp-block-heading" id="working-with-real-data">Working with &#8222;real data&#8220; – MVVM approach</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Working-with-a-databound-ListView-–-dynamic-data-640px.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/01/Working-with-a-databound-ListView-–-dynamic-data-640px.png" alt="Working with a databound ListView – dynamic data" class="wp-image-14110" title="Working with a databound ListView – dynamic data"/></a><figcaption class="wp-element-caption">Working with a databound ListView – dynamic data</figcaption></figure>



<p>Moving away from that unpractical non-databased &#8222;stringish&#8220; approach from above, we will now start a newer, clean version of our ListView Control. But first, we need to actually define &#8222;what&#8220; to display, I mean, we need some sort of a so called &#8222;Model&#8220; (or even a ViewModel – but I&#8217;ll leave it at that for now). As we wanted to display some sort of &#8222;music star&#8220;-overview, we could think of a better term in the first place. I will call it list of artists, so let&#8217;s now <strong>create a new class called &#8222;MusicArtist&#8220;</strong> inside a matching folder.</p>



<p>Go ahead and <strong>create the corresponding folder</strong> inside your WPF project, first. We will call that folder like &#8222;<strong>Models</strong>&#8220; – remember, I don&#8217;t want to go too deep into the MVVM cosmos. I would encourage you to <strong><a href="https://robbelroot.de/blog/mvvm-csharp/" target="_blank" rel="noreferrer noopener">refer to my C# MVVM post</a></strong> for that and don&#8217;t be confused, it will for work VB.NET as well. I mean the characteristics of Model-View-ViewModel are in the focus, not the language itself :).</p>



<h3 class="wp-block-heading">The &#8222;MusicArtist&#8220; model class</h3>



<p>Thinking about the class itself and keeping our example from above in mind, we could say, that a music artist has the following properties. For sure, it&#8217;s just for our example and I&#8217;m trying to stay as easy as possible, so feel free to change anything you would like to.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MusicArtist.cs" data-enlighter-group="artist-class">using System;

namespace WpfListViewExampleCs.Models;

public class MusicArtist
{

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public DateTime Birthday { get; set; }

    public MusicArtist(string firstName, string lastName, DateTime birthday)
    {
        FirstName = firstName;
        LastName = lastName;
        Birthday = birthday;
    }
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MusicArtist.vb" data-enlighter-group="artist-class">Imports System

Namespace WpfListViewExampleCs.Models

    Public Class MusicArtist

        Public Property FirstName As String

        Public Property LastName As String

        Public Property Birthday As DateTime

        Public Sub New(firstName As String, lastName As String, birthday As DateTime)
            Me.FirstName = firstName
            Me.LastName = lastName
            Me.Birthday = birthday
        End Sub

    End Class

End Namespace</pre>



<p>In my example here, the music artist has two properties for the name, meaning a first- and a lastname. I don&#8217;t like the &#8222;name&#8220; only approach, as you can&#8217;t easily separate the names in some situations. Well, I mean yeah, before you mention it: &#8222;The Beatles&#8220; isn&#8217;t really nicely separatable in this manner, but, welcome to the world of software development. I would say, this isn&#8217;t the right moment to argue about this, so feel free – again – to change that as you wish. Additionally I thought about using the birthday property, to show some sort of formatting in the XAML as well.</p>



<h2 class="wp-block-heading">Displaying bound data inside the WPF ListView</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Displaying-bound-data-inside-the-WPF-ListView-640px.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/01/Displaying-bound-data-inside-the-WPF-ListView-640px.png" alt="Displaying bound data inside the ListView" class="wp-image-14135" title="Displaying bound data inside the ListView"/></a><figcaption class="wp-element-caption">Displaying bound data inside the WPF ListView</figcaption></figure>



<p>After specifying some kind of model to actually display inside the ListView, we now go ahead and tell the ListView about its datasource. The ListView will then know: &#8222;Where can I fetch my data from? What is my data?&#8220;.</p>



<h3 class="wp-block-heading">Preventing a known error</h3>



<p>But before, we need to clean up the old code, otherwise we could run into an error like this:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em>System.InvalidOperationException: &#8222;The items collection must be empty before using itemssource&#8220;</em></p>
</blockquote>



<p>To avoid this error, you need to remove the manually added items inside our XAML code. You can&#8217;t like say: &#8222;Hey, fetch the items from this datasource here&#8220; AND put them in manually by XAML. Please go ahead and remove this marked area from the XAML code:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Removing-the-hardcoded-XAML-Items-from-the-ListView.png"><img loading="lazy" decoding="async" width="526" height="201" src="https://robbelroot.de/wp-content/uploads/2023/01/Removing-the-hardcoded-XAML-Items-from-the-ListView.png" alt="Removing the hardcoded XAML Items from the ListView" class="wp-image-14130" title="Removing the hardcoded XAML Items from the ListView"/></a><figcaption class="wp-element-caption">Removing the hardcoded XAML Items from the ListView</figcaption></figure>



<h3 class="wp-block-heading">Giving the ListView its datasource</h3>



<p>In the next step, we will actually care for some items being displayed. For this, we will <strong>use the DataSource property of the ListView</strong> and bind to some property from our ViewModel. Don&#8217;t be scared, if you don&#8217;t know what a ViewModel is! Maybe this is another chance, to refer to <strong><a href="https://robbelroot.de/blog/mvvm-csharp/" target="_blank" rel="noreferrer noopener">my blog post considering the MVVM pattern</a></strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;ListView ItemsSource="{Binding MusicArtists}">
&lt;!-- rest of the listview.. -->
&lt;/ListView></pre>



<p>We won&#8217;t create a separate ViewModel right now, for this simple example, we will use the MainWindow itself. This is pretty much easier at this point and it won&#8217;t push you too far away from the actual topic. Never the less, we still need a bindable property inside our MainWindow, which we are going to create, now.</p>



<h3 class="wp-block-heading">Creating a bindable property</h3>



<p>To create the announced property, just build some normal property inside your MainWindow (for example) called &#8222;MusicArtists&#8220;. This could look like the following code, keep in mind, that we should use something which implements the &#8222;INotifyCollectionChanged&#8220; interface. But yes, I hear you, this should be a topic for another blog post, so just take it like that for now.</p>



<p>Next, create that property called &#8222;MusicArtists&#8220; of type of &#8222;ObservableCollection&#8220;, with the generic type argument &#8222;MusicArtist&#8220;. We could also just make it like readonly, but those are fine tuning things, which aren&#8217;t necessary right now.</p>



<p>The last important step is, to say: &#8222;Hey, MainWindow, your DataContext is actually.. you!&#8220;. Then the MainWindow will know where to find the corresponding &#8222;MusicArtists&#8220;, which we are going to bind very soon from the XAML side. Take a look at the following example XAML code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainWindow.xaml.cs" data-enlighter-group="datasource-init">using System;
using System.Collections.ObjectModel;
using System.Windows;
using WpfListViewExampleCs.Models;

namespace WpfListViewExampleCs;

/// &lt;summary>
/// Interaction logic for MainWindow.xaml
/// &lt;/summary>
public partial class MainWindow : Window
{

    public ObservableCollection&lt;MusicArtist> MusicArtists { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        MusicArtists = new ObservableCollection&lt;MusicArtist>();
        DataContext = this;
    }
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainWindow.xaml.vb" data-enlighter-group="datasource-init">Imports System
Imports System.Collections.ObjectModel
Imports System.Windows
Imports WpfListViewExampleCs.Models

Namespace WpfListViewExampleCs

    Public Partial Class MainWindow
        Inherits Window

        Public Property MusicArtists As ObservableCollection(Of MusicArtist)

        Public Sub New()
            InitializeComponent()
            MusicArtists = New ObservableCollection(Of MusicArtist)()
            DataContext = Me
        End Sub

    End Class

End Namespace</pre>



<h3 class="wp-block-heading">Filling up some data</h3>



<p>Currently, the ListView wouldn&#8217;t be able to display much, because there just aren&#8217;t no items inside the &#8222;MusicArtists&#8220;, yet. So in the next step we are going to fill up some items, to make the ListView be able to display those. This is the reason, why we added a quick constructor inside the &#8222;MusicArtist&#8220; class: Creating quick example artists.</p>



<p>Let&#8217;s re-create the MainWindow constructor for this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainWindow.xaml.cs" data-enlighter-group="filling-data">// rest of the MainWindow code behind file

    public MainWindow()
    {
        InitializeComponent();
        MusicArtists = new ObservableCollection&lt;MusicArtist>();
        MusicArtists.Add(new MusicArtist("Jimmy", "Hendrix", new DateTime(1942, 11, 27)));
        MusicArtists.Add(new MusicArtist("Michael", "Jackson", new DateTime(1958, 8, 29)));
        MusicArtists.Add(new MusicArtist("The", "Beatles", new DateTime(1960, 1, 1)));
        DataContext = this;
    }

// rest of the MainWindow code behind file</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainWindow.xaml.vb" data-enlighter-group="filling-data">' rest of the MainWindow code behind file

Public Sub New()
    InitializeComponent()
    MusicArtists = New ObservableCollection(Of MusicArtist)()
    MusicArtists.Add(New MusicArtist("Jimmy", "Hendrix", New DateTime(1942, 11, 27)))
    MusicArtists.Add(New MusicArtist("Michael", "Jackson", New DateTime(1958, 8, 29)))
    MusicArtists.Add(New MusicArtist("The", "Beatles", New DateTime(1960, 1, 1)))
    DataContext = Me
End Sub

' rest of the MainWindow code behind file</pre>



<h3 class="wp-block-heading">But it&#8217;s displaying rubbish now?</h3>



<p>If you are looking at the current results, you would pretty much only see rubbish. If you didn&#8217;t look until now, please watch the following screenshot, then you probably will. The items are more or less being displayed, but there&#8217;s only something like &#8222;Blabla.Bla.MusicArtist&#8220; written.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Bound-ListView-Items-without-Column-Bindings-1.png"><img loading="lazy" decoding="async" width="454" height="178" src="https://robbelroot.de/wp-content/uploads/2023/01/Bound-ListView-Items-without-Column-Bindings-1.png" alt="Bound ListView Items displaying rubbish without Column Bindings" class="wp-image-14159" title="Bound ListView Items displaying rubbish without Column Bindings"/></a><figcaption class="wp-element-caption">Bound ListView Items displaying rubbish without Column Bindings</figcaption></figure>



<p>The reason for that is, that the corresponding ListViewItem actually knows: &#8222;Hey, there is something called MusicArtist&#8220;. But it&#8217;s also asking itself: &#8222;well, how am I supposed to display this? Property A, B, C, WHAT!?&#8220;. In the end it thinks: &#8222;You know what, dev? I&#8217;m just going to display THAT over here&#8220;.</p>



<p>By &#8222;that&#8220; I&#8217;m meaning the complete path to the corresponding class instance type. We are having a class called &#8222;MusicArtist&#8220; inside our project called &#8222;WpfListViewExampleCs&#8220; AND inside the &#8222;Models&#8220; namespace. So this is basically why that &#8222;rubbish&#8220; comes out of it, it displays the complete namespace to class path!</p>



<h3 class="wp-block-heading">Overriding that &#8222;default-rubbish&#8220;</h3>



<p>Before we are going to use the final solution for this, I first want to explain and show you, how you could potentially solve it at this point. Please keep in mind, that this solution depends on your usecase! Usually, if you want to display like &#8222;multiple columns&#8220;, you would actually need – well – multiple columns.</p>



<p>In the image from above, you are seeing the <strong><a href="https://learn.microsoft.com/en-us/dotnet/api/system.object.tostring?view=net-9.0" target="_blank" rel="noreferrer noopener">default object class &#8222;ToString&#8220;</a></strong> output. To change it, you can just override it in your derived class – being the &#8222;MusicArtist&#8220;-class like in a second. Hint: I&#8217;m using the newer, shorter version of the overriding functionality. This means, no body parantheses and an arrow (for C#), as well as string interpolation (for both languages).</p>



<p>You could add this to the &#8222;MusicArtist&#8220; class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MusicArtist.cs" data-enlighter-group="override-musicartist-tostring">// rest of the MusicArtist class

public override string ToString()
    => $"{FirstName} {LastName}";

// rest of the MusicArtist class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MusicArtist.vb" data-enlighter-group="override-musicartist-tostring">' rest of the MusicArtist class

Public Overrides Function ToString() As String
    Return $"{FirstName} {LastName}"
End Function

' rest of the MusicArtist class</pre>



<p>So the current / new output would look like this:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Bound-ListView-Items-with-overriden-ToString-Function.png"><img loading="lazy" decoding="async" width="354" height="210" src="https://robbelroot.de/wp-content/uploads/2023/01/Bound-ListView-Items-with-overriden-ToString-Function.png" alt="Bound ListView Items with overriden ToString Function" class="wp-image-14168" title="Bound ListView Items with overriden ToString Function"/></a><figcaption class="wp-element-caption">Bound ListView Items with overriden ToString Function</figcaption></figure>



<h2 class="wp-block-heading">Using the ListViews &#8222;View&#8220; Property creating columns</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Creating-columns-using-the-ListView-View-Property-640px.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/01/Creating-columns-using-the-ListView-View-Property-640px.png" alt="Creating columns using the ListView View Property" class="wp-image-14218" title="Creating columns using the ListView View Property"/></a><figcaption class="wp-element-caption">Creating columns using the ListView View Property</figcaption></figure>



<p>After cleaning up that &#8222;namespace and class&#8220;-mess we saw in the last section, we now can go the last step (I think). Currently, our ListView is only displaying some kind of single dimensioned data, which is not thaaaat bad, but I guess bad for multi-dimensioned data? What if I wanted to have some sort of separated columns for first and last name? This is exactly, where the so called &#8222;View&#8220;-property of the WPF ListView comes into play!</p>



<h3 class="wp-block-heading">But why a ListView, why no DataGrid instead?</h3>



<p>Sure, you could ask yourself: &#8222;Why would I use a ListView, when I could use a DataGrid instead?&#8220;. The answer is: &#8222;It depends&#8220;, yeah, I hate those answers as well.. Usually there&#8217;s one rule floating around in the internet: Use a DataGrid, if you need editing, use a ListView otherwise – bang. I would pretty much love going deeper into this topic, but well, I think this post is already too big, isn&#8217;t it?</p>



<h3 class="wp-block-heading">Specifying a &#8222;View&#8220;-template</h3>



<p>To start creating those columns we talked about, we need to specify some sort of template for the View property. But it&#8217;s not a usual &#8222;DataTemplate&#8220;, it&#8217;s something more special, lemme give you an example. The basic view provided from WPF itself, is something called a &#8222;GridView&#8220;. I mean, the name pretty much suggests what it is. If needed, you could create something similiar for your own needs, but again, I think this would blow up this post even more..</p>



<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">
    <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Need a WPF developer?</div>
    <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Got a WPF project that needs professional hands?</p>
    <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">I build WPF applications with clean MVVM architecture in C# and VB.NET — professionally and efficiently. Just send me a message.</p>
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">
      <a href="https://robbelroot.de/contact/" style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;white-space:nowrap;" onmouseover="this.style.background='#cf6d17'" onmouseout="this.style.background='#e67e22'">→ Get in touch</a>
    </div>
  </div>
</div>



<p>So let&#8217;s stick with the basic GridView for now. Back into your MVVM prepared ListView, we can now provide a GridView template for our ListView. Watch out for that nice string format functionality, where I specified a custom format for that birthday binding. Basically all you have to do is, providing the columns you want, with a header of your choice. Then you need to tell the ListViewItem, where it should pull the data from (being the DisplayMemberPath-Binding).</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">            &lt;ListView ItemsSource="{Binding MusicArtists}">
                &lt;ListView.View>
                    &lt;GridView>
                        &lt;GridView.Columns>
                            &lt;GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding FirstName}" />
                            &lt;GridViewColumn Header="LastName" DisplayMemberBinding="{Binding LastName}" />
                            &lt;GridViewColumn Header="Birthday" DisplayMemberBinding="{Binding Birthday, StringFormat={}{0:dd.MM.yyyy}}" />
                        &lt;/GridView.Columns>
                    &lt;/GridView>
                &lt;/ListView.View>
            &lt;/ListView></pre>



<p>And finally, you end up having this nice thing here:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-with-specified-View-Property-as-GridView.png"><img loading="lazy" decoding="async" width="505" height="268" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-with-specified-View-Property-as-GridView.png" alt="WPF ListView with specified View Property as GridView" class="wp-image-14226" title="WPF ListView with specified View Property as GridView"/></a><figcaption class="wp-element-caption">WPF ListView with specified View Property as GridView</figcaption></figure>



<h3 class="wp-block-heading">Adding, removing, etc. the MVVM way – preparations</h3>



<p>Because it&#8217;s a bit harder, I saved this topic (and other) for the end of this blog post. You actually need some sort of &#8222;ICommand&#8220; implementation, which we won&#8217;t cover here, but I will give you the example code needed. There will be another blog post about those commands in english, currently, it&#8217;s only available in german, sorry.</p>



<h3 class="wp-block-heading">A DelegateCommand base class</h3>



<p>Please go ahead and <strong>create another folder inside your project</strong>, called &#8222;<strong>Utils</strong>&#8222;. We will deposit a small class over there, which helps us with the buttons in MVVM style. The class I&#8217;m talking about looks like this, it&#8217;s a basic implementation of a delegated action (with check) for the <strong><a href="https://learn.microsoft.com/en-US/dotnet/api/system.windows.input.icommand?view=net-9.0" target="_blank" rel="noreferrer noopener">ICommand-interface</a></strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.cs" data-enlighter-group="delegate-command">using System.Windows.Input;
using System;

namespace Utils
{
    public class DelegateCommand : ICommand
    {
        private Action&lt;object?> _action;

        private Func&lt;object?, bool>? _canExecute;

        public DelegateCommand(Action&lt;object?> action)
        {
            _action = action;
        }

        public DelegateCommand(Action&lt;object?> action, Func&lt;object?, bool> canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        public void Execute(object? parameter)
        {
            _action(parameter);
        }

        public bool CanExecute(object? parameter)
        {
            if (_canExecute == null)
                return true;
            return _canExecute(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, EventArgs.Empty);
        }

        public event EventHandler? CanExecuteChanged;
    }
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.vb" data-enlighter-group="delegate-command">Namespace Utils
    Public Class DelegateCommand
        Implements ICommand
        Private _action As Action(Of Object)
        Private _canExecute As Func(Of Object, Boolean)
        Sub New(action As Action(Of Object))
            _action = action
        End Sub
        Sub New(action As Action(Of Object), canExecute As Func(Of Object, Boolean))
            _action = action
            _canExecute = canExecute
        End Sub
        Public Sub Execute(parameter As Object) Implements ICommand.Execute
            ' führt unsere von außen mitgegebene Aktion aus und übergibt auch den Parameter
            _action(parameter)
        End Sub
        Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            If _canExecute Is Nothing Then
                Return True
            End If
            Return _canExecute(parameter)
        End Function
        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
    End Class
End Namespace</pre>



<h3 class="wp-block-heading">A PropertyChangedBase class</h3>



<p>Without going into too much detail, please copy this class and put it into the &#8222;Utils&#8220; folder as well. There is <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/" target="_blank" rel="noreferrer noopener">a blog post for the INotifyPropertyChanged-interface</a></strong>, but <strong>currently it&#8217;s only in german</strong>. Maybe you could use a browser-translator for now, but I will add the english version soon. So now, please take this class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="PropertyChangedBase.cs" data-enlighter-group="property-changed-base">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;
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="PropertyChangedBase.vb" data-enlighter-group="property-changed-base">Imports System.ComponentModel
Imports System.Runtime.CompilerServices

Namespace Utils

    Public Class PropertyChangedBase
        Implements INotifyPropertyChanged

        Protected Sub NotifyOfPropertyChange(&lt;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</pre>



<h3 class="wp-block-heading">Corresponding buttons</h3>



<p>Please add something like a StackPanel and 3 Buttons inside of it. There will be one button for adding and one for removing an item at a specific position. The third button will be for removing the selected item. At this point, we will also those commands, please have a look at the following XAML. Please pardon me for not making this visually appealing, it&#8217;s only for its functional purpose.</p>



<p>Keep in mind, that you also need to create 3 new properties of type of &#8222;DelegateCommand&#8220;, 1 for each command, being:</p>



<ul class="wp-block-list">
<li>AddItemCommand</li>



<li>RemoveItemCommand</li>



<li>RemoveItemAtIndexCommand</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        &lt;GroupBox Header="Music stars" Padding="8" Width="400" VerticalAlignment="Center" HorizontalAlignment="Center">
            &lt;StackPanel>
                &lt;ListView SelectedItem="{Binding SelectedMusicArtist}" ItemsSource="{Binding MusicArtists}">
                    &lt;ListView.View>
                        &lt;GridView>
                            &lt;GridView.Columns>
                                &lt;GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding FirstName}" />
                                &lt;GridViewColumn Header="LastName" DisplayMemberBinding="{Binding LastName}" />
                                &lt;GridViewColumn Header="Birthday" DisplayMemberBinding="{Binding Birthday, StringFormat={}{0:dd.MM.yyyy}}" />
                            &lt;/GridView.Columns>
                        &lt;/GridView>
                    &lt;/ListView.View>
                &lt;/ListView>
                &lt;StackPanel Orientation="Horizontal" Margin="0 12 0 0" HorizontalAlignment="Right">
                    &lt;Button Command="{Binding AddItemCommand}" Content="Add item" Margin="0 0 8 0" />
                    &lt;Button Command="{Binding RemoveItemCommand}" Content="Remove item" Margin="0 0 8 0" />
                    &lt;Button Command="{Binding RemoveItemAtIndexCommand}" Content="Remove item at index" />
                &lt;/StackPanel>
            &lt;/StackPanel>
        &lt;/GroupBox></pre>



<p>The &#8222;new&#8220; UI now looks like this:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-MVVM-based-UI-1.png"><img loading="lazy" decoding="async" width="477" height="250" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-ListView-MVVM-based-UI-1.png" alt="MVVM based UI" class="wp-image-14269" title="MVVM based UI"/></a><figcaption class="wp-element-caption">MVVM based UI</figcaption></figure>



<h3 class="wp-block-heading">The MainViewModel</h3>



<p>Now create a new folder called &#8222;ViewModels&#8220; and a &#8222;MainViewModel&#8220; class inside. Let the &#8222;MainViewModel&#8220; class inherit from the &#8222;PropertyChangedBase&#8220; you copied from the previous paragraph. The view (code behind) file should now be abandoned as it&#8217;s getting too much otherwise.</p>



<p>Over here we fully implemented the &#8222;SelectedMusicArtist&#8220;-property to actually tell the &#8222;RemoveItemCommand&#8220;: &#8222;Hey, here was something selected, check if you can be executed now&#8220;. We&#8217;re  subscribing to the &#8222;CollectionChanged&#8220; event of the ObservableCollection as well. This way, we can also refresh the commands state, when the collection is changed.</p>



<p>In the next steps, we are going to instantiate the commands and therefore telling them, what to do and when.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="the-main-view-model">using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Utils;
using WpfListViewExampleCs.Models;

namespace WpfListViewExampleCs.ViewModels;

public class MainViewModel : PropertyChangedBase
{

    public ObservableCollection&lt;MusicArtist> MusicArtists { get; set; }

    private MusicArtist? _selectedMusicArtist;

    public MusicArtist? SelectedMusicArtist
    {
        get => _selectedMusicArtist;
        set
        {
            if (_selectedMusicArtist == value)
                return;
            _selectedMusicArtist = value;
            RemoveItemCommand.RaiseCanExecuteChanged();
        }
    }

    public DelegateCommand AddItemCommand { get; set; }

    public DelegateCommand RemoveItemCommand { get; set; }

    public DelegateCommand RemoveItemAtIndexCommand { get; set; }

    public MainViewModel()
    {
        MusicArtists = new ObservableCollection&lt;MusicArtist>();
        MusicArtists.CollectionChanged += MusicArtists_CollectionChanged;
        MusicArtists.Add(new MusicArtist("Jimmy", "Hendrix", new DateTime(1942, 11, 27)));
        MusicArtists.Add(new MusicArtist("Michael", "Jackson", new DateTime(1958, 8, 29)));
        MusicArtists.Add(new MusicArtist("The", "Beatles", new DateTime(1960, 1, 1)));
    }

    private void MusicArtists_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
    {
        RemoveItemCommand.RaiseCanExecuteChanged();
        RemoveItemAtIndexCommand.RaiseCanExecuteChanged();
    }

}
</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainWindow.xaml.vb" data-enlighter-group="the-main-view-model">Imports System
Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
Imports Utils
Imports WpfListViewExampleCs.Models

Namespace WpfListViewExampleCs.ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        Public Property MusicArtists As ObservableCollection(Of MusicArtist)

        Private _selectedMusicArtist As MusicArtist?

        Public Property SelectedMusicArtist As MusicArtist?
            Get
                Return _selectedMusicArtist
            End Get
            Set(ByVal value As MusicArtist?)
                If _selectedMusicArtist = value Then Return
                _selectedMusicArtist = value
                RemoveItemCommand.RaiseCanExecuteChanged()
            End Set
        End Property

        Public Property AddItemCommand As DelegateCommand

        Public Property RemoveItemCommand As DelegateCommand

        Public Property RemoveItemAtIndexCommand As DelegateCommand

        Public Sub New()
            MusicArtists = New ObservableCollection(Of MusicArtist)()
            AddHandler MusicArtists.CollectionChanged, AddressOf MusicArtists_CollectionChanged
            MusicArtists.Add(New MusicArtist("Jimmy", "Hendrix", New DateTime(1942, 11, 27)))
            MusicArtists.Add(New MusicArtist("Michael", "Jackson", New DateTime(1958, 8, 29)))
            MusicArtists.Add(New MusicArtist("The", "Beatles", New DateTime(1960, 1, 1)))
        End Sub

        Private Sub MusicArtists_CollectionChanged(ByVal sender As Object?, ByVal e As NotifyCollectionChangedEventArgs)
            RemoveItemCommand.RaiseCanExecuteChanged()
            RemoveItemAtIndexCommand.RaiseCanExecuteChanged()
        End Sub

    End Class

End Namespace</pre>



<h3 class="wp-block-heading">Modern alternative (.NET 6+): CommunityToolkit.Mvvm</h3>



<p>Writing <code>DelegateCommand</code> and <code>PropertyChangedBase</code> manually works perfectly fine &#x1f449; and understanding how they work is exactly why we did it this way. But in 2026, you would typically reach for the <strong><a href="https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/" target="_blank" rel="noreferrer noopener">CommunityToolkit.Mvvm</a></strong> NuGet package instead.</p>



<p>It ships source generators like <code>[ObservableProperty]</code> and <code>[RelayCommand]</code>, which produce the same boilerplate automatically at compile time, meaning less code to write and maintain.</p>



<p>Compare the two approaches with these small code snippets:</p>



<p>&#x274c; Manual (what we did above)</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private MusicArtist? _selectedMusicArtist;
public MusicArtist? SelectedMusicArtist {
    get => _selectedMusicArtist;
    set { _selectedMusicArtist = value; NotifyOfPropertyChange(); }
}</pre>



<p>&#x2705; CommunityToolkit.Mvvm</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[ObservableProperty]
private MusicArtist? _selectedMusicArtist;</pre>



<p>Well worth a look once you are comfortable with the concepts above!</p>



<h3 class="wp-block-heading">Assign a ViewModel to the MainWindow</h3>



<p>To be able to this all work, make sure, you set an appropriate ViewModel for your MainWindow. Otherwise, the binding system wouldn&#8217;t know, where to search for your bindings. This is done by adding this code to your MainWindow XAML file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- create a namespace mapping at the top of your file -->
xmlns:vm="clr-namespace:WpfListViewExampleCs.ViewModels"

&lt;!-- Set the DataContext MainViewModel instance by XAML -->
&lt;Window.DataContext>
    &lt;vm:MainViewModel />
&lt;/Window.DataContext></pre>



<h3 class="wp-block-heading">How to add WPF ListView items with MVVM</h3>



<p>After you got our little helper class from above inside your &#8222;Utils&#8220; folder and everything else ready, we can now continue. Adding items is now kinda different, because our items are actually bound and not just simple strings. Our commands wants at least to know, what it should do, when executed. We can pass a function, to let the command determine, if it can be executed. I mean, we don&#8217;t want a &#8222;remove selected item&#8220; to happen, when there&#8217;s no item, right?</p>



<p>The following code is needed for the actual functionality: Instantiate the command inside the constructor (don&#8217;t forget to take the command property from above!).</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="main-view-model-add-item">    // other properties

    public DelegateCommand AddItemCommand { get; set; }

    public MainViewModel()
    {
        AddItemCommand = new DelegateCommand(AddItem);

        // list instantiation etc..
    }

    // the delegate function to be executed on click
    private void AddItem(object? parameter)
    {
        // adding miley cyrus, as we have no dynamic dialog, as it's not a part of this here..
        MusicArtists.Add(new MusicArtist("Miley", "Cyrus", new DateTime(1992, 11, 23)));
    }</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="main-view-model-add-item">    ' other properties
   
    Public Property AddItemCommand As DelegateCommand

    Sub New()
        AddItemCommand = new DelegateCommand(AddItem);

        ' list instantiation etc..
    End Sub

    Private Sub AddItem(parameter As Object)
        MusicArtists.Add(New MusicArtist("Miley", "Cyrus", New DateTime(1992, 11, 23)))
    End Sub</pre>



<h3 class="wp-block-heading">Removing the selected item MVVM style</h3>



<p>The important thing here is, that we can only remove a selected item, if there is actually one selected. Please check the &#8222;SelectedMusicArtist&#8220;-property from the above MainViewModel for this. If the selected item (therefore the SelectedMusicArtist) changes, we tell the command to refresh.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="main-view-model-remove-item">    // other properties

    public DelegateCommand RemoveItemCommand { get; set; }

    public MainViewModel()
    {
        RemoveItemCommand = new DelegateCommand(RemoveItem, CanRemoveItem);

        // list instantiation etc..
    }

    private void RemoveItem(object? parameter)
    {
        // we should know that SelectedMusicArtist isn't null, therefore the !
        MusicArtists.Remove(SelectedMusicArtist!);
    }

    private bool CanRemoveItem(object? parameter)
    {
        return SelectedMusicArtist != null;
    }</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="main-view-model-remove-item">    ' other properties
   
    Public Property RemoveItemCommand As DelegateCommand

    Sub New()
        RemoveItemCommand = new DelegateCommand(RemoveItem, CanRemoveItem);

        ' list instantiation etc..
    End Sub

    Private Sub RemoveItem(parameter As Object)
        MusicArtists.Remove(SelectedMusicArtist)
    End Sub

    Private Function CanRemoveItem(parameter As Object) As Boolean
        Return SelectedMusicArtist IsNot Nothing
    End Function</pre>



<h3 class="wp-block-heading">Deleting an item by index, MVVM like</h3>



<p>In the last example, we do pretty much the same, but with some hardcoded index, just as an example!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="main-view-model-remove-item-index">    // other properties

    public DelegateCommand RemoveItemAtIndexCommand { get; set; }

    public MainViewModel()
    {
        RemoveItemAtIndexCommand = new DelegateCommand(RemoveItemAtIndex, CanRemoveItemAtIndex);

        // list instantiation etc..
    }

    private void RemoveItemAtIndex(object? parameter)
    {
        // we need at least one item inside
        MusicArtists.RemoveAt(0);
    }

    private bool CanRemoveItemAtIndex(object? parameter)
    {
        return MusicArtists.Count > 0;
    }</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="main-view-model-remove-item-index">    ' other properties
   
    Public Property RemoveItemAtIndexCommand As DelegateCommand

    Sub New()
        RemoveItemAtIndexCommand = new DelegateCommand(RemoveItemAtIndex, CanRemoveItemAtIndex);

        ' list instantiation etc..
    End Sub

    Private Sub RemoveItemAtIndex(parameter As Object)
        MusicArtists.RemoveAt(0)
    End Sub

    Private Function CanRemoveItemAtIndex(parameter As Object) As Boolean
        MusicArtists.Count > 0
    End Function</pre>



<h2 class="wp-block-heading">Conclusion – WPF ListView Control</h2>



<p>If you want to have a control, which is able to display things in like a list, being able to select one or more items out of it, the ListView is possibly your choice. When thinking about: &#8222;Should I use a ListView or a DataGrid&#8220;, you should choose the ListView, if editing is not a concern. As mostly always, you have the option to go for the code behind, or the MVVM approach, I would personally always choose the MVVM one. It seems much cleaner for my personal preferences and doesn&#8217;t mix up UI with business code. Feel free to leave any comment on how to improve this article, or if I may explained something wrong.</p>



<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">
    <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Need a WPF developer?</div>
    <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Got a WPF project that needs professional hands?</p>
    <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">I build WPF applications with clean MVVM architecture in C# and VB.NET — professionally and efficiently. Just send me a message.</p>
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">
      <a href="https://robbelroot.de/contact/" style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;white-space:nowrap;" onmouseover="this.style.background='#cf6d17'" onmouseout="this.style.background='#e67e22'">→ Get in touch</a>
    </div>
  </div>
</div>



<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-question-1774441748497"><strong class="schema-faq-question">What is the difference between a WPF ListView and a DataGrid?</strong> <p class="schema-faq-answer">A ListView is best for displaying read-only data in list or grid format, while a DataGrid supports inline editing, sorting, and cell-level interaction. Use a ListView when you only need to display and select items, use a DataGrid when users need to edit data directly in the table.</p> </div> <div class="schema-faq-section" id="faq-question-1774441768936"><strong class="schema-faq-question">How do I add columns to a WPF ListView?</strong> <p class="schema-faq-answer">Set the ListView&#8217;s View property to a GridView, then define GridViewColumn elements with Header and DisplayMemberBinding. Each column binds to a property of your data model, allowing multi-column display.</p> </div> <div class="schema-faq-section" id="faq-question-1774441780175"><strong class="schema-faq-question">Can I use the WPF ListView with MVVM and data binding?</strong> <p class="schema-faq-answer">Yes, bind the ItemsSource property to an ObservableCollection in your ViewModel. Use ICommand implementations (like DelegateCommand or RelayCommand) for add/remove operations, and bind SelectedItem for selection tracking.</p> </div> </div>



<h2 class="wp-block-heading">Downloads</h2>



<p>If you need quick and ready to use examples, just go ahead and download the ones you need. Maybe I&#8217;ll add some more later.</p>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/file-download/?dlid=6a6afb78-5d9f-4104-98af-8b46cdb3b68a" target="_blank" rel="noreferrer noopener">WpfListViewExampleCs.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/file-download/?dlid=eae7bc5f-d92c-4b01-b60d-c4e4e362e055" target="_blank" rel="noreferrer noopener">WpfListViewExampleCsMvvm.zip</a></div>
</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/the-wpf-listview-control-the-complete-guide/">The WPF ListView Control – the complete Guide in 2026</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/the-wpf-listview-control-the-complete-guide/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Eigene WPF Commands in MVVM VB.NET &#038; C# &#8211; der 2024 Guide</title>
		<link>https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/</link>
					<comments>https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sat, 07 Jan 2023 11:32:01 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[C# (C Sharp)]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[ausführen]]></category>
		<category><![CDATA[befehle]]></category>
		<category><![CDATA[bindung]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[command]]></category>
		<category><![CDATA[commandparameter]]></category>
		<category><![CDATA[commands]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[datenbindung]]></category>
		<category><![CDATA[handler]]></category>
		<category><![CDATA[klick]]></category>
		<category><![CDATA[knopf]]></category>
		<category><![CDATA[knöpfe]]></category>
		<category><![CDATA[modern]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[parameter]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=13398</guid>

					<description><![CDATA[<p>Nutze WPF Commands, vermeide &#8222;Button1_Click&#8220; &#38; Co. Im heutigen Beitrag schauen wir uns das Thema &#8222;eigene WPF Commands&#8220;, bzw. die passende Schnittstelle &#8222;ICommand&#8220; an. Damit werden wir der besonders aus Winforms-Zeiten (Windows Forms) bekannten Vermischung von Design und Quellcode entfliehen. Dazu schauen wir uns erst die Basis der &#8222;ICommand&#8220;-Schnittstelle an &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/">Eigene WPF Commands in MVVM VB.NET &#038; C# &#8211; der 2024 Guide</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Eigene-Commands-in-VB.NET-WPF-MVVM-mit-PasswordBox-Tricks-und-Co.-Guide-Thumbnail.png"><img loading="lazy" decoding="async" width="1280" height="720" src="https://robbelroot.de/wp-content/uploads/2023/01/Eigene-Commands-in-VB.NET-WPF-MVVM-mit-PasswordBox-Tricks-und-Co.-Guide-Thumbnail.png" alt="Eigene Commands in VB.NET WPF MVVM mit PasswordBox, Tricks und Co. - Guide" class="wp-image-13403" title="Eigene Commands in VB.NET WPF MVVM mit PasswordBox, Tricks und Co. - Guide"/></a><figcaption class="wp-element-caption">Eigene Commands in VB.NET WPF MVVM mit PasswordBox, Tricks und Co. &#8211; Guide</figcaption></figure>






<h2 class="wp-block-heading">Nutze WPF Commands, vermeide &#8222;Button1_Click&#8220; &amp; Co.</h2>



<p>Im heutigen Beitrag schauen wir uns das Thema &#8222;eigene WPF Commands&#8220;, bzw. die passende Schnittstelle &#8222;ICommand&#8220; an. Damit werden wir der besonders aus Winforms-Zeiten (Windows Forms) bekannten Vermischung von Design und Quellcode entfliehen. Dazu schauen wir uns erst die Basis der &#8222;ICommand&#8220;-Schnittstelle an und erstellen auch anschließend eine wiederverwendbare Klasse – wir haben schließlich keinen Bock, alles 10x zu schreiben! Um alles zu verstehen, geht es hier und da natürlich noch einmal Richtung Details, aber gut, so viel Zeit muss sein, wenn man nicht nur &#8222;Copy &amp; Paste&#8220;-Master sein möchte :)!</p>



<p class="info-banner"><strong>&#x1f4a1;</strong> <strong>Hinweis</strong>: Nutze gerne <strong><a href="#toc_container">das Inhaltsverzeichnis</a></strong>, um an passende Stellen zu springen, da es sich hierbei um ein ausführliches Thema handelt, Welches man nicht &#8222;mal eben&#8220; besprechen kann. Falls Du z. B. nur <strong><a href="#finale-delcommand-basisklasse">eine wiederverwendbare Command-Basisklasse</a></strong> benötigst, findest Du Diese weiter unten. Vielleicht möchtest Du auch einen Blick auf <strong><a href="#downloads">die Downloads-Sektion</a></strong> werfen?</p>



<style>
.info-banner {
    background: #03a9f4;
    padding: 2em;
    border-radius: 0.5em;
    color: whitesmoke;
}
.info-banner a {
    color: #FED766;
}
</style>



<p>In diesem Beitrag werden wir synchrone Commands besprechen, die asynchrone Variante werden wir im Detail, in einem der nächsten Beiträge angehen. Ebenso wird das Thema &#8222;Login&#8220; nur als Beispiel thematisiert und nicht vollständig realisiert. Allgemein möchte ich erreichen, dass Du hier rausgehen und &#8222;Nice, ich habe Commands verstanden&#8220; sagen kannst :)!</p>



<h2 class="wp-block-heading">Kurzfassung – .NET WPF Commands in MVVM</h2>



<p>Wenn Du es eilig hast, hier die <strong>Kurzfassung</strong> über .NET MVVM Commands in WPF:</p>



<ul class="wp-block-list">
<li><strong>Ersetze </strong>z. B. die typischen Click-<strong>Handler </strong>von Buttons <strong>durch </strong>passende Datenbindungen an sogenannte <strong>Commands</strong>. Beachte jedoch, dass Commands nicht nur von Buttons, sondern z. B. auch von Kontextmenüs unterstützt werden!</li>



<li>Dazu musst Du Deinem <strong>View </strong>in erster Linie einen <strong>Datenkontext geben</strong>, damit es weiß, <strong>woher </strong>es die &#8222;<strong>Dinge</strong>&#8220; durch Datenbindung <strong>bekommen </strong>kann.</li>



<li><strong>Sage </strong>in Deinem <strong>Button</strong>-XAML dann via <strong>Command-Eigenschafts-Bindung</strong>, dass Du das &#8222;<strong>LoginCommand</strong>&#8220; <strong>verwenden </strong>möchtest &#8211; voilà!</li>



<li><strong>Implementiere </strong>im nächsten Schritt die &#8222;<strong>ICommand</strong>&#8222;-Schnittstelle und <strong>erstelle </strong>danach in Deinem Datenkontext eine passende, bindbare <strong>Eigenschaft</strong>, z. B. &#8222;<strong>LoginCommand</strong>&#8220; zur Verfügung.</li>



<li><strong>Instanziiere </strong>die <strong>Command</strong>-basierte Eigenschaft nun z. B. <strong>in </strong>Deinem <strong>ViewModel</strong>&#8211;<strong>Konstruktor</strong>.</li>



<li><strong>Übergib</strong> manuelle oder gebundene <strong>Parameter</strong>, indem Du <strong>an </strong>die <strong>CommandParameter</strong>&#8211;<strong>Eigenschaft </strong>des (z. B.) Buttons bindest.</li>
</ul>



<p>Damit Du die Implementierung allerdings nicht hunderte Male und für z. B. jeden Knopf wiederholen musst, würde ich Dir eine Abstraktion durch eine Basisklasse vorschlagen. Eine derartige Klasse (für VB.NET &amp; C#) findest Du natürlich auch hier im Beitrag. Scrolle dazu einfach zu &#8222;<strong><a href="#wiederverwendbare-klasse">eine wiederverwendbare Command-Basisklasse</a></strong>&#8222;, oder direkt zu <strong><a href="#downloads">den Downloads</a></strong>.</p>



<h2 class="wp-block-heading">Beitrag als Video ansehen</h2>



<p>Wenn Du diesen Beitrag lieber im Videoformat genießen möchtest, kannst Du natürlich auch das <strong><a href="https://youtu.be/TZD6259Mma8" target="_blank" rel="noreferrer noopener">folgende Video</a></strong> (vielleicht auch ergänzend) ansehen. Besonders die Hinweise bezüglich der &#8222;PasswordBox&#8220; sind sehr wichtig!</p>


<div class="async-youtube" data-embed="TZD6259Mma8" data-alt="">
    <div class="play-button"></div>      
  </div>



<h2 class="wp-block-heading" id="projekt-und-ordnerstruktur">Projekt- und Ordnerstruktur</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Projekt-und-Ordnerstruktur-–-VB.NET-WPF-Commands-in-MVVM_640px.png"><img loading="lazy" decoding="async" width="640" height="427" src="https://robbelroot.de/wp-content/uploads/2023/01/Projekt-und-Ordnerstruktur-–-VB.NET-WPF-Commands-in-MVVM_640px.png" alt="Projekt- und Ordnerstruktur – VB.NET WPF Commands in MVVM" class="wp-image-13421" title="Projekt- und Ordnerstruktur – VB.NET WPF Commands in MVVM"/></a><figcaption class="wp-element-caption">Projekt- und Ordnerstruktur – VB.NET WPF Commands in MVVM</figcaption></figure>



<p>Bevor wir mit dem eigentlichen Thema &#8222;WPF Commands in MVVM&#8220; loslegen können, legen wir uns als Erstes unsere Projektstruktur zurecht. Eine vernünftige Ordner- und Organisationsstruktur ist natürlich nicht nur nützlich, wenn man allein arbeitet, um z. B. immer in den gewohnten Ablauf hineinzukommen. Es hilft uns zusätzlich auch dabei, falls wir mal etwas outsourcen, bzw. jemanden um Hilfe bitten müssen – und das kommt häufig schneller vor, als man denkt! Wer will sich außerdem in seinem eigenen Code immer den Ast absuchen müssen, nur weil es jedes Mal anders aussieht? Keiner!</p>



<p>Natürlich könnte ich jetzt hier auch alles wieder von vorn erzählen, möchte es aber im Sinne des Entwicklers (Don&#8217;t repeat yourself &#8211; wiederhole dich nicht) vermeiden. Schaue Dir den Basis-Projektaufbau daher gerne in meinem Beitrag <strong><a href="https://robbelroot.de/blog/ein-wpf-mvvm-projekt-aufsetzen-guide/" target="_blank" rel="noreferrer noopener">&#8222;Wie setzt man ein VB.NET, bzw. WPF MVVM-Projekt auf&#8220;</a></strong> an.</p>



<h2 class="wp-block-heading">Die Rollenverteilung in .NET WPF MVVM</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/07/MVVM-getrennte-Entwickler-Designer-Rollen.gif"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/07/MVVM-getrennte-Entwickler-Designer-Rollen.gif" alt="Trennung von Designern und Entwicklern" class="wp-image-5074"/></a><figcaption class="wp-element-caption">Trennung von Rollen im MVVM-Entwurfsmuster</figcaption></figure>



<p>Da dieser Beitrag die Verwendung von Commands im Fokus hat, verstehe bitte, dass ich nicht zu tief in das &#8222;Model-View-ViewModel&#8220;-Entwurfsmuster selbst abtauchen kann. Allerdings ist für die Verwendung von WPF Commands natürlich ein gewisses Grundverständnis der MVVM-Architektur erforderlich. Besuche für eine erweiterte Erklärung gerne meinen <strong><a href="https://robbelroot.de/blog/mvvm-csharp/" target="_blank" rel="noreferrer noopener">Beitrag zum MVVM-Entwurfsmuster</a></strong>, auch wenn Dieser C#-geprägt ist, sind alle Erkenntnisse natürlich auch bei VB.NET analog.</p>



<p>Grundsätzlich geht es bei dieser Strukturierung von modernen .NET Applikationen (oder auch Applikationen im Allgemeinen) anhand des MVVM-Musters darum, eine saubere Rollentrennung zu erreichen. Insbesondere spricht man hier von der Trennung von Benutzeroberfläche und Geschäftslogik – woran meist verschiedene Personen wie Designer und Entwickler arbeiten. Dies bietet nicht nur die Möglichkeit, sich fast ganz auf seine Rolle konzentrieren zu können, sondern auch ganz andere praktische Vorteile. So erreicht man durch die einfachere Austauschbarkeit von &#8222;Views&#8220; und &#8222;ViewModels&#8220; etwa eine erhöhte Test- und Wartbarkeit seiner Software im Allgemeinen.</p>



<h3 class="wp-block-heading">Das View – die Aufgabe des Designers</h3>



<p>Je nach Herangehensweise (also View-, oder ViewModel-First) geht z. B. der Designer hin und entwirft nach etwaigen Wireframing-Prozessen die gewünschte Oberfläche mit Hilfe der XAML-Auszeichnungssprache. Mit dem Kunden wurden also ggf. vorherige Absprachen (mit Skizzen &#8211; Wireframes) getroffen, Welche das ungefähre Layout und Design zumindest grob bestimmen sollen. Dies kann dann z. B. ohne eine Zeile Code geschrieben zu haben wie gleich folgend aussehen und eine gemeinsame Basis / einen gemeinsamen Konsens bilden. Zugegebenermaßen ist das folgende Beispiel schon eher auf einem &#8222;Non-Plus-Ultra&#8220;-Level, da man – je nach Unternehmensgröße – eher ein &#8222;mach&#8216; Mal&#8220; geliefert bekommt. Aber gut, träumen darf man als Entwickler noch, oder!?</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/MVVM-WPF-XAML-Wireframing-Prozess.png"><img loading="lazy" decoding="async" width="2880" height="1600" src="https://robbelroot.de/wp-content/uploads/2023/01/MVVM-WPF-XAML-Wireframing-Prozess.png" alt="MVVM WPF XAML Wireframing Prozess – Quelle: moqups Wireframing Tool" class="wp-image-13479" title="MVVM WPF XAML Wireframing Prozess"/></a><figcaption class="wp-element-caption">MVVM WPF XAML Wireframing Prozess – Quelle: moqups.com Wireframing Tool</figcaption></figure>



<p>Wenn unsere Wünsche daher also wahr werden, haben die Designer die Möglichkeit, die skizzierten Wünsche des Kunden relativ unabhängig vom Entwickler (-Team) in XAML umsetzen zu können. Ganz im Stil von WPF und Co. verwendet man hier Datenbindungen, also XAML Binding-Anweisungen, wie z. B.:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;TextBox Text="{Binding WelcomeMessage}" /></pre>



<p>Den Designern kann und soll es an dieser Stelle egal sein, wie genau die &#8222;WelcomeMessage&#8220; erschaffen und verändert wird, solange Sie daran binden können &#8211; ergo sich an die WPF-Mechanismen gehalten wird. Viele verkaufen den utopischen Traum des &#8222;Solo-Separat-Entwickelns&#8220; zu gern, allerdings muss natürlich trotzdem Austausch zwischen Entwicklern und Designern stattfinden. Ein &#8222;wir arbeiten vollkommen getrennt voneinander&#8220; ist also nicht zu 100% möglich, ABER eben viel viel einfacher. Die Designer können ja schließlich z. B. auch nicht raten, ob unsere &#8222;IsSelected&#8220;-Eigenschaft nun eben sinnigerweise so, oder &#8222;Selected&#8220; heißt. Je öfter man zusammenarbeitet, desto leichter erschließen sich solche Muster natürlich in Zukunft und man kann immer unabhängiger, gar blind zusammenarbeiten.</p>



<h3 class="wp-block-heading">Der Entwickler, die ViewModels, Geschäftslogik und Co.</h3>



<p>Nachdem wir als Entwickler – im Optimalfall – also nun unsere Wireframes bekommen haben, können nun auch wir ziemlich isoliert / separat tätig werden. Wir entwerfen die passenden ViewModel-Klassen zu den gezeigten Oberflächen, Welche &#8222;INotifyPropertyChanged&#8220; und Co. verwenden, um durch die Datenbindungen zu kommunizieren. Schaue Dir hierzu gerne <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/" target="_blank" rel="noreferrer noopener">meinen Beitrag zum Thema &#8222;INotifyPropertyChanged&#8220;</a></strong> an. Bei Bedarf erschaffen wir Test-ViewModels, Welche wir durch die neue Herangehensweise, ohne Probleme und Aufwand austauschen und testen können.</p>



<p>Wie erwähnt möchte ich den Exkurs in Richtung &#8222;Model-View-ViewModel-Entwurfsmuster&#8220; nicht zu weit treiben, daher gehe ich hier nicht weiter auf z. B. Models ein. Ich denke sowieso, dass das nicht zielführend wäre, denn zu viel Input ist ja auch schlecht, oder? &#8222;Kleine&#8220; Häppchen machen dann schon eher den Appetit :)! </p>



<h2 class="wp-block-heading">Ein kleines Login-Fenster-Beispiel für WPF Commands</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Ein-erstes-eigenes-WPF-Command-in-MVVM.png"><img loading="lazy" decoding="async" width="640" height="423" src="https://robbelroot.de/wp-content/uploads/2023/01/Ein-erstes-eigenes-WPF-Command-in-MVVM.png" alt="Ein erstes, eigenes WPF Command in MVVM" class="wp-image-13507" title="Ein erstes, eigenes WPF Command in MVVM"/></a><figcaption class="wp-element-caption">Ein erstes, eigenes WPF Command in MVVM</figcaption></figure>



<p>Nach dem kleinen Exkurs von oben, schauen wir uns nun die weitere Reise in Richtung Commands an. Dazu bauen wir uns im nächsten Schritt eine kleine Login-Oberfläche (Achtung, billig..), Welche wie gleich folgend aussehen könnte. Hier werden wir auch direkt aus einer Art Designer-Perspektive agieren, also wir arbeiten in erster Linie &#8222;nur&#8220; am XAML-Code selbst.</p>



<p>Wir tun hier einfach mal so, als hätten wir ein passendes Wireframe vom Kunden vorliegen.. Was macht also ggf. in erster Linie eine Login-Oberfläche aus? Naja, wir brauchen:</p>



<ul class="wp-block-list">
<li>Eine Textbox für die Eingabe des Nutzers / E-Mail-Adresse</li>



<li>Ein Label / Textblock für diese Textbox, sonst weiß der Nutzer nicht was das soll</li>



<li>Eine PasswordBox für die Eingabe des Passworts (beachte hier die Hinweise)</li>



<li>Auch hierfür einen Textblock</li>



<li>Einen Button, wie soll der Benutzer sonst &#8222;Login-Versuch durchführen&#8220; triggern</li>



<li>ggf. weiteren Kram, wie &#8222;Passwort vergessen&#8220; &#8211; lassen wir hier aber aus..</li>
</ul>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Login-Fenster-mit-WPF-Commands-in-MVVM.png"><img loading="lazy" decoding="async" width="789" height="446" src="https://robbelroot.de/wp-content/uploads/2023/01/Login-Fenster-mit-WPF-Commands-in-MVVM.png" alt="Login-Fenster mit WPF Commands in MVVM" class="wp-image-13511" title="Login-Fenster mit WPF Commands in MVVM"/></a><figcaption class="wp-element-caption">Login-Fenster mit WPF Commands in MVVM</figcaption></figure>



<p>Bitte bedenke auch an dieser Stelle – wie oben angekündigt –, dass wir hier kein vollständiges Login-Beispiel realisieren können, da der Beitrag auch so schon lang genug wird &#x1f609;! Einen Login werde ich ggf. mal in einem anderen Beitrag separat behandeln und dort dann ausführen.</p>



<h3 class="wp-block-heading">Datenbindungen des Login-Fensters</h3>



<p>Nachdem wir im obigen Schritt die grundsätzlich benötigten Steuerelemente angemerkt haben, brauchen wir – für MVVM selbstverständlich – auch passende Datenbindungen. Ansonsten wüssten weder die Textboxen, woher Sie Ihren Text bekommen, oder gar &#8222;hinschicken&#8220; sollen. Ebenso hätte der Anmelden-Knopf keine Ahnung, was beim Klick passieren soll (Spoiler: Ein Command ausführen).</p>



<p>Der Designer wird an dieser Stelle hier irgendwie vorher (mit Kunden und Entwicklern) besprochen haben, dass es im ViewModel so etwas namens &#8222;User&#8220; geben muss. Dabei handelt es sich genauer genommen um eine String-Eigenschaft, welche den dementsprechenden Text für die Textbox – also den Benutzer – beinhalten muss. Ebenso muss diese Eigenschaft bei Code-technischen Änderungen nach außen kommunizieren, dass Sie sich geändert hat. Dies geht wie vermutlich bekannt über &#8222;INotifyPropertyChanged&#8220;, was hier allerdings nicht weiter Thema sein wird. Hier nochmal erneut der Hinweis auf <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/">meinen &#8222;INotifyPropertyChanged&#8220;-Beitrag mit &#8222;PropertyChanged&#8220;-Basisklasse</a></strong>.</p>



<p>Schaue Dir nun einmal den XAML-Code zum Fenster an, beachte, dass Du die obigen <strong><a href="#projekt-und-ordnerstruktur">&#8222;Projekt- und Ordnerstruktur&#8220;-Schritte</a></strong> korrekt abgeschlossen hast. Ansonsten wirst Du hier vermutlich Probleme mit Namespace und Co. bekommen. Passe ebenfalls auf, dass Du den Projektnamen umbenennen musst, in meinem Beispiel hieß das Projekt &#8222;WpfCommandsVbTutorial&#8220;.</p>



<h3 class="wp-block-heading">Datenkontext (DataContext) setzen</h3>



<p>Im ersten Schritt ergänzen wir die folgenden zwei Punkte in den XAML-Code des MainWindows (MainViews).</p>



<p>1. Wir mappen via &#8222;xmlns:&lt;name&gt;&#8220; einen Namespace anhand eines Aliases:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- ganz oben, im Abschnitt des Window-Tags -->
xmlns:vm="clr-namespace:WpfCommandsVbTutorial.ViewModels"</pre>



<p>2. Wir geben dem jeweiligen View einen Datenkontext (DataContext-Eigenschaft des Windows) über XAML. Wie Du vielleicht weißt, wäre dies auch via &#8222;Code behind&#8220;-Datei möglich, ich habe mich hier für die XAML Variante entschieden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- im "Content" des Windows -->
&lt;Window.DataContext>
    &lt;vm:MainViewModel />
&lt;/Window.DataContext></pre>



<p>Du kannst an dieser Stelle übrigens die Styling-relevanten Dinge ignorieren, also praktisch alles, was in &#8222;StackPanel.Resources&#8220; z. B. steht. Dies ist nur zur Anschauung erstellt worden und Du solltest Deinen Fokus größtenteils auf die oben aufgelisteten Steuerelemente legen.</p>



<p class="info-banner"><strong>&#x1f4a1;</strong> Hinweis: Wir werden im weiteren Verlauf noch an der PasswordBox und Co. arbeiten, sowie wichtige Sicherheitsaspekte besprechen. Dies hier ist daher noch nicht die finale Variante! Ebenso fehlt hier auch noch ein wichtiger Punkt bei der Benutzer-Textbox!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- in C#, there's a project prefix before Views -->
&lt;Window x:Class="Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfCommandsVbTutorial"
        mc:Ignorable="d"
        xmlns:vm="clr-namespace:WpfCommandsVbTutorial.ViewModels"
        Title="MainWindow" Background="DarkOrange" Height="450" Width="800" WindowStartupLocation="CenterScreen">
    
    &lt;Window.DataContext>
        &lt;vm:MainViewModel />
    &lt;/Window.DataContext>

    &lt;Grid>
        &lt;StackPanel Width="200" VerticalAlignment="Center" HorizontalAlignment="Center">
            &lt;StackPanel.Resources>
                &lt;Style TargetType="TextBlock">
                    &lt;Setter Property="Foreground" Value="WhiteSmoke" />
                    &lt;Setter Property="FontWeight" Value="SemiBold" />
                    &lt;Setter Property="FontSize" Value="16" />
                    &lt;Setter Property="Margin" Value="0 0 0 4" />
                &lt;/Style>
                &lt;Style TargetType="TextBox">
                    &lt;Setter Property="FontSize" Value="16" />
                    &lt;Setter Property="Margin" Value="0 0 0 4" />
                    &lt;Setter Property="Effect">
                        &lt;Setter.Value>
                            &lt;DropShadowEffect ShadowDepth="2" Direction="330" Color="Black" Opacity="0.5" BlurRadius="1"/>
                        &lt;/Setter.Value>
                    &lt;/Setter>
                &lt;/Style>
                &lt;Style TargetType="PasswordBox">
                    &lt;Setter Property="FontSize" Value="16" />
                    &lt;Setter Property="Margin" Value="0 0 0 8" />
                    &lt;Setter Property="Effect">
                        &lt;Setter.Value>
                            &lt;DropShadowEffect ShadowDepth="2" Direction="330" Color="Black" Opacity="0.5" BlurRadius="1"/>
                        &lt;/Setter.Value>
                    &lt;/Setter>
                &lt;/Style>
            &lt;/StackPanel.Resources>
            &lt;TextBlock Text="Benutzer" />
            &lt;TextBox Text="{Binding User}" />
            &lt;TextBlock Text="Passwort" />
            &lt;!-- die Passwordbox kann nicht so einfach gebunden werden und da dies nicht
Bestandteil dieses Beitrages ist, werde ich dies auf einen anderen Beitrag verlagern.
Konzentriere Dich bitte auf die Aspekte von WPF Commands :) -->
            &lt;PasswordBox />
            &lt;Button Command="{Binding LoginCommand}" Content="Anmelden" FontSize="16" />
        &lt;/StackPanel>
    &lt;/Grid>
&lt;/Window></pre>



<h2 class="wp-block-heading">Das ViewModel zur Oberfläche</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Das-MainViewModel-640px.png"><img loading="lazy" decoding="async" width="640" height="417" src="https://robbelroot.de/wp-content/uploads/2023/01/Das-MainViewModel-640px.png" alt="Ein ViewModel zur Oberfläche" class="wp-image-13686" title="Ein ViewModel zur Oberfläche"/></a><figcaption class="wp-element-caption">Ein ViewModel zur Oberfläche</figcaption></figure>



<p>Bevor wir mit den WPF Commands im Detail fortfahren können, müssen wir noch etwas bauen, was Diese letztendlich beinhaltet. Hierbei rede ich natürlich von einer ViewModel-Klasse, Welche alles Notwendige für die Datenbindungen bereitstellt. Neben dem oben im XAML erwähnten &#8222;LoginCommand&#8220;, bezieht sich dies natürlich auch auf die Eigenschaften wie &#8222;User&#8220; und &#8222;Password&#8220;.</p>



<p>Wenn wir dies auslassen würden, könnte die grafische Oberfläche Ihre dort empfangenen Änderungen nie via Datenbindungen an die dahinter liegenden ViewModel-Eigenschaften weitergeben. Somit hätten wir auch in unserer Geschäftslogik (innerhalb des ViewModels) nie die Chance, damit tatsächlich arbeiten zu können. Wie Du Dir also vorstellen kannst, wäre eine Anmeldung ohne z. B. typische Benutzer- und Passwort-Kombination ziemlich schwierig.</p>



<h3 class="wp-block-heading">Fehlermeldungen bei fehlender / falscher Datenbindung</h3>



<p>Falls Du an dieser Stelle also eine der typischen Binding-Fehlermeldungen bekommen solltest, kannst Du Dir nun vorstellen woran das liegt. Du hast vermutlich vergessen, den DataContext mit einer passenden ViewModel-Instanz zu befüllen – wie wir es im gleich folgenden Schritt tätigen werden. Typische Fehlermeldung sehen ungefähr so aus, also hier wurde z. B. die &#8222;User&#8220;-Eigenschaft nicht auf der &#8222;MainViewModel&#8220;-Instanz gefunden:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/BindingExpression-Fehler-–-User-konnte-nicht-fuer-die-Datenbindung-auf-dem-ViewModel-gefunden-werden.png"><img loading="lazy" decoding="async" width="856" height="75" src="https://robbelroot.de/wp-content/uploads/2023/01/BindingExpression-Fehler-–-User-konnte-nicht-fuer-die-Datenbindung-auf-dem-ViewModel-gefunden-werden.png" alt="BindingExpression Fehler – User konnte nicht für die Datenbindung auf dem ViewModel gefunden werden" class="wp-image-13762" title="BindingExpression Fehler – User konnte nicht für die Datenbindung auf dem ViewModel gefunden werden"/></a><figcaption class="wp-element-caption">BindingExpression Fehler – User konnte nicht für die Datenbindung auf dem ViewModel gefunden werden</figcaption></figure>



<p>Falls Du also eine derartige Fehlermeldung bekommst, stelle sicher, dass die Eigenschaft &#8222;User&#8220; in Deinem  Viewmodel existiert. Es kann hier aber auch vorkommen, dass z. B. gar kein Fehler kommt und dennoch nichts passiert. Dies ist z. B. der Fall, wenn Du vergisst, den DataContext überhaupt zu setzen! Denke daran, dass wir das hier im View selbst, also via XAML-Code weiter oben getan haben!</p>



<h3 class="wp-block-heading">Das (erste) MainViewModel erstellen</h3>



<p>Erstelle für die weitere Vorgehensweise in Richtung WPF Commands nun einmal bitte eine Klasse namens &#8222;MainViewModel&#8220; in Deinem &#8222;ViewModels&#8220;-Ordner. Unsere ViewModel-Klasse wird hierbei von der &#8222;PropertyChangedBase&#8220;-Basisklasse erben, damit wir die dort zurechtgeschriebene Funktionalität weiterverwenden können. Somit sparen wir es uns, die &#8222;INotifyPropertyChanged&#8220;-Schnittstelle immer und immer wieder manuell implementieren zu müssen. Kopiere Dir die Basisklasse ruhig von <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/#PropertyChangedBase-Klasse" target="_blank" rel="noreferrer noopener">diesem Beitrag hier</a></strong>.</p>



<p>Nun das MainViewModel, wundere Dich bitte nicht, dass dort schon anderer Kram drin steht, aber ich möchte Dir diesen Batzen gleich nicht noch 3x um die Ohren hauen. Wir nehmen dies daher als Basis und arbeiten uns von dort aus weiter durch den Code. Es fehlen hier auch noch die ein odere andere Funktion, sowie eine Klasse für die Commands, Welche wir natürlich noch erstellen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="main-view-model">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        Private _user As String

        Public Property User As String
            Get
                Return _user
            End Get
            Set(value As String)
                If _user = value Then
                    Return
                End If
                _user = value
                NotifyOfPropertyChange()
            End Set
        End Property

        Private _password As String

        Public Property Password As String
            Get
                Return _password
            End Get
            Set(value As String)
                If _password = value Then
                    Return
                End If
                _password = value
                NotifyOfPropertyChange()
            End Set
        End Property

        Public Property LoginCommand As LoginCommand

        Sub New()
            LoginCommand = New LoginCommand()
        End Sub

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="main-view-model">using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{
    private string _user;

    public string User
    {
        get => _user;
        set
        {
            if (_user == value)
                return;
            _user = value;
            NotifyOfPropertyChange();
        }
    }

    private string _password;

    public string Password
    {
        get => _password;
        set
        {
            if (_password == value)
                return;
            _password = value;
            NotifyOfPropertyChange();
        }
    }

    public LoginCommand LoginCommand { get; set; }

    public MainViewModel()
    {
        LoginCommand = new LoginCommand();
    }

}</pre>



<h3 class="wp-block-heading">Die üblichen Mechanismen</h3>



<p>Zuerst einmal siehst Du im obigen MainViewModel-Code die 3 wichtigsten Eigenschaften für unser Login-Fenster:</p>



<ol class="wp-block-list">
<li>Die User-Eigenschaft</li>



<li>Die Password-Eigenschaft</li>



<li>Die LoginCommand-Eigenschaft</li>
</ol>



<p>Bis auf das &#8222;LoginCommand&#8220; sind alle Eigenschaften sogenannte &#8222;voll implementierte&#8220;-Eigenschaften, Sie haben also einen von uns manuell implementierten Getter und Setter. Dies geschieht deshalb, weil wir im Setter sagen müssen: &#8222;Hey, es hat sich Code-seitig z. B. der User geändert&#8220;. Das passiert einerseits, wenn wir einen gespeicherten Zugang von der Festplatten laden, aber auch, wenn der Benutzer des Programms eine Eingabe in der Textbox macht – besonders hierzu aber gleich noch etwas! Andererseits können wir dem Command das dann auch noch explizit mitteilen, denn warum sollte man sich anmelden können, wenn, wenn z. B. gar kein Benutzername eingegeben wurde? Dazu kommen wir aber noch..</p>



<p>Etwas anders sieht es wie schon gesagt beim &#8222;LoginCommand&#8220; aus, denn Dieses wird nach der Instanziierung nicht mehr geändert. Hier reicht also eine sogenannte automatisch implementierte Eigenschaft aus.</p>



<h2 class="wp-block-heading">Der erste Command-Versuch</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-Cmmand-nach-3-Klicks-sperren.gif"><img loading="lazy" decoding="async" width="796" height="452" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-Cmmand-nach-3-Klicks-sperren.gif" alt="WPF Command nach 3 Klicks sperren" class="wp-image-13848" title="WPF Command nach 3 Klicks sperren"/></a><figcaption class="wp-element-caption">WPF Command nach 3 Klicks sperren</figcaption></figure>



<p>An dieser Stelle werden wir den ersten Versuch Richtung eigener WPF Commands starten. Wir werden dafür das sogenannte &#8222;ICommand&#8220;-Interface (manuell) implementieren – später vereinfacht, keine Sorge! Erstelle also nun bitte eine weitere Klasse (ohne Datei) namens &#8222;LoginCmd&#8220;, Diese kannst Du für den Anfang einfach innerhalb des Wurzelverzeichnisses Deines Projektes ablegen. Dies werden wir selbstverständlich später ändern, brauchen wir aber am Anfang zur reinen Demonstration.</p>



<p>Schreibe für VB.NET anschließend – wie für Schnittstellen-Implementierungen üblich – einfach &#8222;Implements INotifyPropertyChanged&#8220; unter die beginnende Klassendefinition: &#8222;Public Class LoginCommand&#8220;. Für C# kannst Du ein &#8222;: INotifyPropertyChanged&#8220; hinter den Klassennamen schreiben. In beiden Fällen kannst Du dann die Imports durch die Visual Studio-Hilfe durchführen. Alternativ kannst Du auch Strg+&#8220;.&#8220; drücken und die dann erscheinenden Vorschläge durchführen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCmd.vb" data-enlighter-group="erstes-command-1">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        ' restlicher MainViewModel-Code

        Public Property LoginCommand As LoginCommand

        Sub New()
            LoginCommand = New LoginCommand()
        End Sub

        Public Class LoginCmd
            Implements ICommand

            Public Sub Execute(parameter As Object) Implements ICommand.Execute
                Throw New NotImplementedException()
            End Sub

            Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
                Throw New NotImplementedException()
            End Function

            Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

        End Class

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCmd.cs" data-enlighter-group="erstes-command-1">using System.Windows.Input;
using System;
using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{

    // restlicher MainViewModel-Code

    public LoginCmd LoginCommand { get; set; }

    public MainViewModel()
    {
        LoginCommand = new LoginCmd();
    }

    public class LoginCmd : ICommand
    {

        public void Execute(object? parameter)
        {
            throw new NotImplementedException();
        }

        public bool CanExecute(object? parameter)
        {
            throw new NotImplementedException();
        }

        public event EventHandler? CanExecuteChanged;

    }
}</pre>



<h3 class="wp-block-heading">Was soll bei Ausführung des WPF Commands passieren?</h3>



<p>Um dem Command sagen zu können: &#8222;Hey, wenn Du ausgeführt wirst, soll xy passieren&#8220;, müssen wir nun eine bestimmte Methode implementieren. Dabei handelt es sich um die &#8222;Execute&#8220;-Methode, der &#8222;ICommand&#8220;-Schnittstelle. Dort drin können wir beispielsweise einmal einen Anmeldevorgang simulieren, mehr wird denke ich zu kompliziert sein, also etwa mit Services zu kommunizieren, usw. Das werde ich aber mit Sicherheit noch in einem anderen Beitrag vertiefen!</p>



<p>Die &#8222;Execute&#8220;-Methode sieht dann grundsätzlich erstmal wie folgt aus:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.vb" data-enlighter-group="login-command-klasse">Public Class LoginCommand
    Implements ICommand

    Public Sub Execute(parameter As Object) Implements ICommand.Execute
        ' hier kommt rein, was beim Klick passieren soll
        Debug.WriteLine("Melde mich an")
    End Sub

    ' restlicher Code..

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.cs" data-enlighter-group="login-command-klasse">public class LoginCommand : ICommand
{

    public void Execute(object? parameter)
    {
        // hier kommt rein, was beim Klick passieren soll
        Debug.WriteLine("Melde mich an");
    }

    // restlicher Code..

}</pre>



<h3 class="wp-block-heading">Kann das WPF Command überhaupt ausgeführt werden?</h3>



<p>Nachdem wir die eine &#8222;Execute&#8220;-Methode implementiert und somit beschrieben haben, was beim Ausführen des Commands passieren soll, geht&#8217;s nun mit dem &#8222;kann ich das ausführen&#8220; weiter. Es wäre ja z. B. blöd, wenn der Benutzer der Software den &#8222;Anmelden&#8220;-Knopf spammen könnte. Stattdessen sollte man den Button deaktivieren, während z. B. eine Art Sperre stattfindet. Dazu müssen wir eine Funktion namens &#8222;CanExecute&#8220; implementieren, Welche – wie der Name schon sagt – bestimmt, ob das jeweilige Command gerade ausgeführt werden kann.</p>



<p>Der Code dazu könnte wie folgt aussehen, also, dass z. B. das Command nach 3 fehlerhaften Login-Versuchen gesperrt ist.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.vb" data-enlighter-group="gesperrtes-command">Public Class LoginCommand
    Implements ICommand

    Private _failedAttempts As Integer

    Public Sub Execute(parameter As Object) Implements ICommand.Execute
        ' simulate failed login attempt
        _failedAttempts += 1
    End Sub

    Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
        Return _failedAttempts &lt; 3
    End Function

    Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.cs" data-enlighter-group="gesperrtes-command">using System;
using System.Windows.Input;

public class LoginCommand : ICommand
{
    private int _failedAttempts;

    public void Execute(object? parameter)
    {
        // simulate failed login attempt
        _failedAttempts++;
    }

    public bool CanExecute(object? parameter)
    {
        return _failedAttempts &lt; 3;
    }

    public event EventHandler? CanExecuteChanged;

}</pre>



<p>Zum Schluss bleibt hier nun noch ein letztes Problem: Das Command wird so gesehen niemals &#8222;aktualisiert&#8220;. Es wird aktuell leider nicht nach außen bekanntgemacht: &#8222;Hey, grafische Oberfläche, evaluiere bitte einmal neu, ob ich ausgeführt werden kann, denn hier hat sich was geändert!&#8220;. Somit bleibt das Command aktuell immer ausführbar. Wenn Du stattdessen z. B. initial ein Kriterium hättest – wie z. B. eine Rolle an Nutzern– die den Button nicht drücken dürfen, dann könnte es auch sein, dass der Button permanent grau hinterlegt ist. Keine Sorge, darum kümmern wir uns nun im letzten Schritt!</p>



<h3 class="wp-block-heading">Neu evaluieren, ob ausgeführt werden kann</h3>



<p>Um der grafischen Oberfläche genau dieses Signal a la &#8222;Hey, re-evaluiere hier bitte einmal die CanExecute-Funktion&#8220; zu geben, müssen wir nur eins tun: Das Ereignis auslösen, Welches bewusst von der &#8222;ICommand&#8220;-Schnittstelle dafür vorgegeben wurde, namens &#8222;CanExecuteChanged&#8220;. Aktuell ist dies noch relativ einfach, da wir alles was wir dafür benötigen, innerhalb der Command-Instanz selbst haben.</p>



<p>Was ich meine, ist die Anzahl an fehlgeschlagenen Anmelde-Versuchen, Welche wir in der Zeile 3 deklariert haben. Wir müssten also eigentlich immer das &#8222;CanExecuteChanged&#8220;-Ereignis auslösen, wenn sich diese Variable ändert. Gleich kommen wir auch noch dazu, wie wir unter Umständen agieren könnten, wenn wir z. B. auf eine &#8222;IsLoading&#8220;-Eigenschaft eines ViewModels keinen Zugriff haben.</p>



<p>Das könnte z. B. so aussehen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.vb" data-enlighter-group="can-execute-changed-1">Public Class LoginCommand
    Implements ICommand

    Private _failedAttempts As Integer

    Public Sub Execute(parameter As Object) Implements ICommand.Execute
        ' simulate failed login attempt
        _failedAttempts += 1
        RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
    End Sub

    Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
        Return _failedAttempts &lt; 3
    End Function

    Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.cs" data-enlighter-group="can-execute-changed-1">using System.Windows.Input;
using System;

public class LoginCommand : ICommand
{
    private int _failedAttempts;

    public void Execute(object? parameter)
    {
        // simulate failed login attempt
        _failedAttempts++;
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public bool CanExecute(object? parameter)
    {
        return _failedAttempts &lt; 3;
    }

    public event EventHandler? CanExecuteChanged;

}</pre>



<h3 class="wp-block-heading">Der ganze Aufwand für ein einziges Command?</h3>



<p>Ich gebe zu, dass dies alles, vor allem als Anfänger natürlich erstmal überwältigend klingen kann, besonders für bisher ein einziges Command, aber keine Sorge – &#8222;I got you&#8220;. Statt diesen Aufwand immer wieder von vorn zu betreiben, werden wir uns – als &#8222;faule&#8220; Entwickler – selbstverständlich einige Hilfsmittel schreiben, Welche uns die Arbeit vereinfachen. Im ersten Schritt wird das die gleich folgende, wiederverwendbare Klasse Namens z. B. &#8222;DelegateCommand&#8220; sein.</p>



<h2 class="wp-block-heading" id="wiederverwendbare-klasse">Eine wiederverwendbare DelegateCommand-Klasse</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Das-DelegateCommand-–-unsere-Basisklasse-fuer-WPF-Commands-640px.png"><img loading="lazy" decoding="async" width="640" height="424" src="https://robbelroot.de/wp-content/uploads/2023/01/Das-DelegateCommand-–-unsere-Basisklasse-fuer-WPF-Commands-640px.png" alt="Das DelegateCommand – unsere Basisklasse für WPF Commands" class="wp-image-13853" title="Das DelegateCommand – unsere Basisklasse für WPF Commands"/></a><figcaption class="wp-element-caption">Das DelegateCommand – unsere Basisklasse für WPF Commands</figcaption></figure>



<p>Wie Du vermutlich im letzten Schritt festgestellt hast, ist das Ganze mit den WPF Commands nicht so &#8222;mal eben&#8220; wie mit den Click-Handlern erledigt. Lasse Dich aber bitte hier dennoch nicht dazu verführen – typisch Mensch, typisch Gewohnheitstier – dennoch wieder die alten &#8222;Button1_Click&#8220; und Co. Dinger zu verwenden. Wir können uns wie hier drüber erwähnt, auch viele Hilfsmittel erschaffen, mit Denen wir uns das Handling deutlich vereinfachen können.</p>



<p>Im Endeffekt ändert sich von der Konzeption des Commands selbst, nicht viel, wir brauchen immer noch folgende Aspekte:</p>



<ol class="wp-block-list">
<li>Was soll bei Ausführung getan werden?</li>



<li>Kann es ausgeführt werden?</li>



<li>Wann ändert sich die Info, ob&#8217;s ausgeführt werden kann?</li>
</ol>



<p>Allerdings möchten wir nun nicht jedes Mal dafür eine eigene Klasse erstellen, sondern alles ein wenig mehr zentralisieren. Das können wir ganz einfach, indem wir Obiges logisch betrachten: Punkt 1 ist einfach nur ein &#8222;Packen&#8220; Arbeit, Welchen wir in die Zukunft delegieren (vielleicht rückt der Begriff &#8222;DelegateCommand&#8220; nun etwas näher &#x1f609;), nämlich bei z. B. einem Klick. Punkt 2 ist praktisch das Gleiche in bunt, nur, dass wir eine &#8222;Ja/Nein&#8220;-Info zurückbekommen: Also einen Boolean. Punkt 3 kann je nach Fall komplizierter werden, aber auch das lässt sich regeln.</p>



<h3 class="wp-block-heading">Methoden / Funktionalität dynamisch übergeben</h3>



<p>Wenn man nun zu den obigen Erkenntnissen gekommen ist, fragt man sich im nächsten Schritt das Offensichtliche: &#8222;Okay, aber wie verlagere / gruppiere ich denn überhaupt Arbeit?&#8220;. Das Stichwort, bzw. die Stichworte Deiner Begierde nennen sich &#8222;<strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.action-1?view=net-7.0" target="_blank" rel="noreferrer noopener">Action</a></strong>&#8222;, bzw. &#8222;<strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.func-2?view=net-7.0" target="_blank" rel="noreferrer noopener">Func</a></strong>&#8222;. Diese übernehmen exakt das, was wir bruachen, Sie kapseln / gruppieren unsere Anweisungen und machen Diese praktisch ansprech- und ausführbar – auch später.</p>



<h3 class="wp-block-heading">Der erste Versuch – delegierte Arbeit</h3>



<p>Schreiben wir also nun unseren aus den Erkenntnissen resultierenden, ersten Versuch. Hierbei geht es erstmal nur darum, die &#8222;Was soll getan werden&#8220;-Anweisungen als Gruppe von Anweisungen zu verlagern / zu delegieren. Das geht auch im Endeffekt ganz einfach, schaue Dir dazu diese neue Variante unserer Command-Implementierung an.</p>



<p>Wir lassen hierbei der instaziierenden Partei die Möglichkeit, den gruppierten Stapel an Arbeit von außen mitzugeben. Beachte auch, dass wir sogar die Möglichkeit haben, einen Parameter mitzuliefern. Dadurch sind wir – indem wir z. B. eine weitere Klasse erstellen – auch nicht auf einen Übergabeparameter limitiert, könnten also praktisch eine ganze &#8222;Config&#8220; mitliefern. Natürlich muss dies passend in der Execute-Methode gecastet werden..</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.vb" data-enlighter-group="delegate-command-mit-aktion">Namespace Utils

    Public Class DelegateCommand
        Implements ICommand

        Private _action As Action(Of Object)

        Sub New(action As Action(Of Object))
            _action = action
        End Sub

        Public Sub Execute(parameter As Object) Implements ICommand.Execute
            ' führt unsere von außen mitgegebene Aktion aus und übergibt auch den Parameter
            _action(parameter)
        End Sub

        Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            Return True
        End Function

        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.cs" data-enlighter-group="delegate-command-mit-aktion">using System.Windows.Input;
using System;

namespace Utils;

public class DelegateCommand : ICommand
{
    private Action&lt;object?> _action;

    public DelegateCommand(Action&lt;object?> action)
    {
        _action = action;
    }

    public void Execute(object? parameter)
    {
        // führt unsere von außen mitgegebene Aktion aus und übergibt auch den Parameter
        _action?.Invoke(parameter);
    }

    public bool CanExecute(object? parameter)
    {
        return true;
    }

    public event EventHandler? CanExecuteChanged;

}</pre>



<h3 class="wp-block-heading">Delegierte Arbeit im MainViewModel verwenden</h3>



<p>Zurück in unserem (komprimierten) MainViewModel, könnte die Erstellung des Commands nun wie gleich folgend und vollkommen dynamisch aussehen. Beachte auch, dass wir durch Polymorphie oben ein &#8222;ICommand&#8220; deklarieren, aber ein diese Schnittstelle implementierendes Objekt zuweisen können (im Konstruktor).</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="mainvm-beispiel-mit-action-command">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        ' restliche Eigenschaften..

        Public Property LoginCommand As ICommand

        Sub New()
            LoginCommand = New DelegateCommand(AddressOf Login)
        End Sub

        ' unsere gruppierten Anweisungen - zusammengefasst
        Private Sub Login(parameter As Object)
            ' tu dies
            ' tu jenes
            ' tu das
        End Sub

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="mainvm-beispiel-mit-action-command">using System.Windows.Input;
using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{

    // restliche Eigenschaften..

    public ICommand LoginCommand { get; set; }

    public MainViewModel()
    {
        LoginCommand = new DelegateCommand(Login);
    }

    // unsere gruppierten Anweisungen - zusammengefasst
    private void Login(object? parameter)
    {
        // tu dies
        // tu jenes
        // tu das
    }
}</pre>



<h3 class="wp-block-heading">Was fehlt ist, ob&#8217;s geht!</h3>



<p>Was nun noch als vorletzter Punkt fehlt, ist eine dynamische Feststellung, ob das Command überhaupt ausgeführt werden kann, denn das haben wir aktuell völlig vernachlässigt. Zum Glück können wir uns auch hier ganz schnell helfen, denn dafür gab es neben der &#8222;Action&#8220; auch etwas namens &#8222;Func&#8220;. Damit können wir eine Funktion dynamisch übergeben und dessen Rückgabewert nach unserem Belieben auswerten.</p>



<p>Hierzu habe ich einen neuen Konstruktor erstellt, Welcher uns dann die optionale Möglichkeit bietet, sagen zu können: &#8222;Hey, so stellst Du fest, ob das Command ausgeführt werden kann&#8220;. Wenn dies also nicht mitgegeben wird, könnte man praktisch davon ausgehen, dass das Command immer ausgeführt werden kann.</p>



<h3 class="wp-block-heading" id="finale-delcommand-basisklasse">Die finale DelegateCommand-Basisklasse</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.vb" data-enlighter-group="delegate-command-mit-aktion2">Namespace Utils

    Public Class DelegateCommand
        Implements ICommand

        Private _action As Action(Of Object)

        Private _canExecute As Func(Of Object, Boolean)

        Sub New(action As Action(Of Object))
            _action = action
        End Sub

        Sub New(action As Action(Of Object), canExecute As Func(Of Object, Boolean))
            _action = action
            _canExecute = canExecute
        End Sub

        Public Sub Execute(parameter As Object) Implements ICommand.Execute
            ' führt unsere von außen mitgegebene Aktion aus und übergibt auch den Parameter
            _action(parameter)
        End Sub

        Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            If _canExecute Is Nothing Then
                Return True
            End If
            Return _canExecute(parameter)
        End Function

        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.cs" data-enlighter-group="delegate-command-mit-aktion2">using System.Windows.Input;
using System;

namespace Utils
{
    public class DelegateCommand : ICommand
    {
        private Action&lt;object?> _action;

        private Func&lt;object?, bool>? _canExecute;

        public DelegateCommand(Action&lt;object?> action)
        {
            _action = action;
        }

        public DelegateCommand(Action&lt;object?> action, Func&lt;object?, bool> canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        public void Execute(object? parameter)
        {
            _action(parameter);
        }

        public bool CanExecute(object? parameter)
        {
            if (_canExecute == null)
                return true;
            return _canExecute(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, EventArgs.Empty);
        }

        public event EventHandler? CanExecuteChanged;
    }
}</pre>



<p>Nun kann unser MainViewModel wie folgt ergänzt werden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="mainvm-beispiel-mit-func-command">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        ' other properties..

        Private Property LoginAttempts As Integer

        Public Property LoginCommand As ICommand

        Sub New()
            LoginCommand = New DelegateCommand(AddressOf Login, AddressOf CanLogin)
        End Sub

        ' our grouped instructions - summed up
        Private Sub Login(parameter As Object)
            ' do this
            ' do that
            ' do something else
            LoginAttempts += 1
        End Sub

        Private Function CanLogin(parameter As Object) As Boolean
            ' determine, if the login process should be executed and return it
            Return LoginAttempts &lt; 3
        End Function

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="mainvm-beispiel-mit-func-command">using System.Windows.Input;
using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{

    // restliche Eigenschaften..

    private int LoginAttempts { get; set; }

    public ICommand LoginCommand { get; set; }

    public MainViewModel()
    {
        LoginCommand = new DelegateCommand(Login, CanLogin);
    }
    
    // our grouped instructions - summed up
    private void Login(object? parameter)
    {
        // do this
        // do that
        // do something else
        LoginAttempts++;
    }

    private bool CanLogin(object? parameter)
    {
        // determine, if the login process should be executed and return it
        return LoginAttempts &lt; 3;
    }
}</pre>



<h3 class="wp-block-heading">Und was, wenn es sich ändert?</h3>



<p>Nun kommen wir (sorry, endlich) zum finalen Punkt: Wir müssen auch hier die Möglichkeit bieten, sagen zu können: &#8222;Hey Oberfläche, bitte neu evaluieren, ob das Command ausgeführt werden kann&#8220;. Dafür gibt es z. B. die <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.input.commandmanager.invalidaterequerysuggested?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener">&#8222;CommandManager.InvalidateRequerySuggested&#8220;-Methode</a></strong>, Welche ich aber nicht ganz toll finde. Alle Commands re-evaluieren, nur weil sich ggf. Eines geändert hat? Nee..</p>



<p>Wir werden stattdessen unser eigenes kleines Helferlein dafür einbauen, ich meine, dafür haben wir ja sowieso schon unsere Basisklasse. Wir ergänzen also eine Methode, Welche es uns von außen erlaubt, das &#8222;CanExecuteChanged&#8220;-Ereignis des Commands auszulösen. Für mich fühlt sich auch das nicht ganz super an, aber es deckt genau unsere Bedürfnisse:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.vb" data-enlighter-group="finales-delegate-command">Namespace Utils

    Public Class DelegateCommand
        Implements ICommand

        Private _action As Action(Of Object)

        Private _canExecute As Func(Of Object, Boolean)

        Sub New(action As Action(Of Object))
            _action = action
        End Sub

        Sub New(action As Action(Of Object), canExecute As Func(Of Object, Boolean))
            _action = action
            _canExecute = canExecute
        End Sub

        Public Sub Execute(parameter As Object) Implements ICommand.Execute
            _action(parameter)
        End Sub

        Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            If _canExecute Is Nothing Then
                Return True
            End If
            Return _canExecute(parameter)
        End Function

        Public Sub RaiseCanExecuteChanged()
            RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
        End Sub

        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.cs" data-enlighter-group="finales-delegate-command">using System.Windows.Input;
using System;

namespace Utils;

public class DelegateCommand : ICommand
{
    private Action&lt;object?> _action;

    private Func&lt;object?, bool>? _canExecute;

    public DelegateCommand(Action&lt;object?> action)
    {
        _action = action;
    }

    public DelegateCommand(Action&lt;object?> action, Func&lt;object?, bool>? canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    public void Execute(object? parameter)
    {
        _action(parameter);
    }

    public bool CanExecute(object? parameter)
    {
        if (_canExecute == null)
            return true;
        return _canExecute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public event EventHandler? CanExecuteChanged;
}</pre>



<p>Zum Schluss nun unsere letzte MainViewModel-Anpassung (bezogen auf die fehlgeschlagene Logins Geschichte):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="final-main-vm">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        ' restliche Eigenschaften

        Public Property LoginCommand As CommandBase

        Private _loginAttempts As Integer

        Private Property LoginAttempts As Integer
            Get
                Return _loginAttempts
            End Get
            Set(value As Integer)
                _loginAttempts = value
                LoginCommand.RaiseCanExecuteChanged()
            End Set
        End Property

        Sub New()
            LoginCommand = New CommandBase(AddressOf Login, AddressOf CanLogin)
        End Sub

        Private Sub Login(parameter As Object)
            ' fehlgeschlagenen Login simulieren..
            LoginAttempts += 1
        End Sub

        Private Function CanLogin(parameter As Object) As Boolean
            Return _loginAttempts &lt; 3
        End Function

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="final-main-vm">using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{

    // restliche Eigenschaften

    public DelegateCommand LoginCommand { get; set; }

    private int _loginAttempts;

    private int LoginAttempts
    {
        get => _loginAttempts;
        set
        {
            _loginAttempts = value;
            LoginCommand.RaiseCanExecuteChanged();
        }
    }

    public MainViewModel()
    {
        LoginCommand = new DelegateCommand(Login, CanLogin);
    }

    private void Login(object? parameter)
    {
        // simulate failed login
        LoginAttempts++;
    }

    private bool CanLogin(object? parameter)
    {
        return _loginAttempts &lt; 3;
    }
}</pre>



<h2 class="wp-block-heading">Wie übergibt man Command-Parameter?</h2>



<figure class="wp-block-image size-full is-resized"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-Command-Parameter-uebergeben_640px.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-Command-Parameter-uebergeben_640px.png" alt="WPF Command-Parameter übergeben" class="wp-image-14032" style="width:640px;height:360px" title="WPF Command-Parameter übergeben"/></a><figcaption class="wp-element-caption">WPF Command-Parameter übergeben</figcaption></figure>



<p>Bisher konnten wir schon viele Eindrücke in das WPF Command gewinnen, eine Sache ist jedoch noch ein wenig auf der Strecke geblieben, sorry. Es geht um das Übergeben von Parametern, da wir ja auch z. B. extra eine &#8222;Action&#8220; / &#8222;Func&#8220; mit generischem Typenparameter vom Typ &#8222;Object&#8220; deklariert haben. Bisher verwenden wir diese Möglichkeit der Parameterübergabe noch nicht.</p>



<p class="info-banner"><strong>&#x1f4a1;</strong> Hinweis: Viele Online-Code-Schnipsel verwenden die Übergabe des Parameters auch als Möglichkeit, die PasswordBox in das Command zu übergeben und so das Passwort bei Bedarf abzurufen. Es ist laut Diskussion im Netz zwar in erster Linie &#8222;sicherer&#8220; und sicherlich eine mögliche Herangehensweise, allerdings finde ich dies wenig praktikabel.</p>



<p>Jeder (und ich meine jeder) Entwickler muss hier selbst entscheiden, Welche Sicherheitsmaßnahmen für sich, Kunden und Co. angemessen sind! Dies soll die &#8222;Considerations&#8220; selbstverständlich trotzdem nicht kleinreden und man sollte sich an &#8222;best practices&#8220; halten..</p>



<h3 class="wp-block-heading">Warum, bzw. wann übergibt man Command-Parameter?</h3>



<p>Bevor man sich allerdings tiefer in diesen Dschungel wagt, macht diese kleine Überlegung ggf. auch Sinn: &#8222;Wann braucht man Command-Parameter überhaupt!?&#8220;. Grundsätzlich können wir ja auf die Eigenschaften unseres Viewmodels zugreifen, wenn wir lokale Methoden des ViewModels mit der DelegateCommand-Klasse von oben verwenden. Das stimmt soweit auch, aber wie wir schon im Absatz hier drüber gesehen haben, kann es Situationen geben, wo wir auf die Dinge ggf. keinen Zugriff haben, dann könnte so eine Übergabe helfen.</p>



<h3 class="wp-block-heading">Parameter manuell via XAML übergeben</h3>



<p>Lasse uns daher einmal im nächsten Schritt schauen, wie wir diese Möglichkeit der Parameter nun allgemein verwenden könnten. Ich denke hier zuerst an die einfachste Variante, also eine einfache &#8222;manuelle&#8220; Übergabe. Dies können wir sehr einfach im XAML-Code erledigen, indem wir einfach einen passenden Wert, an die &#8222;CommandParameter&#8220;-Eigenschaft mitliefern:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;Button Command="{Binding LoginCommand}" CommandParameter="D" /></pre>



<h3 class="wp-block-heading">WPF Command-Parameter via DataBinding übergeben</h3>



<p>Auch ganz interessant ist die eigentlich offensichtlichste Sache, also die Übergabe via normalem Databinding. Hierzu kann ich einfach eine normale &#8222;Binding-Expression&#8220;, also einen Bindungs-Ausdruck schreiben. Dieser wird dann zu passender Zeit evaluiert und als CommandParameter übergeben:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;Button Command="{Binding LoginCommand}" CommandParameter="{Binding SomeBoundPropertyToPassIn}" /></pre>



<h3 class="wp-block-heading">Mehrere Parameter via Klasse oder MultiBinding übergeben</h3>



<p>Hier kommt noch ein wichtiger Punkt, da viele Anfänger daran scheitern. Häufig stellt man folgende Überlegung an: &#8222;Okay, so übergebe ich einen einzigen Parameter an das WPF Command, aber wie kann ich Mehrere auf einmal übergeben?&#8220;.</p>



<p>Aber keine Sorge, die Antwort ist relativ einfach, die erste Variante wäre via eigener Klasse. Lege dazu einfach eine passende Klasse mit den Eigenschaften / Werten, die Du übertragen möchtest, an:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="parameter-params-class">Public Class SpecialCmdParams

    Public Property SomePropToPassOne As String

    Public Property SomePropToPassTwo As Integer

    ' ...

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="parameter-params-class">public class SpecialCmdParams
{

    public string SomePropToPassOne { get; set; }

    public int SomePropToPassTwo { get; set; }

    // ...

}</pre>



<p>Instanziiere diese Klasse nun an passender Stelle, z. B. im ViewModel-Konstruktor und befülle die Eigenschaften durch passende Bindungen an z. B. Textboxen, whatever. Im nächsten Schritt kannst Du die Instanz der Klasse natürlich einfach via Datebindung (wie hier drüber, siehe &#8222;SomeBoundPropertyToPassIn&#8220;) übergeben. Gleich schauen wir uns noch an, wie man dies dann abrufen kann.</p>



<h3 class="wp-block-heading">Parameter via Multibinding übergeben</h3>



<p>Wer keine Lust hat jedes Mal eine passende Klasse zu erstellen, kann sich die Übergabe mehrerer Command-Parameter auch durch ein sogenanntes &#8222;<strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.data.multibinding?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener">Multibinding</a></strong>&#8220; vereinfachen. Wie der Name schon sagt, bindet man hier nicht an ein &#8222;Ding&#8220;, sondern kann gleich mehrere Datenbindungen quasi in Einer verwenden.</p>



<p>Das Blöde ist hier nur, dass man einen &#8222;Converter&#8220; benötigt, wie soll sonst aus &#8222;mehrere Dinger&#8220; -&gt; &#8222;ein Ding&#8220; werden? Man muss hier auch noch bedenken, dass man eventuell den Weg zurück braucht, also aus einem Ding wieder Mehrere zu machen. Ein derartiges, passendes Muster finden wir bei der <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.data.imultivalueconverter?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener">&#8222;IMultiValueConverter&#8220;-Schnittstelle</a></strong>.</p>



<p>Implementieren wir dieses Interface also einmal beispielhaft, um mehrere Zahlen zu übergeben (auch wenn dies bei einem Login keinen Sinn macht), es geht wie gesagt um &#8222;Commands&#8220; selbst :)! Wir übergeben hier einfach mal stumpf die Größe des Login-Fensters. Dies könnten wir natürlich auch durch eine normale Datenbindung realisieren, aber es geht wie gesagt um ein Beispiel!</p>



<p>Beachte, dass die Implementierung hier nur beispielhaft und z. B. nicht konfigurierbar ist. Zum Thema &#8222;ValueConverter&#8220; im Allgemeinen werde ich ggf. noch einen separaten Beitrag schreiben. Erstelle also nun einmal folgende Klasse, im (z. B.) &#8222;Utils&#8220;-Ordner</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DoubleNumberConverter.vb" data-enlighter-group="double-number-converter">Imports System.Globalization

Namespace Utils

    Public Class DoubleNumberConverter
        Implements IMultiValueConverter

        Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IMultiValueConverter.Convert
            Return String.Join("|", values)
        End Function

        Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
            Return value.ToString.Split("|")
        End Function

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DoubleNumberConverter.cs" data-enlighter-group="double-number-converter">using System.Globalization;

namespace Utils
{
    public class DoubleNumberConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            return string.Join("|", values);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            return value.ToString().Split("|");
        }
    }
}</pre>



<p>Damit können wir dann ein Multibinding realisieren, Welches dann über übliche Binding-Ausdrücke Daten mitliefert – aber eben Mehrere! Vergiss hier jedoch nicht, eine Instanz des &#8222;DoubleNumberConverters&#8220; entweder in der App.xaml / Application.xaml, oder in Deinem jeweiligen Control (UserControl, Window, etc..) zu erstellen. Ansonsten kannst Du den Konverter nicht verwenden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- The Window here is named "MyWindow" for example purposes -->

    &lt;!-- further above -->
    &lt;Window.Resources>
        &lt;ResourceDictionary>
            &lt;u:DoubleNumberConverter x:Key="MyDoubleNumberConverter" />
        &lt;/ResourceDictionary>
    &lt;/Window.Resources>

&lt;!-- usage -->
&lt;Button Command="{Binding LoginCommand">
    &lt;Button.CommandParameter>
        &lt;MultiBinding Converter="{StaticResource MyDoubleNumberConverter}">
             &lt;Binding Path="ActualWidth" ElementName="MyWindow"/>
             &lt;Binding Path="ActualHeight" ElementName="MyWindow"/>
        &lt;/MultiBinding>
    &lt;/Button.CommandParameter>
&lt;/Button></pre>



<h3 class="wp-block-heading">Übergebene Parameter abgreifen</h3>



<p>Nachdem wir die Beispiele zum Übergeben der Parameter gesehen haben, schauen wir uns nun an, wie wir Diese auch wieder abgreifen können. Je nachdem Welches der obigen Beispiele Du verwendest, sieht die Vorgehensweise eigentlich immer gleich aus (auch bei CanExecute):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="getting-params">' rest of the ViewModel-Class (like MainViewModel)

' the "parameter" contains everything, but combined in one thing
Public Sub Login(parameter As Object)
    ' if it looked like this in the XAML:
    ' CommandParameter="D"
    Dim passedLetter = Convert.ToString(parameter)
    ' now there's the letter D inside passedLetter

    '' if it was a custom class
    Dim yourParam = CType(parameter, SpecialCmdParams)

    '' if it was the DoubleNumberConverter - you now have :
    Dim numbersAsStrings = Convert.ToString(parameter).Split("|")
    ' do conversion, whatever
End Sub

' rest of the ViewModel-Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="getting-params">public void Login(object parameter)
{
    // if it looked like this in the XAML:
    // CommandParameter="D"
    var passedLetter = Convert.ToString(parameter);
    // now there's the letter D inside passedLetter

    // // if it was a custom class
    var yourParam = (SpecialCmdParams)parameter;

    // // if it was the DoubleNumberConverter - you now have :
    var numbersAsStrings = Convert.ToString(parameter).Split("|");
}</pre>



<h2 class="wp-block-heading" id="downloads">Downloads</h2>



<p>Lade Dir hier gerne das Beispielprojekt (oder einzelne Bestandteile) in der Sprache Deiner Wahl herunter, da der Beitrag natürlich anhand des Themas ein wenig riesig ist. So kannst Du Dich spielerisch an die einzelnen Punkte wagen und begleitend mit dem Beitrag arbeiten. Die einzelnen Dinge beinhalten jeweils die Dateien für beide Sprachen.</p>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=5867f9d0-4c87-4691-b5af-edcfc9cf21e5" target="_blank" rel="noreferrer noopener">WpfCommandsExampleVbTutorial.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=b7a9ff1d-36a0-4517-b7c9-7d3b08395f3a" target="_blank" rel="noreferrer noopener">WpfCommandsExampleCsTutorial.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=6f4780e5-cac9-4a61-a0ef-336fdf663bfa" target="_blank" rel="noreferrer noopener">DelegateCommand.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=9c9ac493-82cc-45f2-a2cd-34a1dbe8e78b" target="_blank" rel="noreferrer noopener">PropertyChangedBase.zip</a></div>
</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/">Eigene WPF Commands in MVVM VB.NET &#038; C# &#8211; der 2024 Guide</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Ein WPF MVVM Projekt aufsetzen (VB.NET &#038; C#) – 2026 Guide</title>
		<link>https://robbelroot.de/blog/ein-wpf-mvvm-projekt-aufsetzen-guide/</link>
					<comments>https://robbelroot.de/blog/ein-wpf-mvvm-projekt-aufsetzen-guide/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 04 Jan 2023 20:57:49 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[C# (C Sharp)]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[aufbau]]></category>
		<category><![CDATA[aufsetzen]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[entwurfsmuster]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[konfiguration]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[pattern]]></category>
		<category><![CDATA[projekt]]></category>
		<category><![CDATA[projektvorlage]]></category>
		<category><![CDATA[setup]]></category>
		<category><![CDATA[starten]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[view]]></category>
		<category><![CDATA[viewmodel]]></category>
		<category><![CDATA[visual basic]]></category>
		<category><![CDATA[vorlage]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=13539</guid>

					<description><![CDATA[<p>Moderne Software durch WPF MVVM Projekte erstellen In diesem Guide zeige ich, wie du ein WPF MVVM Projekt aufsetzen kannst — Schritt für Schritt, von der Ordnerstruktur bis zur wiederverwendbaren Projektvorlage. Falls du von WinForms umsteigst, lies auch: Windows Forms zu WPF migrieren – Der vollständige Guide Viele mich anschreibende Zuschauer &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/ein-wpf-mvvm-projekt-aufsetzen-guide/">Ein WPF MVVM Projekt aufsetzen (VB.NET &amp; C#) – 2026 Guide</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-MVVM-Projekt-aufsetzen-beitrags-kopf-bild.png"><img loading="lazy" decoding="async" width="640" height="427" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-MVVM-Projekt-aufsetzen-beitrags-kopf-bild.png" alt="WPF MVVM Projekt in VB.NET und C# aufsetzen" class="wp-image-13557" title="WPF MVVM Projekt in VB.NET und C# aufsetzen"/></a><figcaption class="wp-element-caption">WPF MVVM Projekt in VB.NET und C# aufsetzen</figcaption></figure>






<h2 class="wp-block-heading">Moderne Software durch WPF MVVM Projekte erstellen</h2>



<p><strong>In diesem Guide zeige ich, wie du ein WPF MVVM Projekt aufsetzen kannst — Schritt für Schritt, von der Ordnerstruktur bis zur wiederverwendbaren Projektvorlage.</strong></p>



<p><em>Falls du von WinForms umsteigst, lies auch: <a href="https://robbelroot.de/blog/windows-forms-zu-wpf-migrieren/" target="_blank" rel="noreferrer noopener"><strong>Windows Forms zu WPF migrieren – Der vollständige Guide</strong></a></em></p>



<p>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.</p>



<p>In erster Linie sind hier die Ordnerstruktur, die Konfiguration des Start-Prozesses und einige kleine / weitere Dinge relevant, aber genug gequasselt – let&#8217;s go &#x1f913;!</p>



<h2 class="wp-block-heading">Kurzfassung – WPF MVVM Projekt aufsetzen</h2>



<p>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.</p>



<p>Die Schritte wären an sich wie folgt:</p>



<ul class="wp-block-list">
<li><strong>Erstelle </strong>die MVVM-typischen <strong>Ordner</strong>: <strong>Views</strong>, <strong>ViewModels</strong>, <strong>Models</strong>, <strong>Utils</strong> (optional)</li>



<li><strong>Verschiebe </strong>das <strong>MainWindow </strong>über den Visual Studio Projektmappenexplorer <strong>in </strong>den &#8222;<strong>Views</strong>&#8222;-Ordner</li>



<li><strong>Passe </strong>den Namen des <strong>MainWindows zu </strong>&#8222;<strong>MainView</strong>&#8220; <strong>an</strong></li>



<li><strong>Sorge </strong>dafür, <strong>dass </strong>das <strong>MainView in </strong>einem passenden <strong>Namespace ist </strong>– Achtung: Code behind Datei, sowie auch die XAML-Datei</li>



<li><strong>Setze</strong> im MainView einen DataContext (entweder im XAML oder Code behind)</li>



<li><strong>Passe </strong>die <strong>StartupUri </strong>in Deiner Application.xaml Datei <strong>an</strong>: &#8222;Views/MainView.xaml&#8220;</li>



<li><strong>Implementiere </strong>die <strong>INotifyPropertyChanged</strong>-Schnittstelle <strong>in </strong>einer <strong>Basisklasse</strong> – für die Vererbung an ViewModel-Klassen (in den Utils-Ordner damit)</li>



<li><strong>Erstelle </strong>eine passende <strong>MainViewModel</strong>&#8211;<strong>Klasse</strong>, Welche von Deiner &#8222;PropertyChanged&#8220;-Implementierung erbt (häufig auch ShellViewModel genannt)</li>
</ul>



<p class="info-banner">&#x1f4a1;&nbsp;<strong>Hinweis</strong>: Nutze gerne <strong><a href="#toc_container">das Inhaltsverzeichnis</a></strong>, 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.</p>



<style>
.info-banner {
    background: #03a9f4;
    padding: 2em;
    border-radius: 0.5em;
    color: whitesmoke;
}
.info-banner a {
    color: #FED766;
}
</style>



<h2 class="wp-block-heading" id="propertychanged-schnittstelle">INotifyPropertyChanged in WPF — Warum und wie</h2>



<p>Beachte, dass ich nicht genauer auf das &#8222;INotifyPropertyChanged&#8220;-Interface eingehen werden, dies habe ich im Beitrag &#8222;<strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/#PropertyChangedBase-Klasse" target="_blank" rel="noreferrer noopener">Der ultimative INotifyPropertyChanged Guide</a></strong>&#8220; getan. Klicke auf den Link, falls Du die Basisklasse oder auch detaillierte Informationen zum Thema benötigst – der Link schickt Dich direkt zur Basisklasse.</p>



<p>Kurzgesagt ist <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.componentmodel.inotifypropertychanged?view=net-7.0" target="_blank" rel="noreferrer noopener">diese Schnittstelle</a></strong> eine Art Vertrag (eine Schnittstelle eben..), damit die &#8222;WPF-Engine&#8220; – so nenne ich Sie jetzt einfach mal – weiß: &#8222;Hey, wann und wie werden mir Änderungen kommuniziert?&#8220;. Es ist daher unsere Aufgabe als Entwickler, Sie korrekt zu implementieren und an den notwendigen Stellen das &#8222;PropertyChanged&#8220;-Ereignis auszulösen. Somit weiß die Oberfläche dann: &#8222;Aha, da ist was passiert, also muss ich aktiv werden&#8220;.</p>



<h2 class="wp-block-heading">Mehr über das MVVM-Entwurfsmuster selbst</h2>



<p><em>Das MVVM Pattern in WPF ist der Standard für saubere, testbare Desktop-Anwendungen</em>.</p>



<p>Falls Du eventuell völlig neu im Themenbereich MVVM bist, kann ich Dir hier auch meinen <strong><a href="https://robbelroot.de/blog/mvvm-csharp/" target="_blank" rel="noreferrer noopener">Beitrag über das &#8222;Model-View-ViewModel-Entwurfsmuster&#8220;</a></strong> empfehlen. Lass Dich hier bitte nicht von der &#8222;Spezialisierung&#8220; auf C# verwirren, letztendlich ist hier alles analog und die Erkenntnisse helfen Dir in beiden .NET-Sprachen gleichermaßen.</p>



<h2 class="wp-block-heading">Schritt 1: MVVM-Ordner anlegen</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Projekt-und-Ordnerstruktur-–-VB.NET-WPF-Commands-in-MVVM_640px.png"><img loading="lazy" decoding="async" width="640" height="427" src="https://robbelroot.de/wp-content/uploads/2023/01/Projekt-und-Ordnerstruktur-–-VB.NET-WPF-Commands-in-MVVM_640px.png" alt="Projekt und Ordnerstruktur – WPF MVVM Projekt aufsetzen" class="wp-image-13421" title="Projekt und Ordnerstruktur – WPF MVVM Projekt aufsetzen"/></a><figcaption class="wp-element-caption">Projekt und Ordnerstruktur – WPF MVVM Projekt aufsetzen</figcaption></figure>



<p>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 &#8222;Hinzufügen-&gt;Ordner&#8220;.</p>



<p>Erstelle nun innerhalb Deiner Projektmappe unter anderem einen <strong>Ordner </strong>namens &#8222;<strong>ViewModels</strong>&#8222;, hier kommen – wie der Name schon sagt – unsere ViewModels rein. Füge dann bitte noch einen weiteren <strong>Ordner </strong>namens &#8222;<strong>Views</strong>&#8220; 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).</p>



<h3 class="wp-block-heading">Die richtige WPF Projektstruktur — Ordner und Namespaces</h3>



<p>Achtung: Wenn Du MVVM-Hilfs-Frameworks wie &#8222;Caliburn Micro&#8220; verwendest, könntest Du allerdings ein wenig an <strong><a href="https://de.wikipedia.org/wiki/Namenskonvention_(Datenverarbeitung)" target="_blank" rel="noreferrer noopener">Namenskonventionen</a></strong> 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.</p>



<p>Im <strong>letzten Schritt</strong> benötigen wir noch einen weiteren kleinen &#8222;<strong>Hilfs-Ordner</strong>&#8222;, dort packen wir nützliche Helferlein rein, Welche uns den Alltag in MVVM versüßen. Nenne den Ordner daher einfach &#8222;<strong>Utils</strong>&#8220; (Utilities/Hilfsmittel), später kommt dort dann die wiederverwendbare &#8222;PropertyChangedBase&#8220;-Klasse hinein. Wenn Du auch den <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/#PropertyChangedBase-Klasse" target="_blank" rel="noreferrer noopener">Beitrag zur &#8222;INotifyPropertyChanged&#8220;-Schnittstelle</a></strong> besucht hast, hast Du hier auch schon die notwendige &#8222;PropertyChangedBase&#8220;-Basisklasse drin. Besuche ansonsten einfach den Link, ziehe Dir den Code (wo Du direkt auskommen solltest) und packe die Klasse in den &#8222;Utils&#8220;-Ordner.</p>



<p>Unsere finale Struktur sollte also nun wie folgt aussehen:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Finale-Ordnerstruktur-im-Projekt-–-VB.NET-WPF-Commands-in-MVVM.png"><img loading="lazy" decoding="async" width="279" height="191" src="https://robbelroot.de/wp-content/uploads/2023/01/Finale-Ordnerstruktur-im-Projekt-–-VB.NET-WPF-Commands-in-MVVM.png" alt="Finale Ordnerstruktur im Projekt – WPF MVVM Projekt aufsetzen" class="wp-image-13428" title="Finale Ordnerstruktur im Projekt – WPF MVVM Projekt aufsetzen"/></a><figcaption class="wp-element-caption">Finale Ordnerstruktur im Projekt – WPF MVVM Projekt aufsetzen</figcaption></figure>



<p class="info-banner">&#x1f4a1;&nbsp;<strong>Hinweis</strong>: Wir werden in diesem Beitrag die &#8222;PropertyChangedBase&#8220;-Basisklasse aus meinem Beitrag zum Thema &#8222;<strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/#PropertyChangedBase-Klasse" target="_blank" rel="noreferrer noopener">Die INotifyPropertyChanged-Schnittstelle – Änderungen kommunizieren</a></strong>&#8220; verwenden. Stelle sicher, dass Du die Klasse also im &#8222;Utils&#8220;-Ordner und dem passenden Namespace ablegst! Klicke einfach auf den Link und Du kommst sofort zur passenden Klasse im Beitrag (VB.NET &amp; C# Code).</p>



<style>
.info-banner {
    background: #03a9f4;
    padding: 2em;
    border-radius: 0.5em;
    color: whitesmoke;
}
.info-banner a {
    color: #FED766;
}
</style>



<h2 class="wp-block-heading">Schritt 2: MainWindow verschieben &amp; umbenennen</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/MainWindow-verschieben-etc-640px..png"><img loading="lazy" decoding="async" width="640" height="406" src="https://robbelroot.de/wp-content/uploads/2023/01/MainWindow-verschieben-etc-640px..png" alt="MainWindow verschieben &amp; umbenennen – WPF MVVM Projekt aufsetzen" class="wp-image-13656" title="MainWindow verschieben &amp; umbenennen – WPF MVVM Projekt aufsetzen"/></a><figcaption class="wp-element-caption">MainWindow verschieben &amp; umbenennen – WPF MVVM Projekt aufsetzen</figcaption></figure>



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



<h3 class="wp-block-heading">Ab in den richtigen Ordner</h3>



<p>Schiebe das MainWindow nun in den Ordner namens &#8222;Views&#8220;, verwende dazu am besten den Drag &amp; 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.</p>



<h3 class="wp-block-heading">Einen MVVM entsprechenden Namen &amp; Namespace</h3>



<p>Benenne im nächsten Schritt das &#8222;MainWindow&#8220; in &#8222;MainView&#8220; 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 &#8222;Views.&#8220;-Prefix vor die eigentliche Bezeichnung.</p>



<h3 class="wp-block-heading">DataContext in WPF setzen — via XAML oder Code-Behind</h3>



<p>Beachte hier, dass Du diese beiden Zeilen (mit x:Class &amp; 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 – <strong><a href="#Das-MainViewModel">darum kümmern wir uns später</a></strong>. Durch die später erstellte Klasse wird der Namespace hier verfügbar – ggf. musst Du hierfür einmal das Projekt debuggen/builder, damit &#8222;er&#8220; es kapiert.</p>



<p>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 &#8222;Code behind&#8220;-Datei durchführen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;Window x:Class="Views.MainView"
        xmlns:vm="clr-namespace:WpfCommandsVbTutorial.ViewModels">

    &lt;Window.DataContext>
        &lt;vm:MainViewModel />
    &lt;/Window.DataContext>

    &lt;!-- restlicher XAML-Code -->
&lt;/Window></pre>



<p>Diese Änderungen werden wir nun auch im sogenannten &#8222;Code behind&#8220;-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 &#8222;Code behind&#8220;-Datei und Du solltest folgenden Code einfügen &#8211; also das MainView mit einem Namespace umgeben.</p>



<h3 class="wp-block-heading">Anmerkung zum DataContext</h3>



<p>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&#8216; Dir aber auch gern an, wie Du auch hier den Datenkontext festlegen könntest.</p>



<p>Mach&#8216; Dir hier übrigens keine Sorgen über das &#8222;MainViewModel&#8220;, dabei handelt es sich um eine Klasse, Welche wir gleich noch erstellen werden!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainView.xaml.vb" data-enlighter-group="mainview-namespace">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</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainView.xaml.cs" data-enlighter-group="mainview-namespace">namespace Views
{
    class MainView
    {

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

    }
}</pre>



<h2 class="wp-block-heading">Schritt 3: Start-Prozess der Software anpassen (Bootstrapping)</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Start-Prozess-anpassen-640px.png"><img loading="lazy" decoding="async" width="640" height="427" src="https://robbelroot.de/wp-content/uploads/2023/01/Start-Prozess-anpassen-640px.png" alt="Start-Prozess anpassen – WPF MVVM Projekt aufsetzen" class="wp-image-13658" title="Start-Prozess anpassen – WPF MVVM Projekt aufsetzen"/></a><figcaption class="wp-element-caption">Start-Prozess anpassen – WPF MVVM Projekt aufsetzen</figcaption></figure>



<p>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 &#8222;StartupUri&#8220; in der &#8222;Application.xaml / App.xaml&#8220;-Datei angepasst werden.</p>



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



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;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">
    &lt;Application.Resources>
         
    &lt;/Application.Resources>
&lt;/Application></pre>



<h2 class="wp-block-heading">Schritt 4: ViewModel in WPF erstellen — Basisklasse und MainViewModel</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Das-MainViewModel-640px.png"><img loading="lazy" decoding="async" width="640" height="417" src="https://robbelroot.de/wp-content/uploads/2023/01/Das-MainViewModel-640px.png" alt="Ein passendes ViewModel erstellen" class="wp-image-13686" title="Ein passendes ViewModel erstellen"/></a><figcaption class="wp-element-caption">Ein passendes ViewModel erstellen</figcaption></figure>



<p>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 &#8222;cool&#8220; aussehen, aber letztendlich nichts &#8222;können&#8220;.</p>



<h3 class="wp-block-heading">Eine wiederverwendbare Basisklasse</h3>



<p>Um uns nicht immer wiederholen zu müssen, machen wir hier Gebrauch von der schon mehrfach erwähnten &#8222;PropertyChangedBase&#8220;-Basisklasse aus meinem anderen Beitrag. Gehe daher also bitte hin und erstelle diese Klassen-Datei im oben angelegten &#8222;Utils&#8220;-Ordner. Einen detaillierten Guide findest Du dazu im <strong><a href="#propertychanged-schnittstelle">oben verlinkten Beitrag</a></strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="PropertyChangedBase.vb" data-enlighter-group="property-changed-base-klasse">Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Namespace Utils
    Public MustInherit Class PropertyChangedBase
        Implements INotifyPropertyChanged
        Protected Sub NotifyOfPropertyChange(&lt;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</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="PropertyChangedBase.cs" data-enlighter-group="property-changed-base-klasse">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;
}</pre>



<h3 class="wp-block-heading">Das MainViewModel</h3>



<p>Nun erstellen wir unser MainViewModel, Welches die aufbereiteten Elemente für das View beinhaltet – darunter auch passende Logik, wie z. B. für einen &#8222;Button1_Click&#8220;. 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.</p>



<p>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:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="main-view-model">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class NewMainViewModel
        Inherits PropertyChangedBase

        Sub New()
            
        End Sub

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="main-view-model">using WpfCommandsVbTutorial.Utils;

namespace ViewModels
{

    public class NewMainViewModel : PropertyChangedBase
    {

        public NewMainViewModel()
        {
            
        }

    }

}</pre>



<h2 class="wp-block-heading">Bonus: WPF MVVM Projektvorlage erstellen</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/NET-MVVM-Projektvorlage-640px.png"><img loading="lazy" decoding="async" width="640" height="430" src="https://robbelroot.de/wp-content/uploads/2023/01/NET-MVVM-Projektvorlage-640px.png" alt="Bonus: NET MVVM Projektvorlage" class="wp-image-13693" title="Bonus: NET MVVM Projektvorlage"/></a><figcaption class="wp-element-caption">Bonus: NET MVVM Projektvorlage</figcaption></figure>



<p>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.</p>



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



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Projektvorlagen-Assistent-Schritt-1.png"><img loading="lazy" decoding="async" width="717" height="549" src="https://robbelroot.de/wp-content/uploads/2023/01/Projektvorlagen-Assistent-Schritt-1.png" alt="Projektvorlagen-Assistent Schritt 1" class="wp-image-13695" title="Projektvorlagen-Assistent Schritt 1"/></a><figcaption class="wp-element-caption">Projektvorlagen-Assistent Schritt 1</figcaption></figure>



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



<p>&#x1f4a1;&nbsp;<strong>Hinweis</strong>: Hake hier am besten das Kästchen &#8222;Vorlage automatisch in Visual Studio importieren&#8220; an, dann brauchst Du Dich darum nicht manuell kümmern.</p>



<figure class="wp-block-image size-full" id="Projektvorlagen-Assistent-Schritt-2"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Projektvorlagen-Assistent-Schritt-2.png"><img loading="lazy" decoding="async" width="720" height="551" src="https://robbelroot.de/wp-content/uploads/2023/01/Projektvorlagen-Assistent-Schritt-2.png" alt="Projektvorlagen-Assistent Schritt 2" class="wp-image-13701"/></a><figcaption class="wp-element-caption">Projektvorlagen-Assistent Schritt 2</figcaption></figure>



<p>Wenn Du nun ein neues Projekt anlegst, findest Du Dein Template ganz einfach wieder:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Projektvorlagen-Assistent-Schritt-3.png"><img loading="lazy" decoding="async" width="941" height="628" src="https://robbelroot.de/wp-content/uploads/2023/01/Projektvorlagen-Assistent-Schritt-3.png" alt="Projektvorlagen-Assistent Schritt 3" class="wp-image-13705" title="Projektvorlagen-Assistent Schritt 3"/></a><figcaption class="wp-element-caption">Projektvorlagen-Assistent Schritt 3</figcaption></figure>
<p>Der Beitrag <a href="https://robbelroot.de/blog/ein-wpf-mvvm-projekt-aufsetzen-guide/">Ein WPF MVVM Projekt aufsetzen (VB.NET &amp; C#) – 2026 Guide</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/ein-wpf-mvvm-projekt-aufsetzen-guide/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Der ultimative WPF DataGrid MVVM Guide in 2026 – C# &#038; VB.NET</title>
		<link>https://robbelroot.de/blog/der-ultimative-wpf-datagrid-mvvm-guide-csharp-und-vb-net/</link>
					<comments>https://robbelroot.de/blog/der-ultimative-wpf-datagrid-mvvm-guide-csharp-und-vb-net/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sat, 24 Dec 2022 12:40:22 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[C# (C Sharp)]]></category>
		<category><![CDATA[C# Problemlösungen]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[WPF Problemlösungen]]></category>
		<category><![CDATA[auswahl]]></category>
		<category><![CDATA[bindung]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[databinding]]></category>
		<category><![CDATA[datagrid]]></category>
		<category><![CDATA[datagridview]]></category>
		<category><![CDATA[mainwindow]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[selecteditem]]></category>
		<category><![CDATA[tabelle]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[view]]></category>
		<category><![CDATA[viewmodel]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=13143</guid>

					<description><![CDATA[<p>Daten im MVVM tabellarisch darstellen – mit WPF DataGrid Ich glaube jeder Entwickler wird regelmäßig eine Art Tabellen-Steuerelement, also z. B. das WPF DataGrid benutzen müssen. Unter Windows Forms hieß es damals noch &#8222;DataGridView&#8220;, aber letztendlich hat sich vom offensichtlichen Zweck nichts geändert: Wir möchten dem Nutzer Daten anhand einer &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/der-ultimative-wpf-datagrid-mvvm-guide-csharp-und-vb-net/">Der ultimative WPF DataGrid MVVM Guide in 2026 – C# &amp; VB.NET</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/WPF-Datagrid-MVVM-Der-ultimative-Guide.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/12/WPF-Datagrid-MVVM-Der-ultimative-Guide.png" alt="WPF Datagrid MVVM - Der ultimative Guide" class="wp-image-13288" title="WPF Datagrid MVVM - Der ultimative Guide"/></a><figcaption class="wp-element-caption">WPF Datagrid MVVM &#8211; Der ultimative Guide</figcaption></figure>






<h2 class="wp-block-heading">Daten im MVVM tabellarisch darstellen – mit WPF DataGrid</h2>



<p>Ich glaube jeder Entwickler wird regelmäßig eine Art Tabellen-Steuerelement, also z. B. das WPF DataGrid benutzen müssen. Unter Windows Forms hieß es damals noch &#8222;DataGridView&#8220;, aber letztendlich hat sich vom offensichtlichen Zweck nichts geändert: Wir möchten dem Nutzer Daten anhand einer Tabellenstruktur darstellen. Diese Daten werden anhand von Reihen, Welche aus verschiedenen Spalten bestehen gegliedert dargestellt.</p>



<p>Daher beschäftigen wir uns im heutigen Beitrag damit, was sich seit den Windows Forms (DataGridView) geändert hat und wie man im heutigen MVVM- (Model-View-Viewmodel-) Entwurfsmuster mit Tabellen arbeitet. Auch wenn wir hier natürlich nicht zu tief in die Details von MVVM selbst abtauchen können, werde ich einen Teil wiederholen.</p>



<p>Gerne kannst Du in meinem <strong><a href="https://robbelroot.de/blog/mvvm-csharp/" target="_blank" rel="noreferrer noopener">Beitrag über das Model-View-ViewModel-Entwurfsmuster</a></strong> mehr Details erfahren. Hierbei spielt es auch keine Rolle, ob man VB.NET oder C# verwendet, denn die Prinzipien sind die Gleichen! Für diesen Beitrag ist auch das <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/" target="_blank" rel="noreferrer noopener">Verständnis über die &#8222;INotifyPropertyChanged&#8220;-Schnittstelle </a></strong>essenziell, also schau auch einmal dort vorbei!</p>



<p class="info-banner">&#x1f4a1; <strong>Hinweis</strong>: Beachte bitte, dass es nicht &#8222;den einen Weg&#8220; gibt. Im heutigen Beitrag schauen wir uns eine Möglichkeit an, alles mehr oder weniger selfmade zu machen, da ich das Grundverständnis wichtig finde. In einem zukünftigen Beitrag, bzw. in einem Update für diesen Beitrag, werde ich dann noch auf die Möglichkeiten mit einem Werkzeug wie Caliburn Micro eingehen. Derartige Frameworks helfen uns Entwicklern bei der Umsetzung und sparen uns Einiges an Arbeit.</p>



<style>
.info-banner {
    background: #03a9f4;
    padding: 2em;
    border-radius: 0.5em;
    color: whitesmoke;
}
.info-banner a {
    color: #FED766;
}
</style>



<h2 class="wp-block-heading">Im Videoformat ansehen</h2>



<p>Falls Du keine Lust auf Text hast, kannst Du Dir auch gerne mein passendes Video ansehen. Ich würde Dir jedoch trotzdem empfehlen, den ein oder anderen Blick auf diesen Beitrag hier zu werfen, da ich hier noch mehr im Detail auf das Thema eingehen kann.</p>


<div class="async-youtube" data-embed="n7U4eQkTsyM" data-alt="">
    <div class="play-button"></div>      
  </div>



<h2 class="wp-block-heading">Ordnerstruktur vorbereiten</h2>



<p>Die meisten Entwickler lieben es, alles sauber zu strukturieren, es gehört ja auch irgendwie zum Beruf, oder? Daher gehen wir im nächsten Schritt hin und beginnen mit unserer Projekt-Strukturierung. Achte darauf, dass Du die Ordner nicht aus Versehen in der Projektmappe, sondern tatsächlich im Projektordner erstellst!</p>



<p>Erstelle dazu im ersten Schritt den wichtigsten Ordner in Deinem Projekt, namens &#8222;ViewModels&#8220;. Danach kannst Du noch den Ordner &#8222;Models&#8220; und einen Weiteren namens &#8222;Utils&#8220; erstellen. Danach sind wir startklar und können passende ViewModels dort ablegen und darauf zugreifen. Deine Struktur sollte zu diesem Zeitpunkt wie folgt aussehen:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/Ordnerstruktur-des-Projekts-–-WPF-DataGrid-MVVM-Beispiel.png"><img loading="lazy" decoding="async" width="290" height="318" src="https://robbelroot.de/wp-content/uploads/2022/12/Ordnerstruktur-des-Projekts-–-WPF-DataGrid-MVVM-Beispiel.png" alt="Ordnerstruktur des Projekts – WPF DataGrid MVVM Beispiel" class="wp-image-13171" title="Ordnerstruktur des Projekts – WPF DataGrid MVVM Beispiel"/></a><figcaption class="wp-element-caption">Ordnerstruktur des Projekts – WPF DataGrid MVVM Beispiel</figcaption></figure>



<p class="info-banner">&#x1f4a1; <strong>Hinweis</strong>: Beachte hier, dass wir uns nicht an alles halten, sprich, wir werden keinen &#8222;Views&#8220;-Ordner anlegen, da hier die Verwendung des DataGrids im Vordergrund steht! Ich möchte Dich hier nicht unnötig damit verwirren, wie man dann das MainWindow inkl. der Application-Datei auch noch umgestalten müsste, etc.</p>



<p>Allerdings ist dies auch nicht schlimm, da es praktisch im Kern darum geht, wo man die Daten her bekommt und wie man Sie anschließend durch Datenbindungen darstellt.</p>



<h2 class="wp-block-heading">Das MainViewModel für die WPF DataGrid Bindung</h2>



<p>Damit wir gleich irgendwann mit sogenannten Datenbindungen im WPF-Bereich arbeiten können, müssen wir vorerst noch andere Vorbereitungen treffen. Da im MVVM-Entwurfsmuster mit ViewModels und dazugehörigen Views gearbeitet wird, legen wir im nächsten Schritt unser erstes ViewModel an.</p>



<p>Dies wird praktisch das &#8222;Haupt-Ding&#8220; unserer Anwendung, daher nennen wir es passenderweise auch &#8222;MainViewModel&#8220;. Weil wir natürlich sauber arbeiten, achte bitte darauf, dass Du die Klassen-Datei nicht nur im korrekten Ordner (ViewModels) anlegst, sondern auch mit einem korrekten Namespace versiehst! </p>



<p class="info-banner">&#x1f4a1; <strong>Hinweis</strong>: Für das C#-Snippet verwende ich hier die neue Namespace-Variante, also ohne die &#8222;{}&#8220; und einen zusätzlichen Einschub (ich liebe dieses Feature). Wenn Du noch mit der alten Syntax unterwegs bist, kannst Du Diese natürlich genauso gut verwenden. Umschließe dazu einfach das &#8222;MainViewModel&#8220; – wie üblich – mit dem &#8222;namespace&#8220;-Schlüsselwort und &#8222;{}&#8220; und setze die Klasse dort rein.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="erstes-mainviewmodel">namespace DataGridBindingBeispiel.ViewModels;

public class MainViewModel
{

    public MainViewModel()
    {

    }

}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="erstes-mainviewmodel">Namespace ViewModels

    Public Class MainViewModel
    
        Sub New()

        End Sub

    End Class

End Namespace</pre>



<h2 class="wp-block-heading">Den DataContext des MainWindows setzen</h2>



<p>Nachdem Du nun das &#8222;MainViewModel&#8220; erstellt hast, müssen wir Dieses, bzw. eine Instanz davon im nächsten Schritt verwenden. Ansonsten wüsste das &#8222;MainWindow&#8220; nicht, wo es die zugrundeliegenden Daten für die Datenbindungs-Anweisungen findet. Lass uns den &#8222;DataContext&#8220; des &#8222;MainWindows&#8220; nun im Code-Behind-File des Views setzen.</p>



<p>Dorthin gelangst Du, indem Du einfach die F7-Taste drückst, während Du im XAML-Designer des &#8222;MainWindows&#8220; bist:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainWindow.xaml.cs" data-enlighter-group="datacontext-setzen">using DataGridBindingBeispiel.ViewModels;

class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainWindow.xaml.vb" data-enlighter-group="datacontext-setzen">Imports DataGridBindingBeispiel.ViewModels

Class MainWindow

    Sub New()
        InitializeComponent()
        DataContext = New MainViewModel()
    End Sub

End Class</pre>



<p>Grundsätzlich weiß unser Hauptfenster also nun, wo es seine Daten finden kann, wenn wir eine Datenbindung verwenden. Das nächste Problem ist aktuell natürlich noch, dass im Datenkontext noch gar keine Daten vorhanden sind, an Welche gebunden werden könnte. Lass uns das also gleich erledigen, vorerst müssen wir leider noch etwas &#8222;erfinden&#8220; &#8211; dazu im nächsten Abschnitt mehr.</p>



<h2 class="wp-block-heading">Unser Model &#8211; womit arbeiten wir überhaupt?</h2>



<p>Bevor wir gleich überhaupt &#8222;etwas&#8220; anzeigen können, müssen wir uns über dieses &#8222;Etwas&#8220; erst einmal Gedanken machen. In unserem heutigen Beispiel möchten wir z. B. Rechnungen im DataGrid darstellen. Dazu müssen wir unserem Programm jedoch zuerst beibringen, was eine Rechnung überhaupt ist – woher soll es das sonst wissen..</p>



<p>Bringen wir also im nächsten Schritt unserem Programm bei, was eine Rechnung ist. Erstelle dazu im Ordner &#8222;Models&#8220; eine Klassen-Datei namens &#8222;Bill&#8220; und schreibe den folgenden Code hinein. Achte auch hier selbstverständlich auf den korrekten Namespace!</p>



<p class="info-banner">&#x1f4a1; <strong>Hinweis</strong>: Natürlich werden wir hier keine vollständige Rechnung nachbauen, sondern nur eine für das Beispiel komprimierte Klasse/Variante. Beachte auch, dass wir beim VB.NET-Beispiel eckige Klammern brauchen, da &#8222;Date&#8220; ein reserviertes Schlüsselwort, bzw. ein &#8222;DateTime&#8220;-Alias ist.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="Bill.cs" data-enlighter-group="bill-model">using System;

namespace Models
{
    public class Bill
    {
        public int Id { get; set; }

        public DateTime Date { get; set; }

        public Bill(int id, DateTime date)
        {
            Id = id;
            Date = date;
        }
    }
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="Bill.vb" data-enlighter-group="bill-model">Namespace Models

    Public Class Bill

        Public Property Id As Integer

        Public Property [Date] As Date

        Sub New(id As Integer, [date] As Date)
            Me.Id = id
            Me.Date = [date]
        End Sub

    End Class

End Namespace</pre>



<p>So, nun weiß unser Programm, was eine Rechnung ist und der nächste Schritt wäre dann, Rechnungen darzustellen. Dies besteht natürlich wieder aus einzelnen Schritten.</p>



<h2 class="wp-block-heading">Eine erste Datenbindung</h2>



<p>Gehe nun zurück in die &#8222;MainWindow.xaml&#8220;-Datei, dort werden wir jetzt die Tabelle, also das WPF DataGrid erstellen. Natürlich werden wir hier jetzt keine ausgefeilte UI bauen, sondern uns auf das DataGrid allein fokussieren. Schreibe wie für XAML üblich also nun ein öffnendes und schließendes DataGrid-Tag in den XAML Code.</p>



<p>Zusätzlich geben wir auch direkt die erste Datenbindung an:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- MainWindow Rest ... -->

&lt;DataGrid ItemsSource="{Binding Bills}">

&lt;/DataGrid>

&lt;!-- ... --></pre>



<p>Damit sagen wir dem XAML-Code erstmal: &#8222;Hey, stelle hier bitte ein DataGrid dar und die dazugehörigen Einträge/Reihen, findest Du in der Bills-Eigenschaft&#8220;.</p>



<p>Der Code hätte aktuell außer einer Fehlermeldung noch nichts zur Folge. Wo schauen die Datenbindungs-Anweisungen nochmal nach? Richtig! Im DataContext, sprich unserer &#8222;MainViewModel&#8220;-Instanz! Dort gibt es bisher noch keine Art &#8222;Liste&#8220; von Rechnungen. Aktuell kommt so nur ein Fehler namens &#8222;Kann Bills auf blabla nicht finden&#8220;.</p>



<h3 class="wp-block-heading">Automatisch generierte Spalten im WPF DataGrid</h3>



<p>Da wir gerade aber beim Thema XAML sind, stell&#8216; Dir einfach mal vor, wir hätten diese &#8222;Bills&#8220; schon drin (dazu kommen wir gleich selbstverständlich auch noch).  Aktuell würde das &#8222;DataGrid&#8220; alle Spalten anhand der Eigenschaften der zugrundeliegenden Objekte automatisch generieren. Dies sähe erstmal so aus:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/DataGrid-mit-automatischen-Spalten-–-WPF-DataGrid-MVVM-Beispiel.png"><img loading="lazy" decoding="async" width="254" height="151" src="https://robbelroot.de/wp-content/uploads/2022/12/DataGrid-mit-automatischen-Spalten-–-WPF-DataGrid-MVVM-Beispiel.png" alt="DataGrid mit automatischen Spalten – WPF DataGrid MVVM Beispiel" class="wp-image-13215" title="DataGrid mit automatischen Spalten – WPF DataGrid MVVM Beispiel"/></a><figcaption class="wp-element-caption">DataGrid mit automatischen Spalten – WPF DataGrid MVVM Beispiel</figcaption></figure>



<p>Ich sag mal so: Cool, aber auch irgendwie uncool.. Die meisten deutschen Nutzer würden sich direkt beschweren, was denn bitte ein &#8222;Date&#8220; sein soll (bitte arg deutsch aussprechen &#8211; dann kommt der Effekt besser rüber). Ebenso ist die Darstellung, bzw. das Format des Datums nicht wirklich toll &#8211; aber um beides kümmern wir uns nun!</p>



<h3 class="wp-block-heading">Spalten &amp; Formate selbst bestimmen</h3>



<p>Bevor wir uns über die Darstellungs-Formate der jeweiligen Spalten Gedanken machen, müssen wir erstmal dafür sorgen, dass manuelle Spalten vorhanden sind. Das geht im WPF DataGrid ganz einfach, indem wir – eben XAML-typisch – eine Eigenschaft des DataGrids festlegen: &#8222;DataGrid.ColumnDefinitions&#8220;.</p>



<p>Gehe also wieder in den XAML-Code und zwischen die beiden DataGrid-Tags, dort erstellst Du ein öffnendes und schließendes Tag für die &#8222;ColumnDefinitions&#8220;-Eigenschaft. Dort drin fügen wir unsere Spalten-Definitionen hinzu. Für unser Beispiel haben wir erstmal eine simple Text-Spalte und eine Weitere mit einer Format-Angabe.</p>



<h3 class="wp-block-heading">Der Kopf-Text der Spalte</h3>



<p>Wir geben der jeweiligen Spalte einen &#8222;Header&#8220;-Wert, damit wir eine Spaltenüberschrift bekommen und danach noch die Datenbindungs-Anweisung. Bei der Id ist es relativ simple, da wir hier nur sagen: &#8222;Stelle hier einfach die Zahl der Id als Text dar&#8220;. Beim Datum sieht es anders aus, hier sagen wir erstmal, dass er das Datum nehmen, aber speziell formatieren soll. Dies erreichen wir innerhalb der Binding-Anweisung mit der Eigenschaft &#8222;StringFormat&#8220;.</p>



<h3 class="wp-block-heading">Formatierung</h3>



<p>Dort schreibst Du einfach zwei geschweifte Klammern-Paare, pass jedoch dabei auf, die Autovervollständigung grätscht hier öfters mal dazwischen. Im zweiten Paar geben wir zuerst den zu verwendenden Wert an (in diesem Fall den ersten Wert = Index 0), Welchen wir dann mit &#8222;dd.MM.yy HH:mm&#8220; formatieren möchten.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        &lt;DataGrid ItemsSource="{Binding Bills}">
            &lt;DataGrid.Columns>
                &lt;DataGridTextColumn Header="Nr." Binding="{Binding Id}" />
                &lt;DataGridTextColumn Header="Datum" Binding="{Binding Date, StringFormat={}{0:dd.MM.yy HH:mm}}" />
            &lt;/DataGrid.Columns>
        &lt;/DataGrid></pre>



<h3 class="wp-block-heading">Automatische Spalten-Generierung deaktivieren</h3>



<p>Das Ganze sieht dann nun wie gleich folgend aus. Wie Du sicherlich sehen wirst, haben wir das Problem, dass nun 4 Spalten sichtbar sind. Das liegt daran, dass das DataGrid nach wie vor die Spalten generiert, dies müssen wir deaktivieren!</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/DataGrid-mit-manuellen-Spalten-–-WPF-DataGrid-MVVM-Beispiel.png"><img loading="lazy" decoding="async" width="333" height="135" src="https://robbelroot.de/wp-content/uploads/2022/12/DataGrid-mit-manuellen-Spalten-–-WPF-DataGrid-MVVM-Beispiel.png" alt="DataGrid mit manuellen Spalten – WPF DataGrid MVVM Beispiel" class="wp-image-13228" title="DataGrid mit manuellen Spalten – WPF DataGrid MVVM Beispiel"/></a><figcaption class="wp-element-caption">DataGrid mit manuellen Spalten – WPF DataGrid MVVM Beispiel</figcaption></figure>



<p>Die automatische Generierung der Spalten deaktivierst Du mit der <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.controls.datagrid.autogeneratecolumns?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener">&#8222;AutoGenerateColumns&#8220;-Eigenschaft</a></strong> des WPF DataGrids. Mit ausgeschalteter Spalten-Generierung sieht es dann final so aus:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/Ausgeschaltete-Spaltengenerierung.png"><img loading="lazy" decoding="async" width="168" height="124" src="https://robbelroot.de/wp-content/uploads/2022/12/Ausgeschaltete-Spaltengenerierung.png" alt="Ausgeschaltete Spaltengenerierung" class="wp-image-13232" title="Ausgeschaltete Spaltengenerierung"/></a><figcaption class="wp-element-caption">Ausgeschaltete Spaltengenerierung</figcaption></figure>



<p>Selbstverständlich hält Dich auch hier nichts davon ab, die &#8222;Header&#8220;-Eigenschaft zu binden und dynamischen Inhalt wie z. B. Übersetzungen darzustellen.</p>



<h2 class="wp-block-heading">Die Datengebundene Liste befüllen</h2>



<p>Nachdem wir nun alle Vorbereitungen soweit abgeschlossen haben, kümmern wir uns um die eigentlichen Rechnungen. Einerseits werden wir hierfür eine passende Art von Liste erstellen und zusätzlich befüllen. Leider reicht eine normale Liste, also eine gängige &#8222;List(Of T) &amp; List&lt;T&gt;&#8220; nicht aus, da Diese keine Änderungen kommunizieren kann.</p>



<h3 class="wp-block-heading">Kommunizieren von Listen-Änderungen</h3>



<p>Für gewöhnlich nimmt man hier die &#8222;ObservableCollection&#8220;, bzw. einen Listen-Typ, Welcher die <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.collections.specialized.inotifycollectionchanged?view=net-7.0" target="_blank" rel="noreferrer noopener">&#8222;INotifyCollectionChanged&#8220;-Schnittstelle</a></strong> implementiert. Elemente, Welche Listen-Änderungen an das gebundene Steuerelement kommunizieren möchten, können diese Schnittstelle implementieren. Um dies zu tun, lösen die implementierenden Klassen das &#8222;CollectionChanged&#8220;-Ereignis aus.</p>



<h3 class="wp-block-heading">MainViewModel erweitern</h3>



<p>Nun fügen wir dem &#8222;MainViewModel&#8220; die passende Eigenschaft hinzu. Beachte, dass ich hier nur einen &#8222;Getter&#8220; definiere, da wir die Liste nicht mehrfach setzen werden. Wir instanziieren Diese nur einmal im Konstruktor und befüllen Sie anschließend bei Bedarf mit Daten. Natürlich können wir die Liste auch zu passenden Zeitpunkten leeren.</p>



<p>Nach der Instanziierung der Liste fügen wir noch ein paar Einträge (natürlich in Form von Rechnungen) hinzu.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="collectionchanged-liste">using System.Collections.ObjectModel;
using DataGridBindingBeispiel.Models;

namespace DataGridBindingBeispiel.ViewModels;

public class MainViewModel
{

    public ObservableCollection&lt;Bill> Bills { get; }

    public MainViewModel()
    {
        Bills = new ObservableCollection&lt;Bill>();
        Bills.Add(new Bill(1, DateTime.Now));
        Bills.Add(new Bill(2, DateTime.Now));
    }

}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="collectionchanged-liste">Imports System.Collections.ObjectModel
Imports DataGridBindingBeispiel.Models

Namespace DataGridBindingBeispiel.ViewModels

    Public Class MainViewModel

        Public ReadOnly Property Bills As ObservableCollection(Of Bill)

        Public Sub New()
            Bills = New ObservableCollection(Of Bill)()
            Bills.Add(new Bill(1, Date.Now))
            Bills.Add(new Bill(2, Date.Now))
        End Sub

    End Class

End Namespace</pre>



<p class="info-banner">&#x1f4a1; <strong>Hinweis</strong>: Wir benutzen die aufeinanderfolgenden &#8222;Add&#8220;-Aufrufe nur, weil es hier mehr oder weniger die Basis ist. In einem realen Projekt sollte man eine bessere Implementierung einer <strong>INotifyCollectionChanged</strong>-Schnittstelle verwenden, da jeder &#8222;Add&#8220;-Aufruf hier einmal &#8222;Hey, es hat sich was geändert&#8220; schreit. Dies ist natürlich völliger Quatsch! Schaue für eine beispielhafte Implementierung in den nächsten Abschnitt.</p>



<p>Im besten Fall sammelt man vorher einmal alle Items und fügt Diese in einem Schritt hinzu. Das hat den offensichtlichen Vorteil, dass die eigentliche (datengebundene) Liste nur ein einziges Mal &#8222;Hey, ich hab mich geändert&#8220; auslöst &#8211; statt 200x für 200 Einträge.. Dies könnte im ersten Schritt z. B. durch eine Art Service passieren, oder im Testfall wie folgt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="no-change-trigger-list">var list = new List&lt;Bill>();
// triggert kein CollectionChanged!
list.Add(new Bill(1, DateTime.Now));
// triggert auch kein CollectionChanged!
list.Add(new Bill(2, DateTime.Now));

// triggert CollectionChanged!!
// Achtung: Gibt es leider nicht standardmäßig!
Bills.AddRange(list);</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="no-change-trigger-list">Dim list = New List(Of Bill)()
' triggert kein CollectionChanged!
list.Add(New Bill(1, Date.Now))
' triggert auch kein CollectionChanged!
list.Add(New Bill(2, Date.Now))

' triggert CollectionChanged!!
' Achtung: Gibt es leider nicht standardmäßig!
Bills.AddRange(list)</pre>



<h2 class="wp-block-heading">Eine ObservableRangeCollection – AddRange zur Hand!</h2>



<p>Wie im vorherigen Abschnitt erwähnt, gibt es Performance und – naja es fühlt sich halt nicht richtig an – Sauberkeits-Probleme, wenn wir die normale &#8222;ObservableCollection&#8220; verwenden. Sie triggert für jeden hinzugefügten oder gelöschten Eintrag das &#8222;CollectionChanged&#8220;-Ereignis, was blöd ist, wenn das 200x in wenigen Millisekunden passiert.</p>



<p>Daher kannst Du Dich an folgender Klasse orientieren, Welche eine &#8222;AddRange&#8220;-Methode anbietet. Diese triggert das &#8222;CollectionChanged&#8220;-Ereignis bei der Verwendung der Methode nur ein einziges Mal! Google dazu am besten einfach mal nach &#8222;ObservableRangeCollection&#8220;.</p>



<h2 class="wp-block-heading">Mit ausgewähltem Item arbeiten</h2>



<p>Jetzt, wo die Liste an sich erstmal funktioniert, kümmern wir uns im letzten Schritt um eine weitere wichtige Funktionalität: Die Auswahl eines Eintrages. Hierbei spielt es natürlich auch eine Rolle, ob wir den Eintrag aus dem Code, bzw. durch die UI heraus setzen. Also, grundsätzlich zumindest, wir können es uns aber ziemlich einfach machen, da wir mit Zweiwege-Datenbindungen arbeiten.</p>



<p>Bevor wir das allerdings ans Laufen bekommen, fehlt vorher noch eine weitere Sache. Auch hierbei wäre es wieder ratsam, wenn Du Dir zum tieferen Verständnis <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/" target="_blank" rel="noreferrer noopener">meinen Beitrag über die &#8222;INotifyPropertyChanged&#8220;-Schnittstelle</a> </strong>anschaust.</p>



<h3 class="wp-block-heading">Das PropertyChangedBase-Helferlein</h3>



<p>Der Einfachheit halber, werden wir von der dort gezeigten &#8222;PropertyChangedBase&#8220;-Klasse erben. Diese Klasse vereinfacht uns das Auslösen des &#8222;PropertyChanged&#8220;-Ereignisses, Welches der grafischen Oberfläche alles Notwendige signalisiert. Kopiere Dir die Klasse daher gerne in einen &#8222;Utils&#8220;-Ordner und packe Sie in den entsprechenden Namespace:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="PropertyChangedBase.cs" data-enlighter-group="property-changed-base">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;
    }
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="PropertyChangedBase.vb" data-enlighter-group="property-changed-base">Imports System.ComponentModel
Imports System.Runtime.CompilerServices

Namespace Utils

    Public MustInherit Class PropertyChangedBase
        Implements INotifyPropertyChanged

        Protected Sub NotifyOfPropertyChange(&lt;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</pre>



<p class="info-banner">&#x1f4a1; <strong>Hinweis</strong>: Lasse nun Dein &#8222;MainViewModel&#8220; von dieser Basis-Klasse erben, oder implementiere das &#8222;INotifyPropertyChanged&#8220;-Interface manuell!</p>



<h3 class="wp-block-heading">Eine SelectedBill-Eigenschaft</h3>



<p>Füge im nächsten Schritt nun eine &#8222;SelectedBill&#8220;-Eigenschaft im ViewModel hinzu. Diese erlaubt uns die Datenbindung der ausgewählten Rechnung aus dem Datagrid. Das schöne ist, es funktioniert in beide Richtungen! Bedenke hier, dass Du das oben im blauen Hinweis angegebene Interface implementierst, oder von meine Beispiel-Basisklasse erbst!</p>



<p>Die &#8222;SelectedBill&#8220;-Eigenschaft hat hier einen speziellen &#8222;Setter&#8220;. Falls der sich hinter dem Feld befindliche Wert nicht von dem via &#8222;Setter&#8220; übermittelte Wert unterscheiden sollte, springen wir heraus. Warum sollten wir auch &#8222;es hat sich was geändert&#8220; auslösen, wenn dem nicht so ist. Wenn sich allerdings was geändert hat, kommunizieren wir dies via &#8222;PropertyChanged&#8220;-Ereignis nach außen.</p>



<p>Somit können alle interessierten Objekte auf ihre Art – wie das DataGridView – darauf reagieren.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="selected-bill-eigenschaft">using System.Collections.ObjectModel;
using DataGridBindingBeispiel.Models;
using DataGridBindingBeispiel.Utils;

namespace ViewModels
{
    public class MainViewModel : PropertyChangedBase
    {
        public ObservableCollection&lt;Bill> Bills { get; set; }

        private Bill _selectedBill;

        public Bill SelectedBill
        {
            get
            {
                return _selectedBill;
            }
            set
            {
                if (_selectedBill == value)
                    return;
                _selectedBill = value;
                NotifyOfPropertyChange();
            }
        }

        public MainViewModel()
        {
            Bills = new ObservableCollection&lt;Bill>();
            Bills.Add(new Bill(1, DateTime.Now));
            Bills.Add(new Bill(2, DateTime.Now));
        }
    }
}</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="selected-bill-eigenschaft">Imports System.Collections.ObjectModel
Imports DataGridBindingBeispiel.Models
Imports DataGridBindingBeispiel.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        Public Property Bills As ObservableCollection(Of Bill)

        Private _selectedBill As Bill

        Public Property SelectedBill As Bill
            Get
                Return _selectedBill
            End Get
            Set(value As Bill)
                If _selectedBill Is value Then
                    Return
                End If
                _selectedBill = value
                NotifyOfPropertyChange()
            End Set
        End Property

        Sub New()
            Bills = New ObservableCollection(Of Bill)()
            Bills.Add(New Bill(1, Date.Now))
            Bills.Add(New Bill(2, Date.Now))
        End Sub

    End Class

End Namespace</pre>



<p class="info-banner">&#x1f4a1; <strong>Hinweis</strong>: Wenn Du eine Standard-Auswahl, bzw. eine Auswahl aus dem Code heraus treffen möchtest, kannst Du der Eigenschaft einfach einen Wert zuweisen.</p>



<p>Das Setzen der ausgewählten Rechnung aus dem Code heraus könnte so aussehen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="select-default-bill">// zweite Rechnung standardmäßig auswählen
SelectedBill = Bills[1];</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="select-default-bill">' zweite Rechnung standardmäßig auswählen
SelectedBill = Bills(1)</pre>



<h3 class="wp-block-heading">Datenbindung anpassen</h3>



<p>Final können wir nun noch einmal in den XAML-Code gehen, um die bisherige Datenbindungen des DataGrids zu verändern. Bisher weiß das WPF DataGrid natürlich nichts von der &#8222;SelectedBill&#8220;-Eigenschaft in unserem Viewmodel. Dies ändern wir nun mit der folgenden Bindung an die &#8222;SelectedItem&#8220;-Eigenschaft des Datagrids:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainWindow.xaml" data-enlighter-group="">&lt;!-- restlicher MainWindow.xaml Code.. -->

&lt;DataGrid ItemsSource="{Binding Bills}" SelectedItem="{Binding SelectedBill}" AutoGenerateColumns="False">
    &lt;DataGrid.Columns>
        &lt;DataGridTextColumn Header="Nr." Binding="{Binding Id}" />
        &lt;DataGridTextColumn Header="Datum" Binding="{Binding Date, StringFormat={}{0:dd.MM.yy HH:mm}}" />
    &lt;/DataGrid.Columns>
&lt;/DataGrid>

&lt;!-- restlicher Code.. --></pre>
<p>Der Beitrag <a href="https://robbelroot.de/blog/der-ultimative-wpf-datagrid-mvvm-guide-csharp-und-vb-net/">Der ultimative WPF DataGrid MVVM Guide in 2026 – C# &amp; VB.NET</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/der-ultimative-wpf-datagrid-mvvm-guide-csharp-und-vb-net/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
