Blazor WebAssembly nutzt eine komponentenbasierte Architektur, bei der jede Benutzeroberfläche als eigenständige Komponente implementiert wird. Eine Komponente ist in der Regel eine .razor-Datei, die von der abstrakten Basisklasse ComponentBase erbt. Diese Klasse stellt eine Reihe von Methoden bereit, die das Lebenszyklusverhalten einer Komponente steuern, und sie ist zentral für das Verständnis, wie Blazor-Komponenten aufgebaut und miteinander verbunden sind.

ComponentBase definiert Methoden wie OnInitialized, OnParametersSet, OnAfterRender sowie deren asynchrone Gegenstücke. Diese Methoden können überschrieben werden, um benutzerdefinierte Logik beim Initialisieren, bei der Parameterübernahme oder nach dem Rendern auszuführen. Die Methode ShouldRender gibt an, ob eine Komponente erneut gerendert werden soll. Mit StateHasChanged lässt sich ein erneutes Rendern manuell auslösen.

Eine wichtige Eigenschaft der Komponentenarchitektur in Blazor ist, dass der gesamte Renderprozess innerhalb eines einzigen Synchronisierungskontexts stattfindet. Dadurch wird sichergestellt, dass der Zugriff auf gemeinsam genutzte Ressourcen thread-sicher bleibt. Methoden wie InvokeAsync ermöglichen die Ausführung von Logik im Synchronisierungskontext des Renderers, ohne dass explizite Thread-Synchronisierung erforderlich ist.

Layouts sind ein weiteres zentrales Konzept in Blazor. Sie ermöglichen die Wiederverwendung von Benutzeroberflächenstrukturen, ähnlich wie bei MVC-Views oder Razor Pages. Ein Layout ist eine Komponente, die von LayoutComponentBase erbt. Diese Klasse stellt die Eigenschaft Body zur Verfügung, die angibt, wo der Inhalt der eingebetteten Komponente angezeigt werden soll. Über die Direktive @layout kann eine Komponente explizit ein Layout zugewiesen bekommen. Alternativ kann über die App.razor-Datei ein Standardlayout für alle Komponenten gesetzt werden.

Für die Navigation innerhalb einer Blazor-Anwendung stellt das Framework die Dienstklasse NavigationManager zur Verfügung. Sie bietet unter anderem die Methode NavigateTo, mit der programmatisch zu einer bestimmten URL navigiert werden kann. Die Navigation über die Benutzeroberfläche erfolgt typischerweise über das NavLink-Element, das gegenüber einem regulären HTML-Ankerelement (<a>) den Vorteil bietet, automatisch eine aktive CSS-Klasse zu setzen, wenn die Ziel-URL mit der aktuellen URL übereinstimmt.

Diese automatische Klassenzuweisung ermöglicht eine visuelle Hervorhebung des aktuellen Navigationspunkts. Das Matching-Verhalten lässt sich über den Parameter Match konfigurieren. Standardmäßig arbeitet Blazor mit Präfix-Matching, sodass ein Link mit dem Pfad /employees auch auf /employees/UK/London reagiert. Um eine exakte Übereinstimmung zu erzwingen, kann Match="NavLinkMatch.All" gesetzt werden.

Beim Arbeiten mit typisierten URL-Parametern ist es essenziell, die richtige Formatierung gemäß der Invariant Culture zu verwenden, da Blazor-Routen keine lokalisierte Formatierung unterstützen. Beispielsweise müssen Datumsangaben in einem kulturunabhängigen Format erfolgen, etwa 2025-09-24T12:34:56. Routenparameter in Blazor können an Typen wie datetime, decimal, double, float, guid, int oder long gebunden werden. Dabei ist es wichtig, dass übergebene Werte gültig sind, da Blazor ansonsten die Route nicht als gültig interpretiert. Die präzise Definition der Parameter im Routenattribut erhöht die Robustheit der Anwendung.

