Avalonia で Markdown を表示するための最も簡単な要件は、文字列をレンダリングすることです。しかし、文字列が AI からのもので、一度に数語しか到達せず、コード、表、数式、グラフも含まれている場合、アクセス方法にはもう 1 つのステップを検討する必要があります。それは、コンテンツを追加し続ける方法と、より長い会話をどのように整理するかです。
StreamMark は、このタイプのシナリオ向けの Avalonia のネイティブ Markdown レンダリング ライブラリであり、WebView を必要としません。この記事は、NuGet のインストールから始まり、最初に 1 つのドキュメントの表示を完了してから、ストリーミング出力とオプションの拡張機能にアクセスします。
この記事は AI の助けを借りて整理され、プロジェクトのソース コードとリリース パッケージに基づいてチェックされています。 2026 年 10 月 19 日時点で公開されているバージョンを使用してください
0.1.0-alpha.22.NET 10およびAvalonia 12.1.3に対応します。まだプレビュー版であるため、修正版にアクセスしてからアクセスすることをお勧めします。以下の C# アクセス API は、リリース パッケージによってコンパイルおよび検証されています。添付の画像は、実際に TKCode に StreamMark を統合した Headless + Skia レンダリングのスクリーンショットであり、効果を示すために使用されており、以下の最小限のプログラムの実行中のスクリーンショットではありません。

