WPFでは、WindowsFormsHost上にどのように線を引くことができますか?
-
06-07-2019 - |
質問
これが私のXAMLです
<Grid
Name="grid">
<TextBlock
Text="Some Label" />
<WindowsFormsHost
Name="winFormsHost">
</WindowsFormsHost>
</Grid>
フォームのロード時に、次のメソッドを実行します
protected void OnLoad(object sender, RoutedEventArgs e)
{
// Create a line on the fly
Line line = new Line();
line.Stroke = Brushes.Red;
line.StrokeThickness = 17;
line.X1 = 50;
line.Y1 = 50;
line.X2 = 250;
line.Y2 = 50;
this.grid.Children.Add(line);
System.Windows.Forms.TextBox oldSchoolTextbox = new System.Windows.Forms.TextBox();
oldSchoolTextbox.Text = "A bunch of Random Text will follow. ";
oldSchoolTextbox.WordWrap = true;
oldSchoolTextbox.Width = 300;
for (int i = 0; i < 250; i++)
{
oldSchoolTextbox.Text += "abc ";
if (i % 10 == 0)
{
oldSchoolTextbox.Text += Environment.NewLine;
}
}
this.winFormsHost.Child = oldSchoolTextbox;
}
次の行をコメントアウトした場合にのみ線が描画されます。
this.winFormsHost.Child = oldSchoolTextbox;
WindowsFormsHostコントロール上に線を引くにはどうすればよいですか
解決
マイクロソフトが「空域」と呼んでいるものがあります。少なくとも簡単に、これが起こるのを防ぎます。以下は、空域を説明するWPF相互運用ページです。 [DXフォーカスを持っていますが、前述のとおり、WindowsFormsHostにも同じことが当てはまります。]
WindowsFormsHost(子がある場合)は別のHWNDを作成し、WPFレンダリングコンテキストがその四角形に表示されないようにします。
これを回避するための最適なオプションには、.NET 3.5sp1が必要です(少なくとも確実に動作するため)。これを回避するには、完全に独立した完全に透明な背景ウィンドウを作成し、それをウィンドウフォームのホストコントロールの上に配置します。その後、そこに描画すると、正しく表示されます。
ややハック感がありますが、動作します。
他のヒント
同じ問題が発生しました。また、全体を検索した後、WindowsFormsHostの上にある透明な「オーバーレイ」ウィンドウを使用することになりました。メインウィンドウとオーバーレイウィンドウの同期を維持するには、次のイベントを処理する必要があります。
MainWindowのLocationChangedイベント そして WindowsFormsHost要素のLayoutUpdatedイベント。これらのイベントハンドラーは両方とも、WindowsFormsHostウィンドウの上に透明オーバーレイウィンドウを移動する関数を呼び出す必要があります(以下の例のSyncOverlayPosition())。
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.LocationChanged += new EventHandler(MainWindow_LocationChanged);
_windowsFormsHost.LayoutUpdated += new EventHandler(_windowsFormsHost_LayoutUpdated);
}
void MainWindow_LocationChanged(object sender, EventArgs e)
{
SyncOverlayPosition();
}
void _windowsFormsHost_LayoutUpdated(object sender, EventArgs e)
{
SyncOverlayPosition();
}
void SyncOverlayPosition()
{
Point hostTopLeft = _windowsFormsHost.PointToScreen(new Point(0, 0));
_overlayWindow.Left = hostTopLeft.X;
_overlayWindow.Top = hostTopLeft.Y;
_overlayWindow.Width = _windowsFormsHost.ActualWidth;
_overlayWindow.Height = _windowsFormsHost.ActualHeight;
}
受け入れられた答えは機能します。ただし、唯一の問題は、透明なウィンドウがメインウィンドウの上に表示されることです。また、すべてが同期していることを確認するために、動きにフックする必要がありました。
透明なウィンドウとは少し違うことをしました。これは私の場合は機能しましたが、常に機能するとは限りません。
Windowsフォームユーザーコントロールを作成しました。テキストボックスと線画をユーザーフォームのウィンドウに配置します。これにより、その上に描画し、WindowsFormsHostを使用してWPFアプリケーションに表示することができました。