Mit der Einführung von ASP.NET Core 7 wurden neue Projektvorlagen für Blazor WebAssembly bereitgestellt, die eine minimalistische Ausgangsbasis bieten. Beim Erstellen eines Blazor WebAssembly-Projekts wird standardmäßig eine Lösung mit drei Teilprojekten generiert: ein Client-Projekt (.Client), ein Server-Projekt (.Server) und ein Shared-Projekt (.Shared). Das Client-Projekt kann unabhängig bereitgestellt werden, während das Server-Projekt typischerweise als Host dient und zudem serverseitige APIs oder Dienste bereitstellen kann. Im Shared-Projekt können gemeinsam genutzte Typen definiert werden, z. B. DTOs oder Validierungslogik, was die Wiederverwendbarkeit und Konsistenz im Code erhöht.

Die Konfiguration des Servers erfolgt zentral in der Program.cs. Hier wird u. a. die Middleware aktiviert, die es ermöglicht, Razor Pages und MVC-Controller parallel zur Blazor-App zu verwenden. Außerdem wird die Auslieferung der statischen Blazor-Framework-Dateien über UseBlazorFrameworkFiles() sichergestellt, und über MapFallbackToFile("index.html") wird eine Fallback-Route definiert, die alle nicht abgefangenen Anfragen an die Blazor-App weiterleitet.

Ein entscheidender Aspekt der Entwicklung mit Blazor WebAssembly ist die klare Trennung zwischen Client und Server bei gleichzeitiger Möglichkeit zur gemeinsamen Nutzung von Logik. Diese Struktur erleichtert den Aufbau skalierbarer Anwendungen mit sauber definierten Schnittstellen. Zudem kann durch die Verwendung des PWA-Modus (--pwa) eine Offline-Funktionalität implementiert werden, was die Nutzererfahrung auf mobilen Geräten deutlich verbessert.

Wichtig ist dabei auch die Konfiguration der Entwicklungsumgebung. In der Datei launchSettings.json werden unter anderem Umgebungsvariablen wie ASPNETCORE_ENVIRONMENT gesetzt sowie die verwendeten Ports für HTTP und HTTPS definiert. Während der Entwicklung sorgt die Aktivierung von UseWebAssemblyDebugging() dafür, dass Entwickler das Debugging direkt im Browser durchführen können.

Was in der alltäglichen Arbeit mit Blazor oft übersehen wird, ist die Notwendigkeit eines konsistenten Zustandsmanagements über Komponenten hinweg. Gerade weil Blazor-Apps im Browser laufen, muss besonders sorgfältig mit gemeinsam genutztem Zustand umgegangen werden, etwa bei Authentifizierung, API-Kommunikation oder komplexen Benutzerinteraktionen. Auch das Zusammenspiel mit JavaScript erfordert klare Abgrenzungen und sauber definierte Schnittstellen, um die Vorteile beider Welten optimal zu nutzen.

Wie funktioniert das Caching von Web-Komponenten mit Blazor und Local Storage?

Der Umgang mit Daten in modernen Webanwendungen erfordert effiziente Strategien zum Abruf und zur Zwischenspeicherung, um Leistung und Nutzererfahrung zu optimieren. Ein zentrales Szenario zeigt sich beim Laden von Mitarbeiterdaten in einer Blazor WebAssembly-Anwendung. Die Komponente lädt über einen Webdienst Daten und stellt sie in einer Grid-Darstellung dar, die sortiert und gefiltert werden kann – beispielsweise nach Geburtsdatum oder geografischem Standort.

Aktuell wird beim Navigieren zwischen Seiten der Webdienst jedes Mal neu aufgerufen, weil die Daten nur im Arbeitsspeicher der Komponente gehalten werden, deren Lebenszeit auf die jeweilige Seite begrenzt ist. Um diese ständigen Netzwerkaufrufe zu vermeiden und eventuell auch Offline-Funktionalitäten zu ermöglichen, kommt das Caching im lokalen Speicher des Browsers (local storage) zum Einsatz.

Lokaler Speicher ist ein persistenter Speicher, der über Tabs und Browser-Sessions hinweg für die jeweilige Domain erhalten bleibt. Anders als Session Storage, der nur für die Dauer einer Browser-Session verfügbar ist, bietet local storage eine dauerhafte Datenhaltung, was für Webanwendungen mit häufigen Datenabrufen oder Offline-Unterstützung entscheidend ist. Da local storage nur String-Werte speichern kann, ist die Serialisierung und Deserialisierung von Daten erforderlich.

