{"id":50535344,"url":"https://github.com/kylec69/markdownviewer.wpf","last_synced_at":"2026-06-03T16:01:29.736Z","repository":{"id":351702236,"uuid":"1211310022","full_name":"KyleC69/MarkdownViewer.wpf","owner":"KyleC69","description":"A pure WPF control that renders Markdown as native WPF controls allowing for easy theming and customizations.","archived":false,"fork":false,"pushed_at":"2026-06-01T20:29:34.000Z","size":1001,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-01T21:24:31.097Z","etag":null,"topics":["markdown-viewer-control","native-rendering","wpf-application"],"latest_commit_sha":null,"homepage":"https://github.com/KyleC69/MarkdownViewer.wpf","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KyleC69.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["KyleC69"]}},"created_at":"2026-04-15T09:07:45.000Z","updated_at":"2026-06-01T19:45:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/KyleC69/MarkdownViewer.wpf","commit_stats":null,"previous_names":["kylec69/markdownviewer.wpf"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/KyleC69/MarkdownViewer.wpf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleC69%2FMarkdownViewer.wpf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleC69%2FMarkdownViewer.wpf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleC69%2FMarkdownViewer.wpf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleC69%2FMarkdownViewer.wpf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KyleC69","download_url":"https://codeload.github.com/KyleC69/MarkdownViewer.wpf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KyleC69%2FMarkdownViewer.wpf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33872298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["markdown-viewer-control","native-rendering","wpf-application"],"created_at":"2026-06-03T16:01:28.305Z","updated_at":"2026-06-03T16:01:29.726Z","avatar_url":"https://github.com/KyleC69.png","language":"C#","funding_links":["https://github.com/sponsors/KyleC69"],"categories":[],"sub_categories":[],"readme":"# MarkdownViewer.Wpf\n\n`MarkdownViewer.Wpf` is a WPF control for rendering Markdown into a native `UIElement` tree. It uses `Markdig` for parsing and applies WPF styles, brushes, and merged resource dictionaries through the normal WPF theming model, making it suitable for live previews, embedded documentation panes, and markdown-driven desktop UI.\n\n## Features\n\n- Native WPF `MarkdownView` control\n- Deterministic rendering to WPF visual elements instead of a browser surface\n- Markdown-specific WPF control subtypes for predictable, element-scoped implicit styling\n- Optional built-in theme resource dictionaries for default, light, and dark presentations\n- Support for common markdown elements, including:\n  - headings (H1–H6) and paragraphs\n  - bold, italic, strikethrough, subscript, superscript, inserted, marked, and inline code\n  - ordered, unordered, and task lists\n  - block quotes and thematic breaks\n  - indented and fenced code blocks with a header row, language label, and copy button\n  - tables\n  - links, auto-links, and images\n  - HTML blocks and supported inline HTML\n- Extensibility through injectable services for:\n  - link navigation via `IMarkdownLinkNavigator`\n  - image loading via `IMarkdownImageSourceResolver`\n- Custom renderer registration via `MarkdownRendererBuilder`\n- Post-processing pipeline via `IPostProcessor`\n- Diagnostics surface through `MarkdownDiagnostics.Emitted`\n- Sample app included for live editing and theme switching\n- Runtime-adjustable preview/editor split in the sample app\n\n## Requirements\n\n- .NET 9\n- WPF on Windows\n\n## Installation\n\nAdd the NuGet package reference:\n\n```xml\n\u003cItemGroup\u003e\n  \u003cPackageReference Include=\"MarkdownViewer.Wpf\" Version=\"2.0.*\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\n## Basic usage\n\nAdd the XML namespace in XAML:\n\n```xml\nxmlns:markdown=\"clr-namespace:MarkdownViewer.Wpf;assembly=MarkdownViewer.Wpf\"\n```\n\nThen place the control in your view:\n\n```xml\n\u003cmarkdown:MarkdownView Markdown=\"{Binding MarkdownText}\" Padding=\"16\" /\u003e\n```\n\nYou can also set the markdown directly:\n\n```xml\n\u003cmarkdown:MarkdownView\n    Markdown=\"# Hello\\n\\nThis is **MarkdownViewer.Wpf**.\"\n    Padding=\"16\" /\u003e\n```\n\n## Theming\n\nThe renderer emits markdown-specific WPF control subtypes defined in `MarkdownViewer.Wpf.Controls`. Each subtype maps to a distinct markdown concept, allowing themes to apply fully independent implicit styles without relying on attached properties, triggers, or shared target types.\n\nAvailable rendered control types include:\n\n| Type | Represents |\n|---|---|\n| `ParagraphTextBlock` | Paragraph text |\n| `Heading1TextBlock` – `Heading6TextBlock` | Headings H1–H6 |\n| `CodeBlockTextBlock` | Code block content |\n| `CodeInlineSpan` | Inline code |\n| `BlockQuoteBorder` | Block quote container |\n| `CodeBlockBorder` | Code block outer border |\n| `CodeBlockHeaderBorder` | Code block header area |\n| `CodeBlockHeaderTextBlock` | Code block language label |\n| `CodeBlockCopyButton` | Code block copy button |\n| `CodeBlockScrollViewer` | Code block scroll container |\n| `ListPanel` | List container |\n| `ListItemGrid` | List item layout grid |\n| `ListItemMarkerTextBlock` | List item bullet or number |\n| `ListItemContentPanel` | List item content area |\n\nThe control exposes a `ThemeResources` property that accepts a WPF `ResourceDictionary`. If `ThemeResources` is not set, the rendered tree inherits styles from the surrounding control tree and application resources through normal WPF resource lookup. The library does not inject a fallback theme automatically.\n\n### Optional built-in themes\n\nThe library ships three convenience resource dictionaries:\n\n- `Themes/DefaultTheme.xaml`\n- `Themes/LightTheme.xaml`\n- `Themes/DarkTheme.xaml`\n\nExample — switching themes from a view model:\n\n```csharp\nusing System.Windows;\n\npublic ResourceDictionary CurrentThemeResources =\u003e new()\n{\n    Source = new Uri(\n        IsDarkModeEnabled\n            ? \"pack://application:,,,/MarkdownViewer.Wpf;component/Themes/DarkTheme.xaml\"\n            : \"pack://application:,,,/MarkdownViewer.Wpf;component/Themes/DefaultTheme.xaml\",\n        UriKind.Absolute)\n};\n```\n\n```xml\n\u003cmarkdown:MarkdownView\n    Markdown=\"{Binding MarkdownText}\"\n    ThemeResources=\"{Binding CurrentThemeResources}\"\n    Padding=\"20\" /\u003e\n```\n\n### Applying a theme at the application level\n\n```xml\n\u003cApplication.Resources\u003e\n    \u003cResourceDictionary\u003e\n        \u003cResourceDictionary.MergedDictionaries\u003e\n            \u003cResourceDictionary Source=\"pack://application:,,,/MarkdownViewer.Wpf;component/Themes/DefaultTheme.xaml\" /\u003e\n        \u003c/ResourceDictionary.MergedDictionaries\u003e\n    \u003c/ResourceDictionary\u003e\n\u003c/Application.Resources\u003e\n```\n\n### Merging theme overrides per control\n\n```xml\n\u003cmarkdown:MarkdownView Markdown=\"{Binding MarkdownText}\" Padding=\"20\"\u003e\n    \u003cmarkdown:MarkdownView.ThemeResources\u003e\n        \u003cResourceDictionary\u003e\n            \u003cResourceDictionary.MergedDictionaries\u003e\n                \u003cResourceDictionary Source=\"pack://application:,,,/MarkdownViewer.Wpf;component/Themes/DefaultTheme.xaml\" /\u003e\n                \u003cResourceDictionary Source=\"Themes/MarkdownOverrides.xaml\" /\u003e\n            \u003c/ResourceDictionary.MergedDictionaries\u003e\n        \u003c/ResourceDictionary\u003e\n    \u003c/markdown:MarkdownView.ThemeResources\u003e\n\u003c/markdown:MarkdownView\u003e\n```\n\nFor a full theming reference see [docs/THEMING.md](docs/THEMING.md) and [docs/RENDERED-TYPE-CUSTOMIZATION-GUIDE.md](docs/RENDERED-TYPE-CUSTOMIZATION-GUIDE.md).\n\n## Services and integration points\n\n`MarkdownView` accepts an `IServiceProvider` through its `Services` property. The renderer uses that provider to resolve integration services.\n\n### Custom link navigation\n\nImplement `IMarkdownLinkNavigator` to intercept hyperlink clicks.\n\n```csharp\nusing MarkdownViewer.Wpf.Core;\n\npublic sealed class AppLinkNavigator : IMarkdownLinkNavigator\n{\n    public bool TryNavigate(Uri uri, IRenderContext context)\n    {\n        // Handle in-app routing or custom navigation here.\n        return true;\n    }\n}\n```\n\n### Custom image loading\n\nImplement `IMarkdownImageSourceResolver` to control how markdown images are resolved.\n\n```csharp\nusing System.Windows.Media;\nusing MarkdownViewer.Wpf.Core;\n\npublic sealed class AppImageResolver : IMarkdownImageSourceResolver\n{\n    public ImageSource? ResolveImageSource(Uri uri, IRenderContext context)\n    {\n        // Resolve local files, cached images, or protected resources here.\n        return null;\n    }\n}\n```\n\nProvide those services from your application service provider and assign it to `MarkdownView.Services`.\n\n## Custom renderers and post-processors\n\n`MarkdownRendererBuilder` lets you compose a fully custom rendering pipeline. Call `MarkdownRendererBuilder.CreateDefault()` to start from the built-in renderer set and add or replace renderers as needed.\n\n```csharp\nusing MarkdownViewer.Wpf.Core;\n\nMarkdownEngine engine = new MarkdownRendererBuilder()\n    .AddBlockRenderer\u003cMyCustomBlock, MyCustomBlockRenderer\u003e()\n    .AddInlineRenderer\u003cMyCustomInline, MyCustomInlineRenderer\u003e()\n    .AddPostProcessor(new MyPostProcessor())\n    .BuildDispatcher()\n    // pass to MarkdownEngine constructor\n```\n\nImplement `IPostProcessor` to inspect or modify the rendered `UIElement` tree after each render pass:\n\n```csharp\nusing System.Windows;\nusing MarkdownViewer.Wpf.Core;\n\npublic sealed class MyPostProcessor : IPostProcessor\n{\n    public void Process(UIElement root, IRenderContext context)\n    {\n        // Walk or mutate the rendered visual tree here.\n    }\n}\n```\n\nUse `MarkdownEngine.CreateDefault()` to get a ready-made engine using all built-in renderers:\n\n```csharp\nMarkdownEngine engine = MarkdownEngine.CreateDefault();\n```\n\n## Diagnostics\n\nThe library emits diagnostics through `MarkdownDiagnostics` for events such as:\n\n- rendered block and inline nodes\n- missing theme keys\n- ignored unsupported inline HTML\n- image load failures\n- link navigation failures\n\nExample subscription:\n\n```csharp\nusing System.Diagnostics;\nusing MarkdownViewer.Wpf.Diagnostics;\n\nMarkdownDiagnostics.Emitted += (_, args) =\u003e\n{\n    Debug.WriteLine($\"[{args.Kind}] {args.Message}\");\n};\n```\n\n## Running the sample app\n\nThe repository contains a sample WPF application in `src/MarkdownViewer.WPF.Sample` that demonstrates:\n\n- two-pane editing and preview\n- runtime-adjustable pane split via `GridSplitter`\n- theme switching\n- tables, task lists, code blocks, links, images, and HTML rendering\n\nRun it from the repository root:\n\n```powershell\ndotnet run --project .\\src\\MarkdownViewer.WPF.Sample\\MarkdownViewer.Wpf.Sample.csproj\n```\n\n## Repository layout\n\n```\nsrc/\n  MarkdownViewer.Wpf/\n    Controls/       — MarkdownView control and markdown-specific WPF element types\n    Core/           — Rendering engine, builder, dispatcher, and service interfaces\n    Diagnostics/    — Diagnostics events and formatters\n    Rendering/\n      Blocks/       — Block renderers (paragraph, heading, list, code, table, etc.)\n      Inlines/      — Inline renderers (emphasis, link, code, task list, etc.)\n      Html/         — HTML fragment renderer\n  MarkdownViewer.WPF.Sample/  — Sample WPF application\n  MarkdownViewer.Wpf.Tests/   — Automated tests\ndocs/\n  THEMING.md                          — Full theming reference\n  RENDERED-TYPE-CUSTOMIZATION-GUIDE.md — End-to-end style override example\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkylec69%2Fmarkdownviewer.wpf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkylec69%2Fmarkdownviewer.wpf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkylec69%2Fmarkdownviewer.wpf/lists"}