MarkdView 1.0.11

dotnet add package MarkdView --version 1.0.11
                    
NuGet\Install-Package MarkdView -Version 1.0.11
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MarkdView" Version="1.0.11" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MarkdView" Version="1.0.11" />
                    
Directory.Packages.props
<PackageReference Include="MarkdView" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MarkdView --version 1.0.11
                    
#r "nuget: MarkdView, 1.0.11"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MarkdView@1.0.11
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MarkdView&version=1.0.11
                    
Install as a Cake Addin
#tool nuget:?package=MarkdView&version=1.0.11
                    
Install as a Cake Tool

MarkdView

License: MIT .NET Version

现代化 WPF Markdown 渲染控件,支持流式渲染、语法高亮和智能主题管理。

✨ 特性

  • 🚀 智能流式渲染 - 支持 AI 流式输出,自适应防抖优化(50ms-1000ms)
  • 🎨 语法高亮 - 内置多语言高亮支持
  • 😊 Emoji 支持 - 基于 Emoji.Wpf 的彩色 Emoji 渲染
  • 💻 Mac 风格代码块 - 带装饰性圆点的优雅代码展示
  • 🌓 智能主题管理 - 支持自动跟随全局主题或独立设置
  • 📐 比例字体缩放 - 所有文本元素随 FontSize 成比例缩放
  • 🔧 易扩展 - 基于 Markdig,支持丰富的 Markdown 特性
  • 高性能 - 重入保护、低优先级异步渲染,确保 UI 流畅
  • 📜 列表场景优化 - 支持在 ScrollViewer 中禁用内部滚动条

📦 安装

# 使用 NuGet 包管理器
Install-Package MarkdView

# 或使用 .NET CLI
dotnet add package MarkdView

🚀 快速开始

基础用法

<Window xmlns:markd="clr-namespace:MarkdView.Controls;assembly=MarkdView">
    <markd:MarkdownViewer Content="{Binding Content}" />
</Window>
public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    private string _content = "# Hello MarkdView\n\nThis is **bold** text.";
}

主题管理

MarkdView 提供智能主题管理系统,基于全局静态变量 ThemeManager.CurrentTheme 作为唯一真实来源,支持两种使用模式:

模式 1:自动跟随全局主题(推荐)

不设置 Theme 属性(默认 ThemeMode.Auto),所有控件自动跟随全局主题:


<markd:MarkdownViewer Content="{Binding Content}" />

<markd:MarkdownViewer Content="{Binding Content}" Theme="Auto" />
using MarkdView;
using MarkdView.Enums;

// 在应用启动时初始化全局主题
public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        // 初始化全局主题(所有 Theme="Auto" 的控件都会使用此主题)
        ThemeManager.ApplyTheme(ThemeMode.Dark);
    }
}

// 运行时切换全局主题
ThemeManager.ApplyTheme(ThemeMode.Light);
ThemeManager.ApplyTheme(ThemeMode.Dark);

// 获取当前全局主题
var currentTheme = ThemeManager.CurrentTheme; // 始终返回当前实际使用的主题

使用场景

  • ✅ 应用中所有 Markdown 内容使用统一主题
  • ✅ 主题由应用级别统一管理(如跟随系统主题)
  • ✅ 简化主题管理逻辑
模式 2:独立主题设置

显式设置 Theme 属性为 LightDark,控件使用独立主题(并同步到全局):


<markd:MarkdownViewer
    Content="{Binding Content}"
    Theme="{Binding Theme}" />


<markd:MarkdownViewer
    Content="{Binding Content}"
    Theme="Dark" />
public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    private ThemeMode _theme = ThemeMode.Dark;

    [RelayCommand]
    private void SwitchToLight()
    {
        // 修改此属性会:
        // 1. 更新控件主题
        // 2. 同步更新 ThemeManager.CurrentTheme
        Theme = ThemeMode.Light;
    }

    [RelayCommand]
    private void SwitchToDark()
    {
        Theme = ThemeMode.Dark;
    }
}