Blazor selbst hat keinen direkten Zugriff auf Browser-APIs wie local storage. Hier wird das Konzept der JavaScript-Interop verwendet: Über das Interface IJSRuntime können JavaScript-Module dynamisch importiert und Funktionen asynchron aufgerufen werden. Dabei wird ein JavaScript-Modul erstellt, das Wrapper-Funktionen für den Zugriff auf local storage bereitstellt – beispielsweise zum Lesen (get), Schreiben (set), Löschen einzelner Einträge (remove) und Leeren des Speichers (clear). Diese Funktionen sind per ES6-Module exportiert und damit von Blazor einfach ladbar.

Um die Interaktion elegant in die Blazor-Komponenten zu integrieren, wird eine dedizierte Service-Klasse implementiert, die IJSRuntime injiziert bekommt und Methoden zum asynchronen Arbeiten mit local storage kapselt. Dieser Service nutzt Lazy-Initialisierung für das JavaScript-Modul und implementiert das Interface IAsyncDisposable, um Ressourcen nach Gebrauch ordnungsgemäß freizugeben.

Die Mitarbeiterkomponente speichert die erhaltenen Daten als JSON im local storage mit einem Zeitstempel. Beim erneuten Aufruf prüft sie, ob die zwischengespeicherte Version innerhalb einer konfigurierbaren Cache-Dauer liegt. Ist dies der Fall, wird die lokale Kopie genutzt und ein erneuter Webdienstaufruf vermieden. Andernfalls wird der Webdienst neu kontaktiert und die Daten aktualisiert. Dieses Vorgehen verbessert die Reaktionsfähigkeit der Anwendung, reduziert Serverlast und ermöglicht perspektivisch Offline-Funktionalität.

Für Blazor-Entwickler ist es wichtig zu verstehen, dass Interop mit JavaScript zwar mächtig, aber auch asynchron und mit einer gewissen Komplexität verbunden ist. Das korrekte Laden, Verwenden und Freigeben von Modulen ist essentiell, um Speicherlecks zu vermeiden. Die Wahl zwischen Session Storage und local storage richtet sich nach Anforderungen an Persistenz und Scope der Daten.

Die Serialisierung der Daten sollte immer mit Bedacht erfolgen, um Inkonsistenzen zu vermeiden, insbesondere bei komplexeren Datenstrukturen. Ebenso ist die Behandlung von Fehlerfällen beim Zugriff auf local storage relevant, da Nutzer z. B. im Inkognito-Modus oder mit restriktiven Browser-Einstellungen Einschränkungen erfahren können.

Zudem ist es bedeutsam, die Grenzen des local storage zu kennen – typischerweise 5 bis 10 MB pro Domain –, um zu verhindern, dass umfangreiche Datenmengen die Speichergrenze überschreiten und Zugriffe fehlschlagen.

Das vorgestellte Konzept zeigt exemplarisch, wie moderne Webkomponenten performant und benutzerfreundlich gestaltet werden können, indem sie die Stärken von Blazor mit nativen Browsertechnologien sinnvoll kombinieren.

Wie installiert und verwendet man .NET MAUI in Visual Studio 2022 für Windows und Mac?

Um mit der Entwicklung von .NET MAUI-Anwendungen zu beginnen, muss zunächst Visual Studio 2022 für Windows oder Mac installiert werden. Im Allgemeinen werden die notwendigen .NET MAUI-Workloads automatisch während der Installation von Visual Studio 2022 eingerichtet. Sollte es später zu Fehlern kommen, ist es jedoch möglich, die Workloads manuell zu installieren oder sicherzustellen, dass alle benötigten Workloads korrekt installiert sind.

Zur Überprüfung der aktuell installierten Workloads kann der folgende Befehl verwendet werden:
dotnet workload list
Dieser Befehl zeigt alle installierten Workloads in einer Tabelle an, beispielsweise:

markdown
Installed Workload Ids Manifest Version Installation Source --------------------------------------------------------------- maui-maccatalyst 6.0.486/6.0.400 SDK 7.0.100

Um die verfügbaren Workloads anzuzeigen, die noch installiert werden können, verwendet man den Befehl:
dotnet workload search
Die verfügbaren Workloads werden ebenfalls in einer Tabelle angezeigt, z. B.:

markdown
Workload ID Description -------------------------------------------------------------- android .NET SDK Workload für Android-Anwendungen ios .NET SDK Workload für iOS-Anwendungen maccatalyst .NET SDK Workload für macOS-Anwendungen maui .NET MAUI SDK für alle Plattformen

