En WPF, ¿cómo puede dibujar una línea sobre un WindowsFormsHost?
-
06-07-2019 - |
Pregunta
Aquí está mi XAML
<Grid
Name="grid">
<TextBlock
Text="Some Label" />
<WindowsFormsHost
Name="winFormsHost">
</WindowsFormsHost>
</Grid>
En la carga del formulario ejecuto el siguiente método
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;
}
La línea solo se dibuja cuando comento la siguiente línea.
this.winFormsHost.Child = oldSchoolTextbox;
¿Cómo dibujo una línea sobre el control WindowsFormsHost?
Solución
Hay algo que Microsoft ha llamado "espacio aéreo" eso evita que esto suceda, al menos fácilmente. Aquí está la página de interoperabilidad de WPF que describe el espacio aéreo . [Tiene un enfoque DX, pero lo mismo se aplica, exactamente como se indica, a WindowsFormsHost.]
WindowsFormsHost (cuando tiene un hijo) crea un HWND separado, lo que evita que el contexto de representación WPF se muestre en ese rectángulo.
La mejor opción para solucionar esto requiere .NET 3.5sp1 (al menos para trabajar de manera confiable). Puede solucionar esto creando una ventana de fondo 100% transparente y completamente separada, y colocándola sobre el control de host de Windows Forms. Luego dibuja en eso, y se mostrará correctamente.
Es una sensación un tanto rara, pero funciona.
Otros consejos
He tenido el mismo problema, y ??después de buscar por todas partes también terminé usando la ventana transparente 'overlay' en la parte superior de WindowsFormsHost. Para mantener su ventana principal sincronizada con la ventana de superposición, debe controlar los siguientes eventos:
Evento LocationChanged para su MainWindow y Evento LayoutUpdated para su elemento WindowsFormsHost. Ambos controladores de eventos deberían llamar a una función que mueva su ventana de superposición transparente sobre la ventana de WindowsFormsHost (SyncOverlayPosition () en el ejemplo a continuación).
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;
}
La respuesta aceptada funciona. Sin embargo, el único problema es que la ventana transparente se mostrará sobre mi ventana principal. También tuve que conectarme para asegurarme de que todo estuviera sincronizado.
Hice algo ligeramente diferente a una ventana transparente. Esto funcionó en mi caso, pero puede que no siempre funcione.
Creé un control de usuario de Windows Form. Puse el cuadro de texto y el dibujo lineal en el control de usuario del formulario de Windows. Esto me permitió dibujar sobre él y mostrarlo en una aplicación WPF usando WindowsFormsHost.