我有一个WPF应用程序,我想看起来它托管在另一个 - 非WPF - 应用程序中。在现实生活中,这个非WPF应用程序是Internet Explorer中的ActiveX,但为了说明问题,我使用了一个简单的Windows窗体应用程序。
我使用的是Windows API函数SetParent,它已经有很多线程了。但是,我找不到任何关于我的确切问题的内容: WPF应用程序右侧和底部的小区域未在非WPF应用程序窗口中绘制。
WPF窗口自行运行:
将WinForm应用程序窗口作为父级的WPF窗口:
如果将WPF应用程序与WinForms应用程序或普通Win32应用程序(如记事本)交换,我不会遇到此问题。
WinForm代码如下所示:
private void Form1_Load(object sender, EventArgs e)
{
// Start process
var psi = new ProcessStartInfo("c:\\wpfapp\\wpfapp\\bin\\Debug\\wpfapp.exe");
psi.WindowStyle = ProcessWindowStyle.Normal;
_process = Process.Start(psi);
// Sleep until new process is ready
Thread.Sleep(1000);
// Set new process's parent to this window
SetParent(_process.MainWindowHandle, this.Handle);
// Remove WS_POPUP and add WS_CHILD window style to child window
const int GWL_STYLE = -16;
const long WS_POPUP = 0x80000000;
const long WS_CHILD = 0x40000000;
long style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
style = (style & ~(WS_POPUP)) | WS_CHILD;
SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);
// Move and resize child window to fit into parent's
MoveWindow(_process.MainWindowHandle, 0, 0, this.Width, this.Height, true);
}
注意:我知道使用SetParent不一定是推荐的做法,但我想并且需要了解如何这样做,所以请让我:)
答案 0 :(得分:6)
我找到了一个运行良好的解决方法:在SetParent之前调用MoveWindow:
private void Form1_Load(object sender, EventArgs e)
{
// Start process
var psi = new ProcessStartInfo("C:\\WpfApp\\WpfApp.exe");
psi.WindowStyle = ProcessWindowStyle.Normal;
_process = Process.Start(psi);
// Sleep until new process is ready
Thread.Sleep(3000);
// Move and resize child window to fit into parent's
Rectangle rect;
GetClientRect(this.Handle, out rect);
MoveWindow(_process.MainWindowHandle, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top, true);
// Set new process's parent to this window
SetParent(_process.MainWindowHandle, this.Handle);
// Remove WS_POPUP and add WS_CHILD window style to child window
long style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
style = (style & ~(WS_POPUP) & ~(WS_CAPTION)) & ~(WS_THICKFRAME) | WS_CHILD;
SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);
}
在SizeChanged事件处理程序中,我将子项从父项中取出,调用MoveWindow并将其移回父项。为了减少闪烁,我在执行这些操作时隐藏了窗口:
private void Form1_SizeChanged(object sender, EventArgs e)
{
ShowWindow(_process.MainWindowHandle, SW_HIDE);
var ptr = new IntPtr();
SetParent(_process.MainWindowHandle, ptr);
Rectangle rect;
GetClientRect(this.Handle, out rect);
MoveWindow(_process.MainWindowHandle, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top, true);
SetParent(_process.MainWindowHandle, this.Handle);
ShowWindow(_process.MainWindowHandle, SW_SHOW);
}
它没有解释为什么MoveWindow在SetParent之后不起作用,但它解决了我的问题,所以除非出现更好的事情,否则我会将其标记为答案。
答案 1 :(得分:3)
您可能应该调整WPF窗口的大小,使其适合新父窗口的client area:
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
// Move and resize child window to fit into parent's client area.
RECT rc = new RECT();
GetClientRect(this.Handle, out rc);
MoveWindow(_process.MainWindowHandle, 0, 0, rc.Right - rc.Left,
rc.Bottom - rc.Top, true)
答案 2 :(得分:0)
我使用了Form / UserControl和Panel。然后我使用Panel作为新父级,并使用SetWindowPos将面板的新位置和大小设置为子窗口。
注意:MS建议在使用SetWindowLong(或SetWindowLongPtr)激活新样式后使用SetWindowPos。