Falls alle benötigten Workloads für eine .NET MAUI-Anwendung noch nicht installiert sind, kann man mit dem folgenden Befehl das MAUI SDK für alle Plattformen installieren:
dotnet workload install maui
Um bereits installierte Workloads zu aktualisieren, wird der Befehl dotnet workload update genutzt. Falls zusätzliche Workloads für ein Projekt benötigt werden, kann man mit dotnet workload restore diese nachträglich installieren.

Ein besonderes Augenmerk sollte darauf gelegt werden, dass für die Entwicklung von iOS- und macOS-Anwendungen Visual Studio 2022 für Windows nur dann ausreichend ist, wenn man über eine Netzwerkverbindung zu einem Mac Build Host verfügt. Eine detaillierte Anleitung zur Verbindung zwischen Windows und einem Mac Build Host ist auf der offiziellen Microsoft-Website zu finden.

Die .NET MAUI bietet eine Vielzahl an UI-Komponenten, die die Entwicklung plattformübergreifender Anwendungen erleichtern. Diese Komponenten lassen sich in vier Hauptkategorien unterteilen:

  • Pages repräsentieren die Bildschirme der Anwendung, etwa Shell, ContentPage, NavigationPage, FlyoutPage und TabbedPage.

  • Layouts strukturieren die Anordnung von UI-Komponenten, wie z. B. Grid, StackLayout und FlexLayout.

  • Views stellen einzelne UI-Komponenten dar, wie z. B. CarouselView, CollectionView, Label, Entry, Editor und Button.

  • Cells repräsentieren einzelne Elemente in Listen oder Tabellenansichten, etwa TextCell, ImageCell, SwitchCell und EntryCell.

Ein herausragendes Steuerelement in .NET MAUI ist das Shell-Control, das die App-Entwicklung durch standardisierte Navigations- und Suchfunktionen vereinfacht. Wenn man das Shell-Control verwendet, erstellt man eine Klasse, die von der Shell-Klasse erbt. Diese abgeleitete Klasse definiert Komponenten wie TabBar, die Tab-Elemente enthalten, und FlyoutItem-Instanzen, die die Navigation auf der linken Seite ermöglichen. Diese Struktur sorgt für eine einfache Handhabung der Navigation, insbesondere bei Anwendungen mit vielen Seiten, die in einer vertikal scrollbaren Liste angezeigt werden können.

Die ListView-Kontrolle ist für das Arbeiten mit langen Listen von Daten vorgesehen und kann Gruppierungen sowie Header und Footer umfassen. In der ListView können Benutzer mit Hilfe von Kontextaktionen interagieren. Diese Aktionen erscheinen bei einer bestimmten Interaktion (z. B. Wischen oder Rechtsklick), wodurch Entwickler die Möglichkeit haben, benutzerdefinierte, plattformspezifische Funktionen zu implementieren.

Die Entry- und Editor-Kontrollen dienen der Texteingabe und sind häufig an Modelle gebunden, um Benutzereingaben zu verarbeiten. Dabei wird die Entry-Kontrolle für einzeilige Texte verwendet, während die Editor-Kontrolle für mehrzeilige Texte vorgesehen ist.

Ein weiterer wichtiger Aspekt in .NET MAUI ist das Konzept der Handler, die dafür sorgen, dass XAML-basierte Controls auf den nativen Steuerungen der jeweiligen Plattformen abgebildet werden. So wird ein .NET MAUI-Button beispielsweise auf iOS zu einem UIButton, auf macOS zu einem NSButton und auf Android zu einem AppCompatButton. Dies ermöglicht es Entwicklern, plattformspezifische Features zu nutzen und zu erweitern, indem sie auf die nativen Eigenschaften und Methoden der Steuerungen zugreifen.

Für die Entwicklung plattformspezifischer Logik bietet .NET MAUI die Möglichkeit, Compiler-Direktiven zu verwenden. Diese Direktiven ermöglichen es, Code zu schreiben, der nur auf einer bestimmten Plattform ausgeführt wird. Zum Beispiel könnte ein Entwickler auf Android das Verhalten einer Entry-Kontrolle anpassen, indem er auf die native Ansicht zugreift und eine spezifische Eigenschaft wie das Entfernen der Unterstreichung einstellt. Dies geschieht durch spezielle Compiler-Direktiven wie #if __ANDROID__.