図 1: ネイティブ インターフェイスの混合 Markdown コンテンツ。数式、構文のハイライト、グラフにはそれぞれ対応する拡張パックが必要です。
1. アバロニアプロジェクトの準備
.NET 10 SDKを準備します。 Avalonia プロジェクトがまだない場合は、最初にテンプレートをインストールしてから、基本的なデスクトップ プロジェクトを作成できます。
dotnet new install Avalonia.Templates --version 12.1.3
dotnet new avalonia -n StreamMarkStarter
cd StreamMarkStarter
すでにプロジェクトがある場合は、作成手順をスキップできます。対象フレームが net10.0Avalonia関連パッケージを統一して使用 12.1.3、含む Avalonia.Desktop、Avalonia.Themes.Fluent およびテンプレートで有効になっている他の Avalonia パッケージ。 1 つのパッケージをアップグレードするだけで、大きなバージョンを混在させたままにしないでください。
StreamMark は現在、デスクトップ アプリケーションをターゲットとしています。ここの例では Fluent テーマを使用しているため、AtomUI をインストールする必要はありません。
2. NuGet から StreamMark をインストールする
通常の Markdown のみを表示します。最初にこのパッケージをインストールします。
dotnet add package TKCode.StreamMark.Avalonia --version 0.1.0-alpha.22
2 つの名前の違いに注意してください。NuGet パッケージ名は TKCode. プレフィックスが追加されましたが、アセンブリと C# 名前空間はそのままです StreamMark.*。たとえば、使用されるコードは次のとおりです using StreamMark.Avalonia;。
より豊富なコンテンツが必要な場合は、対応する拡張機能をインストールします。
dotnet add package TKCode.StreamMark.Highlighting.TextMate --version 0.1.0-alpha.22
dotnet add package TKCode.StreamMark.RaTeX --version 0.1.0-alpha.22
dotnet add package TKCode.StreamMark.Mermaid --version 0.1.0-alpha.22
| バッグ | 使用 |
|---|---|
TKCode.StreamMark.Avalonia |
マークダウン コントロール、デフォルトのテーマ。自動的にコアに依存します |
TKCode.StreamMark.Highlighting.TextMate |
コード構文の強調表示 |
TKCode.StreamMark.RaTeX |
LaTeX式 |
TKCode.StreamMark.Mermaid |
マーメイドチャート |
TKCode.StreamMark.Theme.AtomUI |
テーマ マッピングに AtomUI のホスト アプリケーションをすでに使用している |
プレビュー バージョンはここで明示的に指定されており、NuGet クライアントがデフォルトでプレリリース バージョンを検索するかどうかには依存しません。すべての StreamMark 拡張機能に同じバージョンを使用することをお勧めします。
3.アプリにテーマを登録する
開ける App.axamlテンプレートの元の Fluent テーマを保持し、後で StreamMark テーマを追加します。
x:Class 独自のプロジェクトの名前空間との一貫性を保ってください。以下でも利用可能 App.Initialize() C# を使用して登録しますが、XAML で繰り返し追加しないでください。
Styles.Add(new StreamMark.Avalonia.Themes.StreamMarkTheme());
ここでの暗い色の設定はデモンストレーションのみを目的としています。に変更できます Light またはシステムテーマを使用します。 Fluent などのホスト テーマは通常のコントロール テンプレートを提供し、StreamMark テーマは Markdown コンテンツで使用されるリソースを提供します。両者には異なる責任があります。
4. 最初のマークダウンを表示する
テンプレートを変更する MainWindow.axaml 簡略化すると次のようになります。
そして変更します MainWindow.axaml.cs。このバージョンは基本パッケージのみに依存しています。
using Avalonia;
using Avalonia.Controls;
using Avalonia.Layout;
using StreamMark.Avalonia;
using StreamMark.Avalonia.Extensions;
namespace StreamMarkStarter;
public partial class MainWindow : Window
{
private readonly MarkdownServices _services = new();
private readonly MarkdownView _view = new();
public MainWindow()
{
InitializeComponent();
// 先设置服务,再设置 Markdown。
MarkdownServices.SetServices(_view, _services);
_view.Markdown = """
# Hello StreamMark
这是运行在 **Avalonia 原生控件** 中的 Markdown。
- 支持标题、段落和列表
- 可以选择、复制文字
- 接下来接入流式输出
| 项目 | 状态 |
| --- | --- |
| NuGet 安装 | 完成 |
| Avalonia 接入 | 完成 |
""";
Content = new ScrollViewer
{
Content = new Border
{
MaxWidth = 820,
Padding = new Thickness(28),
HorizontalAlignment = HorizontalAlignment.Stretch,
Child = _view
}
};
}
}
走る:
dotnet run
タイトル、リスト、表が表示されるようになりました。MarkdownView ドキュメントの高さはドキュメントに応じて大きくなるため、通常、1 つのドキュメントは外側のレイヤーで構成されます。 ScrollViewer スクロールを提供します。MaxWidth 読み取り幅を制御するためです。
5. コードのハイライト、数式、マーメイドを追加します。
拡張パックをインストールした後、プラグインの登録も必要です。上記を入れてください _services フィールドは次のように置き換えられます。
private readonly MarkdownServices _services = new()
{
Plugins =
[
new StreamMark.Highlighting.TextMate.TextMatePlugin(),
new StreamMark.RaTeX.RaTeXPlugin(),
new StreamMark.Mermaid.MermaidPlugin()
]
};
それから置きます _view.Markdown 以下に置き換えます。
_view.Markdown = """
## 代码高亮
```csharp
public record Message(string Role, string Content);
```
## 数学公式
行内公式:$E = mc^2$
$$
\mathrm{Attention}(Q,K,V)
= \mathrm{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
## Mermaid 流程图
```mermaid
flowchart LR
A[网络文本增量] --> B[MarkdownStream]
B --> C[增量解析]
C --> D[Avalonia 原生界面]
```
""";
C# 生の文字列 """ LaTeX のバックスラッシュを再度エスケープする必要はありません。ここでの式は Markdown コンテンツであり、RaTeX プラグインによって処理されます。

