PeterSpoenemann.HelpService
0.7.0
dotnet add package PeterSpoenemann.HelpService --version 0.7.0
NuGet\Install-Package PeterSpoenemann.HelpService -Version 0.7.0
<PackageReference Include="PeterSpoenemann.HelpService" Version="0.7.0" />
<PackageVersion Include="PeterSpoenemann.HelpService" Version="0.7.0" />
<PackageReference Include="PeterSpoenemann.HelpService" />
paket add PeterSpoenemann.HelpService --version 0.7.0
#r "nuget: PeterSpoenemann.HelpService, 0.7.0"
#:package PeterSpoenemann.HelpService@0.7.0
#addin nuget:?package=PeterSpoenemann.HelpService&version=0.7.0
#tool nuget:?package=PeterSpoenemann.HelpService&version=0.7.0
PeterSpoenemann.HelpService
PeterSpoenemann.HelpService stellt wiederverwendbare Hilfekomponenten für WPF und Avalonia bereit.
Sie lesen Markdown-Themen mit !include-Unterstützung, rendern das aktive Thema mit Markdig
als statisches HTML und zeigen es in einem Hilfefenster an. Beide UI-Pakete bieten dieselben
Interfaces und Funktionen: Inhaltsverzeichnis, Volltextsuche, Sprach- und Themewechsel sowie
Zurück-/Vorwärts-Navigation.
Der plattformneutrale Kern liegt im separaten Assembly und NuGet-Paket
PeterSpoenemann.HelpService.Core. Er enthält keine WPF- oder WebView2-Abhängigkeit und kann
dieselben Hilfequellen beispielsweise für ASP.NET-Core- oder andere Weboberflächen laden.
Voraussetzungen
- Für
PeterSpoenemann.HelpService.Core: .NET 10 - Für
PeterSpoenemann.HelpService: Windows und eine WPF-Anwendung auf .NET 10 sowie die installierte Microsoft Edge WebView2 Runtime - Für
PeterSpoenemann.HelpService.Avalonia: eine Avalonia-12-Desktop-Anwendung auf .NET 10. Unter Windows wird WebView2 verwendet, unter macOS WKWebView und unter Linux WPE WebKit beziehungsweise WebKitGTK. Die Linux-Pakete sind in der Avalonia-WebView-Dokumentation aufgeführt.
Unter Windows benötigt der NativeWebView-Host ein Anwendungsmanifest mit einem supportedOS-Eintrag.
Das übliche Avalonia-Desktop-Template bringt dieses Manifest bereits mit. Bei manuell angelegten
Projekten muss es wie im
Avalonia-Sample über
<ApplicationManifest>app.manifest</ApplicationManifest> eingebunden werden.
Installation
Nach der Veröffentlichung auf NuGet.org:
dotnet add package PeterSpoenemann.HelpService
Für Avalonia-Anwendungen wird stattdessen das Avalonia-Paket installiert:
dotnet add package PeterSpoenemann.HelpService.Avalonia
Für eine Oberfläche ohne WPF kann ausschließlich der Kern installiert werden:
dotnet add package PeterSpoenemann.HelpService.Core
Die beiden UI-Pakete referenzieren das Core-Paket automatisch. Eine Anwendung installiert entweder das WPF- oder das Avalonia-Paket; eine zusätzliche Core-Referenz ist nicht erforderlich.
Plattformneutralen Core verwenden
HelpContentProvider lädt die Themen und liefert mit GetAllTopics() die stabil sortierten Daten für
ein Inhaltsverzeichnis. MarkdownHelpDocumentBuilder erzeugt aus dem ausgewählten Thema ein vollständiges
HTML-Dokument. Beide APIs verwenden dieselben Namespaces wie im WPF-Paket:
using PeterSpoenemann.HelpService;
using PeterSpoenemann.HelpService.Services;
var content = new HelpContentProvider("Help/ContextHelp.en.md", HelpLanguageCodes.English);
var renderer = new MarkdownHelpDocumentBuilder();
var tableOfContents = content.GetAllTopics();
var topic = content.GetTopic("settings");
var html = renderer.BuildHtml(topic.Markdown, HelpLanguageCodes.English);
tableOfContents enthält pro Thema ID, Titel, Markdown-Inhalt und Gruppenname. Eine Weboberfläche kann
daraus Navigation und Suche aufbauen und html direkt in ihrer Inhaltsansicht ausgeben. Für Anwendungen
mit Logging steht zusätzlich der bisherige Konstruktor mit ILogger<HelpContentProvider> zur Verfügung.
Lokale Bilder sollten immer über den HelpContentProvider geladen werden, wie im Beispiel oben. Er löst
ihre relativen Pfade auf und bettet die Dateien als Data-URI in das Themen-Markdown ein. Ein direkt mit
beliebigem Markdown aufgerufener MarkdownHelpDocumentBuilder liest dagegen keine lokalen Dateien;
absolute lokale, UNC- und file:-Bildpfade werden nicht übernommen. Wer den Builder ohne
HelpContentProvider verwendet, muss lokale Bilder daher selbst als Data-URI bereitstellen.
HTML-Theme auswählen
MarkdownHelpDocumentBuilder bettet Basis und Theme vollständig in das erzeugte HTML ein. Neben dem
bisherigen hellen Standard stehen ein dunkles und ein systemabhängiges Theme zur Verfügung:
var light = new MarkdownHelpDocumentBuilder();
var dark = new MarkdownHelpDocumentBuilder(HelpDocumentTheme.Dark);
var system = new MarkdownHelpDocumentBuilder(HelpDocumentTheme.System);
Zusätzliche CSS-Regeln werden nach dem Theme eingebettet und können dessen CSS-Variablen oder Regeln überschreiben:
var customCss = File.ReadAllText("Help/my-theme.css");
var custom = new MarkdownHelpDocumentBuilder(HelpDocumentTheme.Dark, customCss);
Das HTML benötigt dadurch auch mit eigenem Theme keine externe CSS-Datei zur Laufzeit.
Einbindung
Das WPF-Anwendungsprojekt referenziert PeterSpoenemann.HelpService und registriert die
Dienste im DI-Container:
services.AddPeterSpoenemannHelpService(options =>
{
options.RootHelpFile = Path.Combine("Help", "ContextHelp.de.md");
options.ApplicationName = "MeineAnwendung";
options.Theme = HelpDocumentTheme.System;
options.AdditionalStyleSheetPath = Path.Combine("Help", "my-theme.css");
});
Ein Avalonia-Projekt verwendet nach der Installation von
PeterSpoenemann.HelpService.Avalonia dieselbe Registrierung. Auch die konsumierenden
Interfaces und der Aufruf bleiben gleich; nur der optionale Owner ist dort ein
Avalonia.Controls.Window statt eines WPF-Fensters:
using PeterSpoenemann.HelpService.Services;
var helpService = serviceProvider.GetRequiredService<IContextHelpService>();
helpService.ShowHelp("settings", mainWindow);
Die bisherige Eigenschaft RootHelpFile bleibt vollständig unterstützt und konfiguriert die
deutsche Hilfe. Deutsch (de) ist die Standardsprache.
Theme unterstützt Light, Dark und System; ohne Konfiguration bleibt die bisherige helle
Darstellung erhalten. AdditionalStyleSheetPath ist optional und wird bei relativen Pfaden gegen
AppContext.BaseDirectory aufgelöst. Die CSS-Datei muss daher wie die Markdown-Hilfe in die Ausgabe
der Anwendung kopiert werden. Ihre Regeln werden direkt in das vom Core erzeugte HTML eingebettet.
Das Theme kann außerdem zur Laufzeit umgeschaltet werden. Ein bereits geöffnetes Hilfefenster wird dabei automatisch neu gerendert:
var themeService = serviceProvider.GetRequiredService<IHelpThemeService>();
themeService.SetTheme(HelpDocumentTheme.Dark);
Das Sample verbindet diese API mit der Auswahl „System“, „Hell“ und „Dunkel“ auf der Registerkarte „Einstellungen“.
Vollständige HTML-Hilfeseite erzeugen
Über IHelpPageBuilder kann der Core alle geladenen Themen zu einer eigenständigen HTML-Seite
zusammenfassen. Sie enthält ein gruppiertes Inhaltsverzeichnis und einen Abschnitt pro Thema:
var html = pageBuilder.BuildPageHtml(
contentProvider.GetAllTopics(),
languageService.CurrentLanguage,
"Hilfe zu meiner Anwendung");
File.WriteAllText("help.html", html);
Links wie [Auswertung](topic:reports) werden dabei in interne Sprungmarken umgewandelt. Auch
Verweise auf Überschriften wie topic:reports#details und lokale Links wie #details bleiben
funktionsfähig. Sämtliche Styles und lokalen Bilder sind in der HTML-Datei eingebettet. Das Sample
demonstriert den Export über die Schaltfläche „HTML anzeigen“.
Mehrsprachige Hilfe
Für Deutsch, Englisch und Polnisch werden mehrere Wurzeldateien nach Sprachcode registriert:
services.AddPeterSpoenemannHelpService(options =>
{
options.RootHelpFiles[HelpLanguageCodes.German] =
Path.Combine("Help", "ContextHelp.de.md");
options.RootHelpFiles[HelpLanguageCodes.English] =
Path.Combine("Help", "ContextHelp.en.md");
options.RootHelpFiles[HelpLanguageCodes.Polish] =
Path.Combine("Help", "ContextHelp.pl.md");
options.Language = HelpLanguageCodes.German;
options.ApplicationName = "MeineAnwendung";
});
Die Sprache kann anschließend ohne Neustart gewechselt werden. Ein bereits geöffnetes Hilfefenster aktualisiert dabei Oberfläche, Inhaltsverzeichnis und aktives Hilfethema:
var languageService = serviceProvider.GetRequiredService<IHelpLanguageService>();
languageService.SetLanguage(HelpLanguageCodes.English);
languageService.SetLanguage(HelpLanguageCodes.Polish);
languageService.SetLanguage(HelpLanguageCodes.German);
IHelpLanguageService.CurrentLanguage enthält die aktive Sprache und
SupportedLanguages die tatsächlich konfigurierten Sprachen. Über LanguageChanged
kann die einbindende Anwendung ihre eigene Oberfläche gleichzeitig aktualisieren.
Relative Wurzelpfade werden gegen AppContext.BaseDirectory aufgelöst. Die
Anwendung muss ihre Hilfequellen in die Ausgabe kopieren, beispielsweise:
<ItemGroup>
<None Update="Help\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Anwendungscode verwendet IContextHelpService.ShowHelp(topicId, owner) zum Öffnen
und IHelpContentProvider.HasTopic(topicId) zum Ein-/Ausblenden kontextbezogener
Hilfe-Schaltflächen. F1 und die konkrete Gestaltung der Hilfe-Schaltfläche bleiben
Aufgabe der einbindenden Anwendung.
Syntax der Programmhilfe
Die Hilfetexte werden mit Markdig und dessen UseAdvancedExtensions()-Pipeline in HTML umgewandelt. Damit stehen CommonMark und die unten beschriebenen erweiterten Markdown-Elemente zur Verfügung. Eingebettetes Roh-HTML ist aus Sicherheitsgründen deaktiviert und wird als Text angezeigt.
Themen und Inhaltsverzeichnis
Die Wurzeldatei ist ContextHelp.de.md. Sie enthält ausschließlich !include-Zeilen, eine je Themendatei unter Topics/. Jedes eigentliche Hilfethema beginnt mit einer Themen-ID und einem Titel:
# collection | Sammlung
Eine Themendatei kann mehrere Themen enthalten (mehrere # id | Titel-Überschriften hintereinander). Diese Überschrift ist Metadaten-Syntax der Anwendung: Sie bestimmt Themen-ID und Navigationstitel und wird nicht an Markdig übergeben. Inhaltliche Überschriften innerhalb eines Themas beginnen daher mit ##.
Die Themen-ID entspricht üblicherweise einem Navigationseintrag, einer Seite oder
einem Dialog der einbindenden Anwendung und wird dort an ShowHelp übergeben.
Verweise auf andere Themen
Ein Verweis auf ein anderes Thema (z. B. im Abschnitt "Siehe auch") wird als normaler Markdown-Link mit dem Schema topic: geschrieben:
Siehe [Sammlung](topic:collection).
Der topic:-Präfix ist keine echte URL, sondern wird von WebView2Html (Behaviors) über
NavigationStarting abgefangen, bevor Chromium versucht, sie aufzulösen: Ein Klick wechselt im selben
Hilfefenster direkt zum angegebenen Thema. Benutzerinitiierte externe http(s)-Links werden im
Standardbrowser geöffnet. Andere URL-Schemata werden vom WPF-Hilfefenster nicht geöffnet.
Markdown-Syntax
Die wichtigsten unterstützten Elemente sind:
Normaler Absatz mit **fettem**, *kursivem* und ***fett-kursivem*** Text.
Auch ~~durchgestrichener~~ Text und `Quelltext` werden von Markdig gerendert.
## Abschnitt {#stabile-abschnitts-id}
- Erster Punkt
- Zweiter Punkt
- [x] Erledigter Punkt
- [ ] Offener Punkt
1. Erster Schritt
2. Zweiter Schritt
| Spalte A | Spalte B |
|----------|----------|
| Wert 1 | Wert 2 |
Begriff
: Eine Definition in einer Definitionsliste.
Ein Text mit Fußnote.[^hinweis]
[^hinweis]: Der zugehörige Fußnotentext.
Eine normale URL wird automatisch verlinkt: https://example.org
> Ein normales Zitat bleibt ein normales Zitat.
> [!TIP]
> Ein hervorgehobener Hinweis mit **Formatierung**.
> [!WARNING]
> Ein hervorgehobener Hinweis auf tatsächliches Risiko, z. B. Datenverlust oder einen irreführenden Scan-Stand.

!include ../Shared/weiterer-text.md
!include <../Shared/datei mit leerzeichen.md>
Markdig unterstützt die Alert-Typen NOTE, TIP, IMPORTANT, WARNING und CAUTION. Für Hinweise und Risiken sollen bevorzugt TIP beziehungsweise WARNING verwendet werden.
Überschriften erhalten durch Markdig automatisch stabile HTML-IDs. Mit {#eigene-id} kann eine ID explizit festgelegt werden. Darüber hinaus aktiviert die Pipeline unter anderem Aufgabenlisten, Definitionslisten, Fußnoten, automatische Links, Pipe- und Grid-Tabellen sowie zusätzliche Hervorhebungen.
Anwendungsspezifische Erweiterungen
!include und die Themenüberschrift # id | Titel sind keine Markdig-Syntax, sondern werden vor dem Markdown-Rendering vom HelpContentProvider verarbeitet. Markdig selbst bietet keine Dateieinbindung oder Verwaltung anwendungsspezifischer Themen-IDs.
Include- und lokale Bildpfade müssen relativ zu der Markdown-Datei angegeben werden, in der sie stehen.
Absolute Pfade, laufwerksbezogene Pfade, UNC-Pfade und file:-URLs sind dafür nicht zulässig. Auch
verschachtelte Includes und ..-Segmente sind möglich, solange das aufgelöste Ziel innerhalb des Ordners
der jeweiligen ContextHelp*.md-Wurzeldatei bleibt. Daher funktionieren beispielsweise
!include ../Shared/text.md oder , wenn Shared beziehungsweise Images
noch innerhalb dieses Ordners liegen.
Der HelpContentProvider liest zulässige lokale Bilder beim Laden und schreibt sie als Data-URI in das
Themen-Markdown. Dadurch enthalten BuildHtml und BuildPageHtml bei der üblichen Kombination aus
Provider und Builder weiterhin vollständige lokale Bilder. Fehlt eine Bilddatei, bleibt der relative
Markdown-Verweis erhalten und der Browser zeigt gegebenenfalls den Alternativtext an. Externe Bild-URLs
und bereits vorhandene Data-URIs werden unverändert weitergegeben.
Ordnerstruktur
Help/
ContextHelp.de.md -- deutsche !include-Liste
ContextHelp.en.md -- englische !include-Liste
ContextHelp.pl.md -- polnische !include-Liste
Topics/
Start.md
Einstellungen.md
Für Inhalte, die von mehreren Themen gemeinsam genutzt werden (z. B. ein Glossar
oder eine Fehlerbehebungs-Tabelle), kann ein Shared/-Unterordner angelegt und per
!include in die betroffenen Themendateien eingebunden werden, statt Inhalte zu
duplizieren.
Fehlertolerantes Laden
Jede !include-Zeile der Wurzeldatei bildet eine eigene Fehlergrenze. Schlägt eine Themendatei fehl (fehlende Datei, zirkuläres Include, Pfad außerhalb von Help/, ungültige Themenüberschrift, doppelte Themen-ID), werden nur deren Themen übersprungen - alle anderen Themendateien bleiben vollständig verfügbar. Der Fehler wird mit Datei- und Zeilenangabe protokolliert (HelpContentProvider, Anwendungsprotokoll).
Eine Themen-ID, für die zur Laufzeit kein passender Eintrag existiert (z. B. wegen eines fehlgeschlagenen Includes oder eines fehlenden Themas), zeigt einen generischen Hinweistext statt eines Fehlers. Der Hilfe-Button in der Anwendung wird für eine Seite ohne hinterlegtes Thema ausgeblendet (IHelpContentProvider.HasTopic).
Lokal bauen und testen
Benötigt wird das .NET 10 SDK:
dotnet restore
dotnet build --configuration Release --no-restore
dotnet test --configuration Release --no-build
dotnet pack src/HelpService.Core/PeterSpoenemann.HelpService.Core.csproj --configuration Release --no-build --output artifacts
dotnet pack src/HelpService/PeterSpoenemann.HelpService.csproj --configuration Release --no-build --output artifacts
dotnet pack src/HelpService.Avalonia/PeterSpoenemann.HelpService.Avalonia.csproj --configuration Release --no-build --output artifacts
Die erzeugten .nupkg- und .snupkg-Dateien liegen danach in artifacts.
Software Bill of Materials (SBOM)
Jedes über einen Release-Tag veröffentlichte NuGet-Paket enthält eine SPDX-2.2-JSON-SBOM
unter sbom/manifest.spdx.json. Dieselbe SBOM wird zusätzlich als
<PackageId>.<Version>.spdx.json am GitHub-Release bereitgestellt.
Für die lokale SBOM-Erzeugung werden zusätzlich die .NET-8-Laufzeit und das festgepinnte Repository-Tool benötigt:
dotnet tool restore
$version = "0.7.0"
./build/Pack-WithSbom.ps1 -Project src/HelpService.Core/PeterSpoenemann.HelpService.Core.csproj -PackageId PeterSpoenemann.HelpService.Core -Version $version
./build/Pack-WithSbom.ps1 -Project src/HelpService/PeterSpoenemann.HelpService.csproj -PackageId PeterSpoenemann.HelpService -Version $version
./build/Pack-WithSbom.ps1 -Project src/HelpService.Avalonia/PeterSpoenemann.HelpService.Avalonia.csproj -PackageId PeterSpoenemann.HelpService.Avalonia -Version $version
Sample-Anwendung
Unter samples/PeterSpoenemann.HelpService.Sample
liegt eine kleine WPF-Anwendung mit zwei Registerkarten und kontextsensitiver Hilfe.
Die aktive Hilfeseite wird über die Schaltfläche am unteren Fensterrand oder mit F1 geöffnet.
Über die Sprachauswahl kann die komplette Sample-Oberfläche einschließlich eines bereits
geöffneten Hilfefensters zur Laufzeit zwischen Deutsch, Englisch und Polnisch wechseln.
dotnet run --project samples/PeterSpoenemann.HelpService.Sample/PeterSpoenemann.HelpService.Sample.csproj
Das entsprechende Avalonia-Desktop-Sample liegt unter
samples/PeterSpoenemann.HelpService.Avalonia.Sample.
Es verwendet dieselben Hilfedateien und demonstriert ebenfalls F1, kontextsensitive Themen,
Sprachwechsel und Themewechsel. Die Farbschema-Auswahl schaltet dabei sowohl das Avalonia-App-Theme
als auch das Theme des geöffneten Hilfefensters um:
dotnet run --project samples/PeterSpoenemann.HelpService.Avalonia.Sample/PeterSpoenemann.HelpService.Avalonia.Sample.csproj
VS-Code-Vorschau
Unter vscode-extension liegt eine passende VS-Code-Extension. Ihre Vorschau
verwendet den .NET-Core dieses Projekts und zeigt daher !include, Themenüberschriften, relative
Bilder sowie die Markdig-Advanced-Extensions genauso wie die Anwendung an. Eine geöffnete
ContextHelp*.md-Datei oder eine von ihr eingebundene Themendatei kann über
HelpService: Vorschau öffnen angezeigt werden. Bau- und Installationshinweise stehen in der
Extension-Dokumentation.
Ein Tooltip zeigt an jedem gerenderten Markdown-Block die ursprüngliche Datei und Zeile an.
Über das Kontextmenü HelpService: Quelldatei öffnen springt VS Code direkt zu dieser Stelle;
bei eingebundenem Inhalt wird die tatsächliche !include-Datei geöffnet.
Die jeweils aktuelle fertige Extension kann direkt bei GitHub heruntergeladen werden:
PeterSpoenemann.HelpService.Preview.vsix herunterladen
Danach lässt sie sich über die VS-Code-Oberfläche oder auf der Kommandozeile installieren:
code --install-extension .\PeterSpoenemann.HelpService.Preview.vsix
Lizenz
Dieses Projekt steht unter der MIT-Lizenz. Copyright © 2026 Peter Spönemann.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- CommunityToolkit.Mvvm (>= 8.4.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
- Microsoft.Web.WebView2 (>= 1.0.4078.44)
- PeterSpoenemann.HelpService.Core (>= 0.7.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.