Es ist wichtig, darauf hinzuweisen, dass die Nutzung von .NET MAUI nicht nur auf Windows und macOS beschränkt ist. Die Plattformübergreifende Entwicklung ist ein wesentlicher Vorteil, da Entwickler mit einer einzigen Codebasis Anwendungen für Android, iOS, Windows und macOS erstellen können. Wenn ein Entwickler jedoch spezifische Funktionen einer Plattform verwenden möchte, ist es notwendig, mit plattformspezifischem Code zu arbeiten, der über die Handler und Compiler-Direktiven angepasst wird.

Für eine erfolgreiche Nutzung von .NET MAUI sollte zudem beachtet werden, dass für das Testen und Entwickeln auf macOS das Xcode-Tool auf einem Mac installiert und ausgeführt werden muss, um sicherzustellen, dass alle erforderlichen Komponenten vorhanden sind.

Wie funktioniert die dynamische Codeausführung und was können wir mit Reflection und Expression Trees erreichen?

Die dynamische Ausführung von Code ist eine mächtige Funktion, die es uns ermöglicht, Assemblies zur Laufzeit zu laden und auszuführen. Dies geht weit über das einfache Aufrufen von Methoden hinaus und erlaubt es, den Code während der Ausführung zu inspizieren und zu verändern. Reflection und Expression Trees sind zwei Konzepte, die hierfür verwendet werden und die es ermöglichen, die Struktur und das Verhalten von Programmen zur Laufzeit zu analysieren und anzupassen.

Ein Beispiel für die Verwendung von Reflection ist das Laden und Ausführen von Assemblies. In einem Beispiel wird eine Konsole angewendet, die die Assembly DynamicLoadAndExecute.Console lädt. Diese Assembly lädt wiederum eine andere, nämlich DynamicLoadAndExecute.Library. Es wird auch ein wichtiges Konzept angesprochen: der Unterschied zwischen sammelbaren und nicht-sammelbaren Assemblies. Während DynamicLoadAndExecute.Console.dll nicht sammelbar ist (es kann nicht aus dem Arbeitsspeicher entfernt werden), ist DynamicLoadAndExecute.Library.dll sammelbar. Dies hat Auswirkungen auf das Management der Ressourcen während der Ausführung und der Speicherbereinigung. Eine solche Dynamik ist besonders dann wichtig, wenn es um die Optimierung von Speicher und Performance geht.

Neben dem Laden von Assemblies und der Verwaltung von Kontexten bietet Reflection weitere interessante Möglichkeiten. Sie ermöglicht etwa die Inspektion von Metadaten einer Assembly oder das dynamische Erzeugen von neuen Codeeinheiten zur Laufzeit. Mit der Klasse MetadataLoadContext kann man zum Beispiel die Inhalte einer Assembly inspizieren. Dies geht weit über die Möglichkeit hinaus, lediglich zur Entwicklungszeit auf Code zuzugreifen, und ermöglicht eine tiefere Interaktion mit der Programmausführung, die während der Laufzeit sogar modifiziert werden kann. Auch die Möglichkeit, mit System.Reflection.Emit.AssemblyBuilder dynamisch neue Assemblies zu erstellen, erweitert den Funktionsumfang dieser Technik erheblich.

Ein weiteres mächtiges Werkzeug in der dynamischen Codebearbeitung sind Expression Trees. Expression Trees repräsentieren Code nicht mehr als eine Liste von Anweisungen, sondern als eine Datenstruktur, die man während der Ausführung untersuchen und verändern kann. Dies ist besonders wertvoll für Szenarien, in denen der Code zur Laufzeit angepasst werden muss, ohne dass der gesamte Quellcode geändert wird. Expression Trees sind nicht veränderbar, aber es können Kopien erstellt werden, die Veränderungen enthalten.

Das Arbeiten mit Expression Trees ist sehr flexibel, da man die Logik eines Codes als Datenstruktur in Form von Ausdrücken manipulieren kann. Ein einfaches Beispiel ist die Addition von zwei Zahlen. In einem solchen Fall würde der Ausdruck 1 + 2 als Baumstruktur dargestellt werden, die dann zur Berechnung genutzt werden kann. Der Vorteil von Expression Trees zeigt sich aber erst in komplexeren Szenarien, in denen dynamische Berechnungen und Entscheidungen erforderlich sind.

