c# - C# WPF 和 WinForms 互操作 - CenterOwner 无效
问题描述
我正在开发一个使用 WPF 和 WinForms 作为其 UI 的遗留应用程序。WPF 占了绝大多数,但应用程序主对话框仍在 WinForms 中。
到目前为止,我已经能够让它们很好地协同工作(感谢 System.Windows.Forms.Integration.ElementHost),但我无法让 WPF 窗口以它们的 WinForms 父级为中心。
我的代码如下所示。
WPF 控件(托管在 ElementHost 中)
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var dialog = new SubWindow();
WindowOwnershipHelper.SetOwner(dialog, this);
dialog.ShowDialog();
}
OwnershipHelper(取自https://stackoverflow.com/a/36606974/13567181)
此类建立“父子”关系,以便嵌套对话框在同一屏幕上打开并与其父级一起最小化...
public static class WindowOwnershipHelper
{
public static void SetOwner(Window window, Visual parent)
{
var source = (HwndSource) PresentationSource.FromVisual(parent);
if (source == null)
{
throw new InvalidOperationException("Could not determine parent from visual.");
}
new WindowInteropHelper(window).Owner = source.Handle;
}
}
我面临的问题是,当dialog.ShowDialog()执行时,新打开的窗口根本不在其所有者周围。它在屏幕上的某个地方,但我不太明白它是如何确定它的位置的。
有趣的是,如果我再次在SubWindow类中重复ButtonBase_OnClick代码,这个新窗口完全围绕它的SubWindow父级居中。
从我的角度来看,这与SubWindow的ElementHost父级有关。
有人可以告诉我如何在不手动计算其位置的情况下让子窗口围绕其父窗口居中吗?(类似于此https://stackoverflow.com/a/42401001/13567181)
编辑:我刚刚在 MSDN 上找到了这个 - 它有点相似,但我不确定。https://social.msdn.microsoft.com/Forums/vstudio/en-US/05768951-73cf-4daf-b369-0905ca7e5222/centering-wpf-window-on-winforms-owner-window?forum=wpf
最好的问候诺伯特
解决方案
使用Application.Run(new MyForm2());
然后单击按钮来创建一个WPF Window
以主窗体为中心的。
public class MyForm2 : Form {
public MyForm2() {
this.Size = new Size(600,600);
this.StartPosition = FormStartPosition.CenterScreen;
Button btn = new Button { Text = "New Window", AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink };
btn.Click += btn_Click;
Controls.Add(btn);
}
void btn_Click(object sender, EventArgs e) {
var w = new System.Windows.Window();
w.SourceInitialized += w_SourceInitialized;
w.Width = 400.0; // number of actual pixels might be different
w.Height = 400.0; // depending on DPI. My laptop is 120 dpi, so 400.0 -> 400 * 120 / 96 = 500 pixels.
w.Title = "WPF Window";
w.ShowDialog();
}
void w_SourceInitialized(object sender, EventArgs e) {
var w = (System.Windows.Window) sender;
WindowInteropHelper helper = new WindowInteropHelper(w);
//w.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner; does nothing
int GWL_HWNDPARENT = -8;
SetWindowLongInternal(helper.Handle, GWL_HWNDPARENT, this.Handle);
Rectangle r = this.Bounds;
RECT r2 = new RECT();
GetWindowRect(helper.Handle, out r2);
int w2 = r2.Right - r2.Left;
int h2 = r2.Bottom - r2.Top;
int x2 = r.X + (r.Width - w2) / 2;
int y2 = r.Y + (r.Height - h2) / 2;
uint SWP_NOSIZE = 0x0001;
uint SWP_NOZORDER = 0x0004;
uint SWP_NOREDRAW = 0x0008;
uint SWP_NOACTIVATE = 0x0010;
uint SWP_NOCOPYBITS = 0x0100;
uint SWP_NOOWNERZORDER = 0x0200;
uint flags = SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER;
SetWindowPos(helper.Handle, IntPtr.Zero, x2, y2, 0, 0, flags);
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int w, int h, uint uFlags);
[DllImport("user32.dll", SetLastError=true)]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", SetLastError=true)]
private static extern int SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
private static int SetWindowLongInternal(IntPtr hWnd, int nIndex, IntPtr dwNewLong) {
if (IntPtr.Size == 4)
return SetWindowLong(hWnd, nIndex, dwNewLong);
return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
}
}
推荐阅读
- javascript - 如何将可写缓冲区通过管道传输到 ReadStream?
- php - 何时(以及为什么何时)以及我应该如何在 php 中清理来自 POST JSON 的数据(这样输出可在 Swift 和 HTML 中使用)
- java - 如何避免在这里创建类似对象的冗余实例化?
- reactjs - 如何将触摸事件传递给 react-draggable
- windows - 使用管理员权限将批处理文件转换为 Exe
- java - 如何将 >1000 个字符串放入数组中并使其可搜索?
- javascript - 问题:如何使(null)不出现在(document.write)中
- c# - CLI Main 中的依赖注入,对象为空
- excel - 使用用户表单更新现有行数据
- python-3.x - 使用配置文件从 python 连接到 oracle db