Titelbild zum Beitrag Erstellen eines Seven Segment Display Controls mit .NET MAUI und SkiaSharp

Blogbeitrag

Erstellen eines Seven Segment Display Controls mit .NET MAUI und SkiaSharp

In diesem Beitrag entwickelst du ein anpassbares Seven Segment Display Control für .NET MAUI. Du erfährst, wie sich Segmente mit SkiaSharp zeichnen, responsiv skalieren, animieren und über bindbare Eigenschaften sowie App-Themes konfigurieren lassen.

Was ist eine Sieben-Segment-Anzeige?

Eine Sieben-Segment-Anzeige gehört zu den bekanntesten Darstellungsformen digitaler Benutzeroberflächen. Sie ist die visuelle Sprache von Weckern, Taschenrechnern, Küchentimern, Zapfsäulen, Laborgeräten und alten Arcade-Punktanzeigen.

Anstatt ein Zeichen wie bei einer normalen Schriftart mit Kurven und Linien zu zeichnen, verwendet eine Sieben-Segment-Anzeige sieben fest definierte Balken:

     -- A --
    |       |
    F       B
    |       |
     -- G --
    |       |
    E       C
    |       |
     -- D --

Jedes Zeichen entsteht aus einer Kombination dieser Balken. Zum Beispiel:

  • Bei 8 leuchten alle Segmente.
  • Bei 1 leuchten nur das obere und das untere rechte Segment.
  • Bei 0 leuchten alle Segmente mit Ausnahme des mittleren Balkens.
  • Bei - leuchtet ausschließlich der mittlere Balken.

Der besondere Reiz entsteht durch diese Einschränkung. Es gibt kein vollständiges Alphabet im klassischen Sinn. Stattdessen steht nur eine kleine Anzahl physischer Formen zur Verfügung, mit denen Zahlen und eine nützliche Auswahl an Buchstaben angenähert werden können. Genau diese Begrenzung sorgt dafür, dass die Anzeige mechanisch, retro und unmittelbar lesbar wirkt.

Warum sollte dies als benutzerdefiniertes MAUI-Control umgesetzt werden?

Die naheliegende Abkürzung wäre die Verwendung einer Sieben-Segment-Schriftart. Für einfache Demos kann das ausreichen, ein echtes wiederverwendbares UI-Control bietet jedoch deutlich mehr Kontrolle:

  • Aktive und inaktive Segmente können getrennt gezeichnet werden.
  • Ein Leuchteffekt kann unabhängig von Schrifteffekten hinzugefügt werden.
  • Die Anzeige lässt sich auf jede beliebige Größe skalieren.
  • Farben, Abstände, Segmentstärke und Animationen können als bindbare Eigenschaften bereitgestellt werden.
  • Das Control kann mithilfe der normalen MAUI-Binding-Funktionen auf das aktive App-Theme reagieren.

In diesem Beispiel wird die Anzeige vollständig manuell mit SkiaSharp gezeichnet. Dadurch bleibt das Rendering unter Android, iOS, Mac Catalyst und Windows vorhersehbar.

Screenshots des SevenSegmentDisplay Controls

Die Beispielanwendung präsentiert das SevenSegmentDisplay Control als Digitaluhr, Countdown-Timer und Statusanzeige. Dabei werden anpassbare Farben, Leuchteffekte, Animationen und eine responsive Skalierung demonstriert.

Die fertige SevenSegmentDisplay-Komponente kann außerdem im Dunkelmodus verwendet werden.

Das Control skaliert automatisch auf unterschiedliche Bildschirmgrößen. Dadurch bleibt die Darstellung auch auf mobilen Geräten scharf und optisch konsistent, ohne dass zusätzliche Anpassungen am Layout erforderlich sind.

Projektstruktur

Das Beispiel verwendet bewusst eine übersichtliche Repository-Struktur:

.editorconfig
Directory.Build.props
Directory.Packages.props
NuGet.config
MauiSevenSegmentDisplay.slnx
README.md
src/
└── MauiSevenSegmentDisplay/
    ├── Controls/
    │   ├── SevenSegmentDisplay.cs
    │   ├── SegmentCharacterMap.cs
    │   ├── SevenSegmentOptions.cs
    │   └── SevenSegmentParts.cs
    ├── Pages/
    │   ├── MainPage.xaml
    │   └── MainPage.xaml.cs
    ├── ViewModels/
    │   └── MainViewModel.cs
    └── MauiSevenSegmentDisplay.csproj
tests/
└── MauiSevenSegmentDisplay.Tests/
    ├── SegmentCharacterMapTests.cs
    ├── SevenSegmentOptionsTests.cs
    └── MauiSevenSegmentDisplay.Tests.csproj

Die vom MAUI-Template erzeugten Ordner für `Platform, Ressourcen und Properties bleiben weiterhin Bestandteil der Anwendung, da sie die tatsächliche plattformübergreifende Projektstruktur bereitstellen.

Zentrale Paketverwaltung

Die Solution verwendet die zentrale Paketverwaltung über Directory.Packages.props. Dadurch werden die Paketversionen aus der Projektdatei herausgehalten und zukünftige Aktualisierungen vereinfacht:

<PackageVersion Include="SkiaSharp" Version="4.150.0" />
<PackageVersion Include="SkiaSharp.Views.Maui.Controls" Version="4.150.0" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageVersion Include="NUnit" Version="4.6.1" />
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.7.0" />

Das Projekt verwendet den installierten stabilen .NET-10-MAUI-Workload und richtet sich an

  • net10.0-android,
  • net10.0-ios,
  • net10.0-maccatalyst und
  • net10.0-windows10.0.19041.0.

Zeichenzuordnung

Die Zuordnung befindet sich in SegmentCharacterMap. Jedes unterstützte Zeichen wird einer Kombination von SevenSegmentParts-Flags zugeordnet.

Die Ziffer 0 verwendet beispielsweise alle Segmente mit Ausnahme von G, während 2 die Segmente A, B, G, E und D verwendet.

Nicht unterstützte Zeichen werden None zugeordnet. Das ist für ein wiederverwendbares Control wichtig, da eine UI-Komponente keinen Fehler auslösen sollte, nur weil eine gebundene Zeichenfolge ein unerwartetes Zeichen enthält. Eine leere Darstellung ist sicherer und leichter nachvollziehbar.

Das Beispiel behandelt außerdem : und . als spezielle schmale Symbole. Sie verwenden nicht die sieben Balken, sondern werden als runde Leuchtpunkte gezeichnet.

Rendering mit SkiaSharp

Das zentrale Control erbt von SKCanvasView. Sämtliche sichtbaren Bestandteile werden manuell in OnPaintSurface gezeichnet.

Der Renderer arbeitet zunächst mit einem eigenen Design-Koordinatensystem:

  • Die Zeichenbreite basiert auf der Segmentstärke.
  • Die Zeichenhöhe basiert auf der Segmentstärke.
  • Doppelpunkte und Dezimalpunkte erhalten eine schmalere Symbolbreite.
  • Der Zeichenabstand wird in die berechnete Gesamtbreite einbezogen.

Nachdem die Zeichenfolge vermessen wurde, berechnet das Control einen Skalierungsfaktor, mit dem das Designmodell in die tatsächlich verfügbare Skia-Zeichenfläche eingepasst wird:

float scale = MathF.Min(
    availableWidth / totalWidth,
    availableHeight / characterHeight);

Dadurch kann dasselbe Control in einer kleinen Karte, einem breiten Desktop-Layout oder auf einem Smartphone-Bildschirm eingesetzt werden, ohne feste Pixelgrößen zu benötigen.

Segmentgeometrie

Jedes normale Segment ist ein Polygon und kein einfaches Rechteck. Horizontale Segmente bestehen aus abgeschrägten Formen mit sechs Punkten. Vertikale Segmente verwenden dasselbe Prinzip, lediglich gedreht und in einem vertikalen Bereich angeordnet.

Die Punkte werden anschließend an eine Hilfsmethode übergeben, die jede Ecke abrundet. Dabei werden scharfe Richtungswechsel durch kurze quadratische Kurven ersetzt. Dies verleiht der Anzeige eine physischere LED- beziehungsweise LCD-Optik, ohne die Geometrie unnötig kompliziert zu machen.

Der Renderer zeichnet die Darstellung in mehreren Ebenen:

  1. Body des inaktiven Segments
  2. Optionaler Leuchteffekt für aktive Segmente
  3. Body des aktiven Segments

Diese Reihenfolge ist wichtig. Die inaktiven Segmente machen die vollständige Form der Anzeige erkennbar, während die aktiven Segmente hell und scharf dargestellt werden.

Leuchteffekt

Der Leuchteffekt wird erzeugt, indem derselbe Pfad eines aktiven Segments zunächst mit einer unscharfen Skia-Farbe und anschließend noch einmal mit der klaren aktiven Füllfarbe gezeichnet wird.

Das Control stellt dafür folgende Eigenschaften bereit:

  • GlowColor
  • GlowIntensity
  • IsGlowEnabled

Dadurch bleibt der Effekt optional und frei gestaltbar. Eine dezente blaue Countdown-Anzeige kann eine geringere Leuchtintensität verwenden, während eine helle Uhr stärker an eine klassische LED-Anzeige erinnern kann.

Animation

Wenn sich die Eigenschaft Text ändert, führt das Control eine kurze Pulsanimation aus. Während der neue Text angezeigt wird, verstärkt der Puls geringfügig den Eindruck von Helligkeit und Leuchten.

Die Animation verwendet einen IDispatcherTimer, der vom Control selbst verwaltet wird. Dadurch wird ein Startproblem vermieden, bei dem der Animationsmanager von MAUI während früher Binding-Aktualisierungen möglicherweise noch nicht verfügbar ist.

Der Timer wird beendet, sobald die Animation abgeschlossen ist. Er wird außerdem gestoppt, wenn das Control entladen wird.

Bindbare Eigenschaften

Das Control stellt die typischen Konfigurationsmöglichkeiten bereit, die eine verwendende Anwendung erwarten würde:

<controls:SevenSegmentDisplay
    Text="{Binding CurrentTime}"
    SegmentColor="Lime"
    InactiveSegmentColor="DarkGreen"
    DisplayBackgroundColor="Black"
    GlowColor="Lime"
    SegmentThickness="12"
    CharacterSpacing="8"
    SegmentCornerRadius="4"
    InactiveSegmentOpacity="0.28"
    GlowIntensity="0.7"
    IsGlowEnabled="True"
    IsAnimationEnabled="True"
    AnimationDuration="250" />

Die Eigenschaft heißt DisplayBackgroundColor und nicht BackgroundColor, um Verwechslungen mit der bereits vorhandenen Eigenschaft VisualElement.BackgroundColor von MAUI zu vermeiden.

App-Themes

Die Demo-Seite verwendet AppThemeBinding für das helle und das dunkle Theme:

SegmentColor="{AppThemeBinding Light=#27D86A, Dark=#39FF72}"
InactiveSegmentColor="{AppThemeBinding Light=#2B6640, Dark=#1E5531}"
InactiveSegmentOpacity="{AppThemeBinding Light=0.34, Dark=0.3}"

Im hellen Modus wird die umgebende Seite aufgehellt, während die eigentlichen Anzeigeflächen dunkel bleiben. So bleibt der für Retro-Anzeigen typische Kontrast in beiden Themes erhalten.

Unit-Tests

Das Beispiel enthält unter tests/MauiSevenSegmentDisplay.Tests ein NUnit-Projekt. Die Tests konzentrieren sich auf Verhaltensweisen, die ohne den Start einer MAUI-Benutzeroberfläche leicht überprüft werden können:

  • SegmentCharacterMapTests überprüft die Zuordnung von Ziffern, die für die Demo verwendeten Statusbuchstaben, die Zuordnung leerer Symbole sowie das Verhalten bei nicht unterstützten Zeichen.
  • SevenSegmentOptionsTests prüft, ob die Konstanten des Design-Koordinatensystems sinnvoll bleiben: Normale Zeichen müssen breiter als Satzzeichen sein, Ziffern müssen höher als breit sein und die Segmentstärke muss eine positive Untergrenze besitzen.

Diese Tests sind bewusst klein gehalten. Sie schützen den wichtigsten nicht visuellen Vertrag des Controls: Für ein bestimmtes Zeichen muss der Renderer die erwarteten Segment-Flags erhalten.

Pixelgenaue Rendering-Tests würden einen separaten Workflow für Screenshots oder Bildvergleiche erfordern. Das wäre für ein produktives Control durchaus sinnvoll, würde jedoch vom Kerngedanken dieses Beitrags ablenken.

Das Testprojekt bindet die wenigen von der Benutzeroberfläche unabhängigen Quelldateien direkt ein, anstatt das MAUI-App-Projekt zu referenzieren. Dadurch bleiben die NUnit-Tests schnell und die MAUI-Resizetizer-Targets werden nicht in einen gewöhnlichen Unit-Test-Build hineingezogen.

Ausführen des Beispiels

Führe im Solution-Ordner folgende Befehle aus:

dotnet build MauiSevenSegmentDisplay.slnx
dotnet test MauiSevenSegmentDisplay.slnx

Das Beispiel kann für Android, iOS, Mac Catalyst und Windows gebaut werden, sofern die jeweils benötigten MAUI-Workloads installiert sind.

Fazit

Das Interessante an diesem Control ist nicht allein, dass es Zahlen zeichnet. Entscheidend ist vielmehr, dass aus einem kleinen, stark eingeschränkten visuellen System durch eine sorgfältige Modellierung eine ausgereifte und wiederverwendbare UI-Komponente entstehen kann:

  • Eine klar definierte Segmentzuordnung
  • Skalierbare Geometrie
  • Bindbare Darstellungseigenschaften
  • Theme-abhängige Farben
  • Leichtgewichtige Animationen
  • Ein MVVM-freundlicher Beispielzustand

Dies ist auch allgemein ein gutes Vorgehen für benutzerdefinierte MAUI-Controls: Beginne mit dem visuellen Modell, stelle die richtigen Anpassungsmöglichkeiten bereit, halte plattformspezifisches Verhalten aus dem Control heraus und überlasse SkiaSharp das Zeichnen der Pixel.

Der vollständige Quellcode dieses Projekts ist auf GitHub verfügbar. Du kannst die Implementierung erkunden, das Beispiel selbst ausprobieren und es als Ausgangspunkt für eigene benutzerdefinierte .NET-MAUI-Controls verwenden:

tsjdev-apps/sevensegmentdisplay-maui

Dieser Beitrag entstand im Rahmen des jährlich stattfindenden Community-Events .NET MAUI UI July 2026 . Im Laufe des Julis veröffentlichen Entwicklerinnen und Entwickler aus aller Welt Blogbeiträge und Videos, in denen sie Ideen, Techniken und Projekte rund um .NET MAUI vorstellen.

Weiterempfehlen

Diesen Beitrag teilen

Wenn dir der Beitrag gefallen hat: gern weiterreichen. Gute Links dürfen sich ruhig schnell verbreiten.

Vorheriger/Nächster Beitrag

Titelbild zum Beitrag Image Sortr: Bilder automatisch nach Aufnahmedatum sortieren Nächster Beitrag Image Sortr: Bilder automatisch nach Aufnahmedatum sortieren
Lust auf ein kurzes digitales Hallo? Wenn du eine Idee teilen, eine Frage loswerden oder ein Projekt anschieben willst: mein Posteingang ist deutlich zuverlässiger als Brieftauben. [email protected] Mail schicken