Ein noch fortgeschritteneres Konzept ist das Arbeiten mit LINQ (Language Integrated Query) in Verbindung mit Expression Trees. Wenn man eine LINQ-Abfrage schreibt, beispielsweise um mit einer Datenbank zu interagieren, wird der C#-Code intern als Expression Tree gespeichert. Dieser wird dann durch ein zugrunde liegendes System, etwa Entity Framework, in eine SQL-Abfrage übersetzt. Dies ermöglicht eine enorme Flexibilität, weil der Code auf einer abstrakten Ebene repräsentiert wird, die dann in andere Formate umgewandelt werden kann.

Ein weiterer fortschrittlicher Mechanismus, der zur dynamischen Codegenerierung genutzt werden kann, sind Source Generatoren. Source Generatoren wurden mit C# 9 und .NET 5 eingeführt und bieten eine Möglichkeit, zur Kompilierzeit zusätzlichen Code zu generieren. Dabei handelt es sich um eine Form der Codeanalyse, bei der der Compiler Quellcode basierend auf vorab definierten Regeln automatisch erzeugt. Ein gängiges Beispiel für den Einsatz von Source Generatoren ist die Serialisierung von JSON. Das Standardverfahren verwendet Reflection zur Laufzeit, um Objekte zu analysieren, was jedoch relativ langsam ist. Source Generatoren ermöglichen es, diese Analyse vorab durchzuführen, sodass der Code schneller ausgeführt werden kann. Die System.Text.Json-Bibliothek nutzt solche Generatoren, um die Performance erheblich zu steigern.

Für das Verständnis von Source Generatoren ist es wichtig, zu wissen, dass sie die Möglichkeit bieten, Code zur Kompilierzeit hinzuzufügen, was wiederum die Flexibilität der Anwendung erhöht. Ein einfaches Beispiel dafür ist das automatische Hinzufügen von Methoden zu bestehenden Klassen, wie im Fall der Program-Klasse, wo durch einen Source Generator eine Methode zur Ausgabe von Nachrichten hinzugefügt wird.

Es ist von entscheidender Bedeutung, dass Source Generatoren in Projekten korrekt eingebunden werden. Dabei muss darauf geachtet werden, dass die Zielplattform und die verwendete C#-Version korrekt konfiguriert sind. Ein Beispiel dafür ist das Setzen der C#-Version auf 10 oder später, um moderne Sprachfunktionen wie globale Using-Direktiven zu unterstützen. Zudem müssen zusätzliche NuGet-Pakete eingebunden werden, um die erforderliche Funktionalität zu gewährleisten.

Die Möglichkeit, den Code zur Laufzeit zu manipulieren, bietet enorme Vorteile, da sie eine weitreichende Anpassung von Programmen ermöglicht, ohne die gesamte Codebasis ändern zu müssen. Dennoch ist es wichtig, bei der Arbeit mit Reflection und Expression Trees vorsichtig zu sein, da diese Mechanismen auch die Performance eines Programms beeinträchtigen können, wenn sie nicht effizient genutzt werden. Das dynamische Generieren von Code kann zudem dazu führen, dass der Überblick über den Code verloren geht, wenn nicht sorgfältig dokumentiert wird, welche Teile des Codes dynamisch hinzugefügt oder verändert werden.

Wie funktioniert die Entwicklung von mobilen und Desktop-Anwendungen mit .NET MAUI?

.NET MAUI (Multi-platform App UI) ist ein moderner Ansatz zur plattformübergreifenden Entwicklung, der es ermöglicht, mit einer einzigen Codebasis native Apps für iOS, Android, Windows und macOS zu erstellen. Die Technologie baut auf dem etablierten Xamarin.Forms auf und erweitert dessen Möglichkeiten, um die komplexen Anforderungen moderner mobiler und Desktop-Anwendungen besser zu erfüllen. Zentral für die Entwicklung mit .NET MAUI ist die Verwendung von XAML (Extensible Application Markup Language), das eine klare Trennung von Benutzeroberfläche und Logik ermöglicht und den Code dadurch wartbarer und übersichtlicher macht. XAML vereinfacht die Definition von UI-Komponenten durch deklarative Syntax, unterstützt Typkonverter und Markup-Erweiterungen, die das Binden von Daten und Ressourcen erleichtern.