使用场景

  • ✅ 不同 Markdown 内容需要使用不同主题
  • ✅ 主题切换由特定控件或 ViewModel 管理
  • ✅ 需要通过数据绑定动态切换主题
ThemeMode 枚举
public enum ThemeMode
{
    Auto = 0,   // 自动跟随全局主题(默认,推荐)
    Light = 1,  // 浅色主题
    Dark = 2    // 深色主题
}

主题同步机制与设计细节见 Guid.md

完整配置

<markd:MarkdownViewer
    Content="{Binding Content}"
    Theme="Auto"
    EnableStreaming="True"
    StreamingThrottle="50"
    EnableSyntaxHighlighting="True"
    UseTransparentCanvas="False"
    FontSize="12"
    FontFamily="Microsoft YaHei UI"
    VerticalScrollBarVisibility="Auto"
    HorizontalScrollBarVisibility="Auto" />

字体与字号设置

MarkdownViewer 支持直接设置 FontFamilyFontSize,也支持数据绑定。


<markd:MarkdownViewer
    Content="{Binding Content}"
    FontFamily="Microsoft YaHei UI"
    FontSize="14" />

<markd:MarkdownViewer
    Content="{Binding Content}"
    FontFamily="{Binding MarkdownFontFamily}"
    FontSize="{Binding MarkdownFontSize}" />

说明:

  • 修改 FontFamily / FontSize 后会立即重渲染并生效
  • FontSize 会按比例影响正文、标题、列表和代码块

透明画布开关

MarkdownViewer 提供 UseTransparentCanvas 属性,用于控制渲染画布是否透明:

  • False(默认):使用主题资源 Markdown.Background,保证主题一致性和可读性
  • True:将 FlowDocument 背景设为透明,适合嵌入已有卡片背景的场景

<markd:MarkdownViewer Content="{Binding Content}" UseTransparentCanvas="False" />


<markd:MarkdownViewer Content="{Binding Content}" UseTransparentCanvas="True" />

语法高亮开关

EnableSyntaxHighlighting 用于控制代码块是否启用语法高亮:

  • True(默认):代码块按语法类型着色
  • False:代码块以普通文本颜色显示

<markd:MarkdownViewer Content="{Binding Content}" EnableSyntaxHighlighting="True" />


<markd:MarkdownViewer Content="{Binding Content}" EnableSyntaxHighlighting="False" />

语法高亮配色(动态资源)

代码块语法色使用动态资源键 Markdown.Syntax.*。主题切换时会自动刷新,不需要手动重新创建控件。

你可以在 App.xaml 或运行时覆盖这些键:

<Application.Resources>
    
    <SolidColorBrush x:Key="Markdown.Syntax.Default" Color="#1F2937" />
    <SolidColorBrush x:Key="Markdown.Syntax.Comment" Color="#6B7280" />
    <SolidColorBrush x:Key="Markdown.Syntax.String" Color="#B45309" />
    <SolidColorBrush x:Key="Markdown.Syntax.ControlKeyword" Color="#7C3AED" />
    <SolidColorBrush x:Key="Markdown.Syntax.Function" Color="#2563EB" />
</Application.Resources>

渲染完成事件

MarkdownViewer 提供 RenderCompleted 事件,用于监控 Markdown 内容何时完成渲染。这在需要显示加载动画、统计渲染性能或协调多个控件时非常有用。

基础用法
<markd:MarkdownViewer
    Content="{Binding Content}"
    RenderCompleted="OnMarkdownRenderCompleted" />
private void OnMarkdownRenderCompleted(object sender, EventArgs e)
{
    // Markdown 渲染完成,可以隐藏 loading 动画
    LoadingIndicator.Visibility = Visibility.Collapsed;
}
高级用法:通过 Attached Behavior 监控多个实例

在聊天应用等场景中,需要等待所有 AI 消息的 Markdown 都渲染完成后再显示内容:

1. 创建 Attached Behavior:

