Das DataGrid von Avalonia

Avalonia with DataGrid

Das auf .Net basierende Cross-Plattform UI Framework Avalonia verfügt über eine große Palette an Standard-Controls. Es ist vieles dabei, was man als Entwickler typischerweise braucht. So gibt es etwa diverse Eingabeboxen, Controls für Auflistungen und welche, über die das Layout beeinflusst werden kann. Wenn ich auf Business-Applikationen schaue, fällt mir zudem noch ein sehr wichtiges ein, welches Avalonia mitbringt: Das DataGrid. Die Aufgabe eines DataGrids besteht grundsätzlich darin, eine mehr oder weniger lange Liste von Objekten in tabellarischer Form darzustellen. Jede Zeile ist ein solches Objekt, jede Spalte bezieht sich auf eine Eigenschaft. Daneben gibt es typischerweise Anforderungen wie zum Beispiel Sortierung, Filterung oder Gruppierung. Das DataGrid in Avalonia liefert diese Features entweder direkt oder bringt sie über den kleinen Umweg einer CollectionView im ViewModel mit. In diesem Artikel möchte ich mich mit den Features beschäftigen, welche das DataGrid in Avalonia im Standard mitbringt und wie man diese verwendet.

Weiterlesen …

Hexagonale Architektur mit C#, .NET 6 und Blazor

Hexagonal

Zur Strukturierung von Software existiert eine Vielzahl von Architekturmustern. Unter dem Begriff Clean Architecture lassen sich mehrere davon zusammenfassen, welche sich zwar im Detail unterscheiden, beim Ziel allerdings auf das gleiche setzen: Trennung von Verantwortlichkeiten. Im Ideal wird dadurch eine Software erreicht, die sich langfristig einfach warten und erweitern lässt. In diesem Artikel möchte ich neben den allgemeinen Prinzipien der Clean Architecture ebenso anhand des Architekturmusters “Hexagonale Architektur“ ins Detail gehen. Über ein Praxisbeispiel werden wir einige Vor- und Nachteile dieser Vorgehensweise sehen. Das Beispiel verwendet C# / ASP.NET Core im Backend und APS.NET Core Blazor Webassembly im Frontend.

Weiterlesen …

Prozesse kontrolliert stoppen mit C#

Stop

C# bzw. .Net bieten von Haus aus ein Set an Methoden und Klassen, um mit anderen Prozessen zu interagieren. So ermöglicht beispielsweise die Klasse System.Diagnostics.Process das Starten und Überwachen von fremden Prozessen. Auch die Konsolenausgabe kann ebenso mit wenigen Handgriffen abgegriffen werden. Wenn es allerdings um das Stoppen eines Prozesses geht, stehen lediglich die Methoden Kill und CloseMainWindow zur Verfügung. Erstere ist sehr unsauber, sie schießt den Prozess direkt ab. Der betroffene Prozess hat somit keine Möglichkeit mehr, sich kontrolliert herunterzufahren. Letztere funktioniert nur für Applikationen mit einer Benutzeroberfläche und (vermutlich) auch nur für Windows. In diesem Artikel möchte ich Wege zeigen, um Prozesse kontrolliert stoppen zu können. Hierbei wird lediglich zwischen dem darunter liegenden Betriebssystem (Windows, Linux oder macOS) unterschieden.

Weiterlesen …

RingBuffer in C#

In .Net existiert eine Vielzahl von Klassen zur Auflistung von Objekten oder Strukturen. Ein einfaches und häufig verwendetes Beispiel ist die Array. Die List<T> ist ebenso stark verbreitet. Daneben gibt es eine Vielzahl von Klassen, welche diverse Spezialfälle abbilden. So etwa für parallelen Zugriff mit den Klassen aus dem Namespace System.Collections.Concurrent. Einen Spezialfall hätte ich allerdings schon häufiger vermisst: Den RingBuffer (oder auch Circular Buffer [1]). Ein RingBuffer dient dazu, eine fortlaufende Liste mit einer maximalen Länge abzubilden. Wenn über die maximale Länge hinaus geschrieben wird, so werden einfach die ältesten Elemente überschrieben. Gehen wir von der max. Länge von 100 aus. Wenn das 101. Element hinzugefügt wird, fliegt das erste Element raus. Dieses neue Element ist dann aber nicht der neue Start der Liste. Der Start der Liste ist immer das älteste Element. Wo benötigt man so ein Verhalten? Ein gutes Beispiel dazu habe ich in der 3D-Engine SeeingSharp. Zur Berechnung der durchschnittlichen FPS (Frames per Second bzw. Bilder pro Sekunde) wird der aktuelle FPS Wert je Sekunde berechnet und an einer Liste angehängt. Nachdem diese Liste eine bestimmte Länge erreicht hat, wird mit jedem neuen Wert der älteste Eintrag entfernt. Die durchschnittlichen FPS ergeben sich anschließend mittels des Durchschnittswerts aller Elemente in der Liste. Mit einer List<T> könnte man dieses Verhalten per Add und RemoveAt(0) relativ einfach abbilden, bei einem RingBuffer dagegen steckt dieses Verhalten bereits im Add. Dazu gibt es beim RingBuffer noch weitere Vorteile aus Sicht der Performance, doch dazu im Verlauf dieses Artikels mehr.

