この記事は公開から4年以上経過しています。
WinForms上でWPFユーザーコントロールを使うと、WPFユーザーコントロールが破棄されるタイミングで内部例外が発生する問題の解決方法です。
限定されたケースでのみしか発生しないうえ例外自体もハンドルされているため問題に気付いていないケースもあると思いますが、気付いてしまい対応に迫られた方の解決の糸口になれば幸いです。
問題
WinForms上にElementHostコントロールを使って配置したWPFのユーザーコントロール上でツールチップやポップアップを表示すると、ElementHostをDisposeするタイミングで内部例外が発生する。また、このエラーが1度発生するとプロセスを再起動するまで他のElementHostの動作が極端に遅くなる。
確認できている再現条件は以下のとおり。
- VisualStudio2015、またはロードされるCLRバージョン(App.configのSKU指定)がv4.0の.NETプロジェクト
- デバッガでプロセスのモジュール一覧を確認したとき
Accessibility.dll
がロードされている(ソフトウェアキーボードやGoogle Chromeを起動していると自動的にロードされる) - WinFormsでElementHostを用いてWPFユーザーコントロールをホストしている
- 上記3のElementHostのWPFユーザーコントロールでウィンドウハンドルを持つツールチップ/ポップアップ(コンボボックス)などを表示
- 上記4のElementHostをDispose
これら全てを満たすと、VisualStudioの出力ウィンドウにのタイミングで例外がスローされました: 'System.ComponentModel.Win32Exception' (WindowsBase.dll の中)
といったエラーメッセージが表示される。
出力ウィンドウの出力内容:
例外設定のCommonLanguageRutimeの例外スローで中断を指定したときのエラー発生箇所:
例外が発生した処理のスタックトレース:
原因
ElementHostでWPFのユーザーコントロールをホストした場合、ビジュアルツリールート要素のAdornerDecoratorのAutomationPeerのNameが未設定であることから、以下のFrameworkコード部分で例外がスロー(ハンドル済)される。
また、当該エラー発生後にはプロセスを再起動するまで同じウィンドウハンドルを利用しているWPFユーザーコントロールにウィンドウメッセージが発生(マウスオーバーやクリックなど)する度に同じ例外がハンドルされるようになることで処理が遅くなる。
※Microsoft Reference Sourceから抜粋したFrameworkコード(赤枠内で例外発生)
対応
以下のようにビジュアルツリールート要素のAdornerDecorator
に対してAutomationProperties.Name
添付プロパティを設定することにより、例外が発生するロジックが実行されないようにする。
サンプルソースコード
C#
public Form()
{
InitializeComponent();
// ↓使用する全てのElementHostにこのイベントを追加
elementHost.HandleCreated += (o, e) =>
{
var preSrc = System.Windows.PresentationSource.FromVisual(elementHost.Child);
System.Windows.Automation.AutomationProperties.SetName(preSrc.RootVisual, elementHost.Name);
};
}
VB.NET
Public Sub New()
InitializeComponent()
' ↓使用する全てのElementHostにこのイベントを追加
AddHandler ElementHost.HandleCreated,
Sub(o, e)
Dim preSrc = System.Windows.PresentationSource.FromVisual(ElementHost.Child)
System.Windows.Automation.AutomationProperties.SetName(preSrc.RootVisual, ElementHost.Name)
End Sub
End Sub
以上です。