図 2: TKCode の StreamMark を介して表示された Mermaid チャート。デフォルトの配色は、ホストの明るいテーマと暗いテーマに応じて変わります。
アクセスの詳細:
- サービスを初めて使用する前に、プラグインを構成する必要があります。ドキュメントのレンダリング後に、同じサービスのプラグイン リストに構成を追加しないでください。
- 特定のサービスを設定します
MarkdownViewそれが最も理解しやすいです。複数の子コントロールが構成を共有する場合、Window または共通の祖先に設定することもできます。 - プラグインを使用する場合、手動で作成したストリーミング ドキュメントとセッション エントリは同じものを使用する必要があります
services.Profileビューでプラグインが有効になっているにもかかわらず、ドキュメントでは引き続きデフォルトの解析構成が使用されるのを防ぐためです。
RaTeX の NuGet パッケージには、デスクトップ RID (Windows、Linux、macOS、それぞれ x64/arm64 を含む) に対応する 6 つのネイティブ ライブラリが含まれています。通常の NuGet アクセスでは、Rust を自分でインストールする必要も、ネイティブ ライブラリを手動でコンパイルする必要もありません。ソース コードからビルドする場合、またはネイティブ パーツをカスタマイズする場合のみ、ウェアハウスのネイティブ ビルド プロセスに従う必要があります。
6. 静的表示をストリーミング出力に変更します
ネットワークシャードが到着するたびにこれを行わないでください _view.Markdown += chunk。このプロパティは、完全なドキュメントをロードするのに適しています。ストリーミング回答は一度作成する必要があります MarkdownStream新しいテキストのみが後で追加されます。
同じように MainWindow クラスに追加:
private async Task PlayDemoAsync(CancellationToken cancellationToken)
{
var stream = new MarkdownStream(profile: _services.Profile);
_view.Stream = stream;
string[] chunks =
[
"# 流式回答\n\n",
"你好,",
"**StreamMark**!\n\n",
"- 原生渲染\n",
"- 增量更新\n"
];
try
{
foreach (var chunk in chunks)
{
cancellationToken.ThrowIfCancellationRequested();
stream.Push(chunk);
await Task.Delay(80, cancellationToken);
}
}
finally
{
// 即使取消,也结束当前流,保留已经收到的内容。
stream.Complete();
}
}
デモの実行を容易にするために、コンストラクターの最後に次のコードを追加して、ウィンドウを開いた後に一度だけ自動的に再生できるようにします。これは実際のネットワーク リターンのシミュレーションであり、モデル API は呼び出されません。
Opened += async (_, _) => await PlayDemoAsync(CancellationToken.None);
例では次のことが必要です System.Threading そして System.Threading.Tasks 名前空間。共通の .NET テンプレートが有効になりました ImplicitUsings 自動的にインポートされました。公式アプリケーションは、ボタンのトリガーとイベント ハンドラーでのキャンセルやエラーの処理に切り替えることができます。
実際のモデルが接続されたら、 chunks SDKに置き換えて返却テキストの増分。一連の回答により、順番にストリームが作成されます。 Push()終了後 Complete()。 SDK が累積的なフルテキストを返す場合、新しいサフィックスが最初に計算され、コンテンツ全体を繰り返しプッシュすることはできません。
Push() そして Complete() バックグラウンド スレッドから呼び出すことができます。セット _view.Streamコントロールの追加とセッション エントリの更新は、引き続き UI スレッドで行う必要があります。この例は Avalonia ウィンドウ イベントから入力されるため、コントロールは UI スレッドに割り当てられます。
スムーズな出力キューはデフォルトで存在するため、 Complete() 画面上のすべてのテキストが同時に表示されるわけではありません。スムージング キューがいつ終了するかを知りたい場合は、次のメッセージを聞いてください。 stream.Completed; 現在のバックログをすぐに表示する必要がある場合は、次のように呼び出すことができます。 stream.Flush()。
7. 長い会話には TranscriptView を使用する
MarkdownView これは単一のドキュメント コントロールであり、仮想化自体は提供しません。トーク履歴が長くなってきたら、 TranscriptViewこれにより、メッセージの整理、表示行の仮想化、メッセージ間の選択とスクロールの処理が可能になります。
次のコードをウィンドウ コンストラクターに配置して、元の単一ドキュメントを置き換えることができます。 ScrollViewer コンテンツ設定:
var transcript = new StreamMark.Avalonia.Transcript.TranscriptView
{
MaxContentWidth = 820
};
MarkdownServices.SetServices(transcript, _services);
// 用户消息可以是任意 Avalonia 控件。
transcript.Entries.Add(
new StreamMark.Avalonia.Transcript.ContentEntry(
new TextBlock { Text = "请介绍 StreamMark", Margin = new Thickness(16) }));
// 历史消息:用匹配插件的 Profile 创建静态条目。
transcript.Entries.Add(
StreamMark.Avalonia.Transcript.MarkdownEntry.FromText(
"这是一条 **历史回答**。", _services.Profile));
// 新回答:创建一次,持续追加。
var reply = new MarkdownStream(profile: _services.Profile);
transcript.Entries.Add(
new StreamMark.Avalonia.Transcript.MarkdownEntry(reply));
Content = transcript;
reply.Push("## 新回答\n\n");
reply.Push("下面可以接入真实模型的文本增量。");
reply.Complete();
二度としないでください TranscriptView アウターレイヤーを着せると無限に身長が高くなります ScrollViewer; ウィンドウまたはグリッドを維持して、視覚的な高さを制限します。積極的に一番下にジャンプする必要がある場合に呼び出されます transcript.ScrollToEnd()フラグメントを受信するたびに強制的に下までスクロールして、ユーザーの読書履歴を中断するのではなく。