public static class MarkdownLoadedBehavior
{
    private static int _loadedCount = 0;
    private static int _totalCount = 0;
    private static Action? _onAllLoaded;

    // 开始跟踪
    public static void StartTracking(string sessionId, int totalCount, Action onAllLoaded)
    {
        _loadedCount = 0;
        _totalCount = totalCount;
        _onAllLoaded = onAllLoaded;
    }

    // Attached Property
    public static readonly DependencyProperty IsTrackingEnabledProperty =
        DependencyProperty.RegisterAttached(
            "IsTrackingEnabled",
            typeof(bool),
            typeof(MarkdownLoadedBehavior),
            new PropertyMetadata(false, OnIsTrackingEnabledChanged));

    public static bool GetIsTrackingEnabled(DependencyObject obj)
        => (bool)obj.GetValue(IsTrackingEnabledProperty);

    public static void SetIsTrackingEnabled(DependencyObject obj, bool value)
        => obj.SetValue(IsTrackingEnabledProperty, value);

    private static void OnIsTrackingEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is MarkdownViewer markdownViewer && (bool)e.NewValue)
        {
            markdownViewer.RenderCompleted += OnMarkdownRenderCompleted;
        }
    }

    private static void OnMarkdownRenderCompleted(object? sender, EventArgs e)
    {
        _loadedCount++;

        if (_loadedCount >= _totalCount && _totalCount > 0)
        {
            _onAllLoaded?.Invoke();  // 所有渲染完成
            _loadedCount = 0;
            _totalCount = 0;
            _onAllLoaded = null;
        }
    }
}

2. 在 XAML 中使用:

<ItemsControl ItemsSource="{Binding Messages}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <markd:MarkdownViewer
                behaviors:MarkdownLoadedBehavior.IsTrackingEnabled="True"
                Content="{Binding Content}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

3. 在 ViewModel 中协调:

// 开始加载会话
IsLoadingMessages = true;

// 统计需要渲染的 Markdown 数量(例如:AI 消息数)
var markdownCount = session.Messages.Count(m => m.IsAIMessage);

// 开始跟踪渲染
MarkdownLoadedBehavior.StartTracking(
    sessionId,
    markdownCount,
    () =>
    {
        // 所有 Markdown 渲染完成后的回调
        Dispatcher.Invoke(() => IsLoadingMessages = false);
    }
);
事件触发时机

RenderCompleted 事件在以下情况触发:

  • Markdown 文本解析完成
  • FlowDocument 构建完成
  • 所有代码块语法高亮完成
  • 文档配置和布局完成

注意:事件在 DispatcherPriority.Background 优先级下触发,确保 UI 主线程不被阻塞。

列表场景使用

ScrollViewer 中使用多个 MarkdownViewer(如聊天消息列表),需要禁用内部滚动条以实现流畅的外层滚动体验:

<ScrollViewer VerticalScrollBarVisibility="Auto">
    <ItemsControl ItemsSource="{Binding Messages}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border Margin="10" Padding="15" Background="White">
                    
                    <markd:MarkdownViewer
                        Content="{Binding Content}"
                        VerticalScrollBarVisibility="Disabled"
                        HorizontalScrollBarVisibility="Disabled" />
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>
列表场景滚动行为说明

⚠️ 必须设置的属性

  • 必须将 VerticalScrollBarVisibility="Disabled" 设置在每个 MarkdownViewer
  • 必须将 HorizontalScrollBarVisibility="Disabled" 设置在每个 MarkdownViewer

🎯 滚动行为

  1. 外层文档滚动:鼠标滚轮事件会自动转发给外层 ScrollViewer,实现流畅的列表滚动
  2. 代码块滚动
    • 鼠标滚轮始终控制外层文档滚动(不会被代码块拦截)
    • 代码块内容只能通过拖动滚动条来滚动
    • 这样设计避免了滚动冲突,提供更好的用户体验
  3. 透明容器支持:即使外层 Border 背景设置为透明,滚动功能依然正常工作