Weiterlesen …

Testautomatisierung beim Parsing von Dokumenten

Testautomatisierung

Als Entwickler steht man regelmäßig vor der Aufgabe, Dokumente mit einem bestimmten Format zu lesen und weiterzuverarbeiten. Ebenso kommt es immer wieder vor, dass es für das gewünschte Dokumentenformat noch keinen passenden Parser gibt. Daraus entsteht die Aufgabe, selbst einen kleinen Parser zu entwickeln. Gesagt, getan. Bei Xml- oder Json-Dokumenten etwa ist das i. d. R. auch relativ schnell erledigt. Nicht selten gibt es aber dennoch verschiedene Besonderheiten, die es zu beachten gilt. Etwa bestimmte Elemente in der Datei, die nicht immer enthalten sind. Nehmen wir als Beispiel ein Dokument, welches einen Kassenbon abbildet. Standardmäßig stehen alle Artikel drin, welche der Kunde gekauft hat. Es gibt allerdings weitere Fälle, wie Artikelrückgaben (Pfand), Stornierung einzelner Zeilen durch das Kassenpersonal, rabattierte Artikel etc. Schnell ergibt sich eine längere Liste von Fällen, die das Parsing und die anschließende Weiterverarbeitung beeinflussen. Aus diesem Grund kann es eine gute Idee sein, möglichst viele Teile davon per Testautomatisierung abzusichern.

Weiterlesen …

Worklog SeeingSharp 2: Getting Started für WinUI 3

WinUI3

Bisher gab es in SeeingSharp 2 zwei GettingStarted Projekte: Einmal für Windows.Forms und einmal für WPF. WinUI 3 hat nun zusammen mit dem WindowsAppSdk 1.1 einen recht guten Entwicklungsstand erreicht. Somit wird es Zeit, ebenfalls für WinUI 3 ein GettingStarted Projekt bereitzustellen. Das Projekt zeigt, wie SeeingSharp 2 in ein WinUI 3 Projekt eingebunden und verwendet werden kann. Im Ergebnis wird ein dreidimensionaler Würfel erzeugt, welcher sich in einer endlosen Animation um seine eigene Y-Achse dreht. Unter [1] ist das Coding des Projekts verfügbar.

Weiterlesen …

Json-Daten in SQL-Server per Entity Framework Core 5

Json in SQL

Update vom 16.10.2022: Dieser Artikel bezieht sich auf EF Core 5. Ab EF Core 7 ist das Speichern von Json-Dokumenten im SQL-Server im Standard-Lieferumfang dabei. Im .Net Blog unter [1] wird beschrieben, wie das Feature funktioniert. In diesem Artikel möchte ich mich mit einem doch recht speziellen Thema beschäftigen, welches mir neulich bei einem Projekt begegnet ist. Die Anforderung, Json-Daten in einem SQL-Server zu speichern, klingt zunächst sehr ungewöhnlich bis falsch. SQL-Server ist sicher nicht die erste Wahl dazu, da die Datenbank auf strukturierte Daten ausgelegt ist, welche sich auf Tabellen und Beziehungen zwischen den Tabellen abbilden lassen. Unstrukturierte Json-Dokumente passen hier nicht wirklich ins Konzept, dokumentenorientierte Datenbanken sind dagegen auf solche Daten spezialisiert. Wie kommt man nun auf die Idee, SQL-Server dafür zu verwenden? Ganz einfach, es geht u. A. um den Betrieb. Man muss es sich schon überlegen, ob man wegen einer einzelnen neuen Anforderung direkt eine komplett neue Technologie betreiben möchte. Der SQL-Server und das Wissen darüber dagegen steht im Projekt und im Betrieb schon zur Verfügung. Nach einer kurzen Recherche stellte sich für mich zudem heraus, dass es durchaus nicht einmal so ungewöhnlich ist, SQL-Server zum Speichern von Json-Dokumenten zu verwenden. Es gilt lediglich, einige Punkte zu beachten.