図 3: TKCode での StreamMark コンテンツの表示。 Diff、タスクリスト、詳細を同じマークダウンに配置できます。スクリーンショットのタスクのステータスは事前設定された例です。
8. トピック、リンク、画像に関するよくある質問
文字の色が異常であるか、背景に一貫性がありません。 まず登録を確認してください StreamMarkThemeホストの明るいテーマと暗いテーマを確認してください。 StreamMark の Markdown リソースの使用量 Md.* 鍵;全体的なデザイン システム マッピングが必要な場合は、テーマ パッケージを検討してください。すでにAtomUIを使用しているアプリもインストール可能 TKCode.StreamMark.Theme.AtomUIStreamMark のデフォルト テーマとホスト AtomUI テーマの準備ができた後に追加 AtomUIMarkdownTheme。通常の Fluent プロジェクトでは、Markdown 用の AtomUI を導入する必要はありません。
拡張機能は明らかにインストールされていますが、レンダリング効果はありません。 パッケージのインストール、プラグインの登録、プロファイルに一致するドキュメントの作成の 3 つです。まずサービスが正しいコントロールに設定されていることを確認してから、 MarkdownStream(profile: _services.Profile) または MarkdownEntry.FromText(text, _services.Profile) 同じ構成が使用されます。
長い文書をスクロールする際には、コントロールがますます増えています。 シングル MarkdownView 仮想化セッションとは異なります。代わりにマルチラウンド チャットを使用してください TranscriptView;仮想化により、ビュー インスタンスとレイアウトのオーバーヘッドが削減されますが、履歴文字列とメッセージ モデル自体が占有するメモリは排除されません。
数式は、公開後にネイティブ ライブラリを読み込むことができません。 実際のプラットフォームで RID を指定します。例: dotnet publish -c Release -r osx-arm64。リリース出力に対応するプラットフォームの RaTeX ネイティブ アセットが含まれていることを確認し、x64 と arm64 を混在させないでください。 Linux では、システムの依存関係とディストリビューション環境もチェックする必要があります。
画像のパスまたはリンクが期待どおりに動作しません。 開始するときは、アクセス可能な HTTPS イメージ アドレスを使用して、相対パス解決の問題を軽減します。リンクは StreamMark のリンク ポリシーによって管理されます。デフォルトで許可される外部プロトコルは HTTP、HTTPS、および mailto であり、アプリケーションは LinkClicked 独自の開封方法とプロセスにアクセスする RequiresConfirmation。判断なしに起動のためにシステムに任意の URL を渡さないでください。
スクリプトはMarkdownで実行できますか? StreamMark は、HTML およびホワイトリストに登録されたコンポーネントのサブセットをサポートしますが、完全なブラウザーではありません。script、style、iframe 不明な要素は実行されず、元のソース コードに従って表示される必要があります。 Web ページの CSS および JavaScript プラグインをネイティブ Markdown コントロールに直接コピーすることはできません。
9. 推奨アクセスシーケンス
まず、基本パッケージとデフォルトのテーマに静的マークダウンを表示させます。次に、本当に必要な拡張機能を登録します。そして通過します MarkdownStream ドッキングされたネットワークテキストの増分。セッションの長さによる最終選択 TranscriptViewキャンセル、エラー プロンプト、リンク処理、イメージ戦略を追加します。
この記事の例では、レンダリング アクセスのみを取り上げており、モデル認証、ツールの実行、セッションの永続性は含まれていません。 StreamMark はネイティブ インターフェイスでコンテンツを表示する責任を負い、エージェントまたはチャット アプリケーションのビジネス プロセスは引き続きホストによって管理されます。
参考入口:
検証手順: この記事のサービス登録、MarkdownView、MarkdownStream、TranscriptView、および 3 種類の拡張プラグイン API は NuGet を使用しています
0.1.0-alpha.22アバロニアと12.1.3.NET 10 でコンパイルおよびチェックした結果、警告は 0 件、エラーは 0 件でした。添付の写真は、既存の実際のコンポーネントのレンダリングからのものです。この記事は、すべてのオペレーティング システムでの実行テストやパフォーマンスの比較テストを行ったわけではありません。