AvaloniaのクリップボードとDataGridの問題

AvaloniaのクリップボードとDataGridの問題

最近のAvaloniaデスクトップソフトウェア開発で解決した2つの問題を記録:クリップボードコピーのクラッシュ、タブ切り替え時のDataGridの遅延。根本原因を分析し、解決策を提供する

最終更新 2026/01/11 12:23
沙漠尽头的狼
読了目安 3 分
カテゴリ
.NET Avalonia UI
タグ
.NET C# Avalonia UI デスクトップ開発 Avalonia

Avalonia でデスクトップアプリケーションを開発中に遭遇し、解決した典型的な2つの問題を記録します。同じ問題に直面する開発者の参考になれば幸いです。

1. クリップボードコピー異常(AOT クラッシュ / デバッグ時に COM 例外)

現象

プロジェクト内の TextBoxSelectedTextBlock コントロールのテキストに対して Ctrl+C コピー操作を行うと、以下の2種類の異常が発生:

  • AOT ビルド実行時、アプリケーションが直接クラッシュし、アプリケーションイベントを確認:

  • Debug モードでは、グローバル例外がキャッチされず、ProgramMain 関数で明確な COM 例外がスロー:
System.Runtime.InteropServices.COMException:“尚未调用 CoInitialize。 (0x800401F0 (CO_E_NOTINITIALIZED))”

原因特定

コード調査の結果、Program.csMain 関数定義が問題の核心でした。エントリポイント関数が async Task 型で宣言されており、Avalonia が要求する同期形式になっていません:

async Taskvoid に変更することで修正されます。Avalonia ドキュメント:Application Lifetimes にも説明があります:

原理分析

Avalonia はデスクトップ UI フレームワークであり、メインスレッドの SynchronizationContext(同期コンテキスト)に強く依存します。クリップボードやウィンドウメッセージループなどのシステムレベル操作は、安定したメインスレッドコンテキスト上で実行される必要があります。

  • async Task Main とすると、CLR がメインスレッドのライフサイクルを非同期に管理するようになり、Avalonia が初期化した同期コンテキストが破壊されます。その結果、クリップボード操作時に CoInitialize が呼び出されていないという COM 例外が発生します。
  • Avalonia 公式ドキュメントでは、アプリケーションのエントリ段階(Main 関数)で準備未完了の SynchronizationContext に依存すべきではないと明記されており、エントリ関数は同期でなければなりません。

2. Tab 切り替え時の DataGrid カクツキ

状況

プロジェクトでは Dock コントロール(VS スタイルレイアウト、Document は TabControl の TabItem に相当)を使用し、Document 内に DataGrid を埋め込んでデータを表示:

  • データ量は極めて少ない(数十件、8~9 フィールド);
  • 実行環境は Win7 / Windows Server 2019、Win10 の同僚からもカクツキがあるとの報告;
  • 現象:Debug モードで Tab 切り替えに約 2 秒のカクツキ、AOT ビルド後は 3~4 秒に悪化;
  • 比較:単一ウィンドウで DataGrid に数十万件のデータ(15 フィールド)を直接表示した場合、リアルタイム更新はスムーズ。

調査過程

  1. 初期は DataGrid の使用方法の問題を疑い、列バインディングの最適化(一方向バインディングのみ)、複雑なスタイル・アニメーションの除去を試みたが、カクツキは改善せず;
  2. Dock コントロールのパフォーマンス問題を疑い、Dock コントロールのバージョン更新や旧バージョンへの切り替えを試みたが、問題は変わらず;
  3. Dock コントロールの影響を排除するため、ネイティブの TabControl に置き換えてテストしたが、カクツキは再現;
  4. コミュニティに相談:Avalonia 交流グループでフィードバックしたところ、TreeDataGrid の使用を提案され、置き換えたところカクツキが完全に解消。

DataGrid は初期移植の WPF(リンク先は Silverlight)スタイルのコンポーネントであり、「セルレベルのコントロール + パッシブ仮想化」という設計のため、少データ量でも Tab 切り替えによる再生成時に、コントロールのインスタンス化・レイアウトのオーバーヘッドが Win7/AOT 環境で増幅されます。一方、TreeDataGrid は Avalonia チームが再構築した新しいコンポーネントで、「行レベルのレンダリング + 強制仮想化」という設計により切り替え時のオーバーヘッドが根本的に低減されており、公式でも DataGrid の代わりに TreeDataGrid を使用することが推奨されています。議論はリンクを参照。

ここで明確にしておくと、TreeDataGrid は Avalonia によって商用スイートに含まれています。

無料版を使用すると、発見したバグが修正されない可能性があります(公式は旧バージョンのメンテナンスをオープンソースコミュニティのブランチに委ねています)。Avalonia.Controls.TreeDataGrid の無料版では 11.1.1 以前のバージョンを使用できます:

Semi 提供の対応テーマライブラリのバージョンは 11.1.1.1 です。

まとめ

  1. Avalonia のエントリ関数 Main は同期で宣言する必要があります。async Task にすると同期コンテキストが破壊され、クリップボードなどのシステム操作で異常が発生します。
  2. DataGrid は Tab 切り替えのシナリオでパフォーマンス上の弱点があるため、公式推奨の TreeDataGrid を優先的に使用することでカクツキ問題を解決できます。
  3. Avalonia の古いコンポーネント(DataGrid など)は、古い OS(Win7/Server)+ AOT ビルド環境でパフォーマンス問題を露呈しやすいため、公式の新しいコンポーネントを優先的に選択することでトラブルを減らせます。忘れずに最新のコントロールライブラリを更新しましょう。

最後に、Avalonia 交流グループのメンバーに解決策を提供していただき感謝します。オープンソースコミュニティの交流は、このような「直感に反する」問題を迅速に特定するのに役立ちます~

さらに探索

関連読書

その他の記事