💡 代码块操作提示

  • 复制代码:点击代码块右上角的复制按钮
  • 滚动代码:拖动代码块内的滚动条(不支持鼠标滚轮)
  • 文本选择:由于 WPF TextBlock 限制,暂不支持直接选中代码文本

🎨 主题定制

方式 1:运行时自定义(推荐)

在应用启动时加载主题并自定义颜色:

using MarkdView;
using MarkdView.Enums;

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        // 应用主题
        ThemeManager.ApplyTheme(ThemeMode.Dark);

        // 自定义特定颜色
        Resources["Markdown.Heading.H1.Border"] = new SolidColorBrush(Color.FromRgb(0xFF, 0x69, 0xB4));
        Resources["Markdown.CodeBlock.Background"] = new SolidColorBrush(Color.FromRgb(0x1E, 0x1E, 0x1E));
    }
}

方式 2:在 App.xaml 中覆盖

<Application.Resources>
    
    <SolidColorBrush x:Key="Markdown.Foreground" Color="#1E1E1E"/>
    <SolidColorBrush x:Key="Markdown.Heading.H1.Border" Color="#5C9DFF"/>
    <SolidColorBrush x:Key="Markdown.Quote.Background" Color="#F9F9F9"/>
    <SolidColorBrush x:Key="Markdown.CodeBlock.Background" Color="#282C34"/>
</Application.Resources>

可用主题资源键与颜色控制范围见 Guid.md

📝 支持的 Markdown 特性

基础语法

  • ✅ 标题 (H1-H6)
  • 粗体 / 斜体 / 删除线
  • ✅ 段落和换行
  • ✅ 引用块
  • ✅ 有序/无序列表
  • ✅ 链接和图片
  • ✅ 水平分隔线

高级特性

  • ✅ 代码块(Mac 风格设计 + 语法高亮)
  • 行内代码
  • ✅ 表格
  • ✅ 任务列表
  • ✅ Emoji 😊
  • ✅ GFM 扩展

语法高亮支持

C#, JavaScript, TypeScript, Python, Java, C/C++, Go, Rust, SQL, Bash, HTML, CSS, JSON, XML 等

📐 字体缩放系统

所有文本元素基于 FontSize 属性成比例缩放:

元素 缩放比例 示例(FontSize=12)
H1 标题 1.5× 18px
H2 标题 1.25× 15px
H3 标题 1.17× 14px
H4 标题 1.08× 13px
H5/H6 标题 1.0× 12px
正文 1.0× 12px
一级列表 1.08× 13px
嵌套列表 0.96× 11.5px
代码 0.92× 11px

<markd:MarkdownViewer FontSize="14" Content="{Binding Content}" />

项目结构、性能优化与实现细节见 Guid.md

🛠️ 技术栈

  • .NET 8.0 - 现代化的 .NET 平台
  • WPF - Windows Presentation Foundation
  • Markdig 0.43.0 - 高性能 Markdown 解析器
  • Emoji.Wpf 0.3.4 - 彩色 Emoji 支持
  • CommunityToolkit.Mvvm - MVVM 工具包(示例项目)

🤝 贡献

欢迎提交 Issue 和 PR!

📄 许可证

MIT License - 详见 LICENSE 文件

🙏 致谢


Made with ❤️ for WPF developers

Product Compatible and additional computed target framework versions.
.NET net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.11 145 3/1/2026
1.0.10 112 2/27/2026
1.0.9 114 2/27/2026
1.0.8 221 11/25/2025
1.0.7 424 11/19/2025
1.0.6 424 11/19/2025
1.0.5 418 11/19/2025
1.0.4 424 11/19/2025
1.0.3 424 11/19/2025
1.0.1 353 11/17/2025
1.0.0 262 11/16/2025

v1.0.11: 新增 UseTransparentCanvas 透明画布开关;语法高亮配色改为 Markdown.Syntax.* 动态资源并支持主题切换自动刷新;README 聚焦使用方式并补充字体/字号与高亮配置说明。