4

我在 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 语句正在评估真实并正确解析句柄。

我也尝试过使用SetWindowLongPtr来自user32.dll(为 x64 编译,因此不使用)的方法,这里SetWindowLong简要描述并在此处使用中显示。此方法适用于 WinForms,但似乎不适用于 WPF。帮助我欧比旺克诺比,你是我唯一的希望。

4

1 回答 1

7

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

为了获得所需的其余行为,我们需要在调用 WPF 窗口之前使用EnableWindow函数user32.dll来禁用本机窗口ShowDialog,并在 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时正确设置所有这些,因为这是模式窗口的正确完整行为。OwnerShowDialog

于 2013-01-18T00:06:20.877 回答