Weiterlesen …

Überwachen von Coding Conventions per Roslyn Analyzer

GPXviewer with Roslyn Analyzer

Das Projekt RK GPXviewer ist ein Modulith in Form einer Desktop Applikation. Das heißt, dass das Programm in mehrere lose gekoppelte Module aufgeteilt ist. Jedes Modul hat hierbei eine öffentliche Schnittstelle und eine nur innerhalb des Moduls sichtbare Logik. Diese Trennung zwischen öffentlicher Schnittstelle und privaten Logikklassen ist hierbei eine strenge Regel. Sie soll sicherstellen, dass das Geflecht an Modulen auch in Zukunft sauber wartbar und erweiterbar bleibt. Nur wie lässt sich die Einhaltung einer solchen Regel am besten sicherstellen? Alle Module befinden sich in der gleichen Projektmappe, eine Regelverletzung wirkt geradezu einladend. Ist eine notwendige Methode oder Eigenschaft gerade nicht in der Schnittstelle enthalten, ist es relativ einfach, ohne Umwege direkt auf die Logik-Klassen zuzugreifen. Damit das nicht passiert, lassen sich für solche Regeln Roslyn Analyzer schreiben. Diese prüfen den Code während des Compile-Vorgangs und geben nach Wahl direkt Fehler oder Warnungen aus. In diesem Artikel möchte ich auf den Roslyn Analyzer eingehen, welchen ich für RK GPXviewer zur Einhaltung obiger Regel umgesetzt habe.

Weiterlesen …

Markdown-Dokumente mit Avalonia rendern

Hilfe-Browser

Markdown ist eine sehr einfache und leicht erlernbare Auszeichnungssprache, welche heute von vielen Produkten unterstützt wird. Häufig dient Markdown dazu, Html-Dokumente zu generieren. Der große Vorteil für mich gegenüber Html oder andere Auszeichnungssprachen ist, dass das Markdown-Dokument selbst bereits gut durch einen Menschen lesbar und der Funktionsumfang auf das notwendige beschränkt ist. Der Einstieg ist entsprechend schnell und selbst ohne vorher die Syntax zu kennen, kann diese leicht verstanden werden. Unter [1] sind weitere Detailinfos über Markdown zu finden. Ein sehr gutes Beispiel zur Verwendung von Markdown ist GitHub. Markdown-Dokumente im Repository erscheinen im Browser direkt als daraus generierte Html-Seiten. In diesem Artikel beschreibe ich etwas ähnliches mithilfe des Cross-Plattform Frameworks Avalonia. Auch hiermit ist es möglich, ein Dokument in der Markdown-Syntax zu schreiben und in der Anwendung anzuzeigen. Sinnvoll ist das etwa bei der Anzeige von in der Anwendung integrierten Hilfeseiten. Der Entwickler schreibt damit innerhalb seiner Entwicklungsumgebung in der Markdown-Syntax und in der Oberfläche erscheint es als sauber formatierte Seite.

Weiterlesen …

Custom Window Chrome mit Avalonia

Message Communicator - Black Theme

Moderne Desktop-Applikationen bringen auch ihren eigenen Fenster-Rahmen mit. Das gehört zum guten Ton und lässt sich bei zahlreichen Beispielen beobachten. In den meisten GUI-Frameworks gibt es einen Weg, genau das zu erreichen. So kann bei WPF oder Windows.Forms der Standard-Rahmen komplett ausgeblendet und damit durch das eigene Programm selbst gerendert werden. Ähnliches gilt auch für Avalonia. Aufgrund des plattformübergreifenden Ansatzes von Avalonia müssen aber einige Kleinigkeiten beachtet werden. So wird hier nicht garantiert, dass es auf jeder Plattform funktioniert. Auch die Standard-Buttons für Maximieren, Minimieren etc. sind je nach Plattform wo anders (rechts bei Windows, links bei macOS). In diesem Artikel möchte ich mich somit genauer mit diesem Thema beschäftigen und zeigen, wie ich es dann bei der App MessageCommunicator gelöst habe.

Weiterlesen …