我在 WPF 项目中有以下 C# 代码:

private static void RunConfig(string owner)
{
    long ownerHandle;
    var settingsWindow = new SettingsWindow();
    if (long.TryParse(owner, out ownerHandle))
    {
        WindowInteropHelper helper = new WindowInteropHelper(settingsWindow);
        helper.Owner = new IntPtr(ownerHandle);
    }
    settingsWindow.ShowDialog();
}

SettingsWindow 对所有者窗口的模式不正确(即,当 SettingsWindow 仍然打开时,我可以专注于、交互甚至关闭所有者窗口)。我究竟做错了什么?

对于上下文,此代码是屏幕保护程序的一部分,所有者窗口是控制面板屏幕保护程序选择窗口(通过命令行参数传入句柄以用作所有者)。我知道 IF 语句正在评估 true 并正确解析句柄。

我还尝试使用 SetWindowLongPtr 中的 user32.dll 方法(为 x64 编译,因此不使用 SetWindowLong ),该方法简要描述了 here 并在使用 here 中显示。此方法在 WinForms 中有效,但在 WPF 中似乎不起作用。帮助我欧比旺克诺比,你是我唯一的希望。

最佳答案

事实证明,使用 WindowInteropHelper 将 native 窗口设置为 WPF 窗口的所有者确实有效,但它并不能完成整个工作。以这种方式设置时,即使 native 窗口具有焦点,WPF 窗口也将在 native 窗口的顶部保持可见。然而,这是唯一获得的效果。 WPF Window 不会阻​​止与原生 Window 的交互,甚至可以关闭原生窗口,而不会关闭或影响 WPF Window。

为了获得所需的其余行为,我们需要在 EnableWindow 中使用 user32.dll 函数在 WPF 窗口上调用 ShowDialog 之前禁用 native 窗口,并在 WPF 窗口关闭后再次重新启用它。

修改后的代码如下所示:

private static void RunConfig(string owner)
{
    long ownerHandle;
    var settingsForm = new SettingsWindow();
    if (long.TryParse(owner, out ownerHandle))
    {
        WindowInteropHelper helper = new WindowInteropHelper(settingsForm);
        helper.Owner = new IntPtr(ownerHandle);
        NativeMethods.EnableWindow(helper.Owner, false);
        settingsForm.ShowDialog();
        NativeMethods.EnableWindow(helper.Owner, true);
    }
    else
    {
        settingsForm.ShowDialog();
    }
}

(注:上面的代码大体上是正确的,但在屏幕保护程序的情况下是不完整的,这就是这段代码的实际用途。如果这段代码用于屏幕保护程序的配置窗口,则为所有者句柄传入的字符串不是要用作所有者的控制面板窗口的句柄,而是作为控制面板窗口的子控件的控件的句柄。在这种情况下,额外的步骤是获取句柄该控件的父级。我们可以通过在传入的句柄上调用 GetParent 来做到这一点,也在 user32.dll 中。这将返回我们想要用于所有者和 EnableWindow 调用的真实句柄。)

如果来自 Microsoft 的任何人发现了这一点,也许可以考虑修改 WindowInteropHelper 以在分配 Owner 并使用 ShowDialog 时正确设置所有这些,因为这是模态窗口的正确完整行为。

关于c# - WPF 窗口应该是 native 所有者窗口的模式,但不是,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14151038/

10-16 22:27