Das Framework stellt eine Vielzahl von UI-Steuerelementen zur Verfügung, darunter Shell zur Navigation, ListView für die Darstellung von Listen und Entry- sowie Editor-Komponenten zur Texteingabe. Die .NET MAUI-Handler ersetzen das traditionelle Renderer-Konzept und optimieren die Performance und Anpassbarkeit der UI-Elemente auf den jeweiligen Plattformen. Eine Besonderheit ist die Möglichkeit, plattformspezifischen Code zu schreiben, um native Funktionalitäten gezielt einzubinden, was eine hohe Flexibilität gewährleistet.

Die Entwicklung erfolgt idealerweise mit modernen Tools wie Visual Studio, das eine umfangreiche Unterstützung für .NET MAUI bietet, inklusive Emulation von Android-Geräten und dem Windows-Entwicklermodus für lokale Tests. Die Architektur von .NET MAUI folgt dem MVVM-Muster (Model-View-ViewModel), das durch zwei-Wege-Datenbindung, ObservableCollections und das Interface INotifyPropertyChanged eine klare Trennung zwischen Benutzeroberfläche und Geschäftslogik fördert. Dies erleichtert nicht nur die Wartung, sondern auch das Testen der Anwendung.

Ein wesentlicher Aspekt ist die Nutzung gemeinsamer Ressourcen, die über die gesamte Anwendung hinweg referenziert und bei Bedarf dynamisch geändert werden können. Dadurch wird ein konsistentes Erscheinungsbild und Verhalten gewährleistet. Die Einbindung von Webservices ist nahtlos möglich und erlaubt es, datengetriebene Anwendungen zu realisieren, die lokale und entfernte Datenquellen nutzen. Das erlaubt etwa, Kundeninformationen dynamisch abzurufen und darzustellen.

Die Integration mit nativen Plattformfunktionen geht über reine UI-Komponenten hinaus. So können Funktionen wie das Clipboard, das Dateisystem oder Medienauswahl plattformübergreifend eingebunden werden, wobei jeweils spezifische Berechtigungen und Konfigurationen für iOS, Android und Windows berücksichtigt werden müssen. Ebenso ermöglicht .NET MAUI die Erstellung mehrerer Fenster und die Integration von Desktop-spezifischen UI-Elementen wie Menüleisten, was die Anwendungsvielfalt deutlich erhöht.

In der Praxis erfordert die Entwicklung mit .NET MAUI ein tiefes Verständnis der zugrundeliegenden Architektur, insbesondere der plattformübergreifenden Konzepte und der Unterschiede bei der Umsetzung nativer Features. Ein wichtiger Schritt ist die manuelle Installation und Konfiguration der erforderlichen Workloads, um die Zielplattformen effizient bedienen zu können. Dabei sind insbesondere Sicherheitsaspekte wie die erlaubte Kommunikation mit Webservices in Testumgebungen zu beachten.

Neben der technischen Umsetzung fördert .NET MAUI die produktive Zusammenarbeit durch die klare Strukturierung von Projekten und den Einsatz von Shared Projects und Ressourcen, was auch die Skalierbarkeit der Anwendungen verbessert. Für Entwickler, die bereits Erfahrung mit C# und .NET haben, stellt .NET MAUI eine natürliche Erweiterung dar, um moderne, plattformübergreifende Lösungen mit aktuellen Sprachfeatures und Bibliotheken zu realisieren.

Es ist wichtig, sich nicht nur mit der Oberfläche der Framework-Funktionalitäten zufrieden zu geben, sondern auch die zugrundeliegenden Konzepte wie MVVM, Datenbindung und Ressourcennutzung tiefgehend zu verstehen. Nur so lässt sich das volle Potenzial von .NET MAUI ausschöpfen und Anwendungen schaffen, die nicht nur optisch ansprechend, sondern auch performant, wartbar und erweiterbar sind. Zusätzlich sollte das Zusammenspiel mit nativen APIs und plattformspezifischen Eigenheiten von Anfang an mitgedacht werden, um unangenehme Überraschungen in späteren Entwicklungsphasen zu vermeiden.