WPF窗口应该是本机所有者窗口的模态,但不是

Ste*_*les 3 c# wpf native window owner

我在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();  
}
Run Code Online (Sandbox Code Playgroud)

SettingsWindow对所有者窗口没有正确的模态(即,当SettingsWindow仍处于打开状态时,我可以专注于,与所有者窗口交互,甚至关闭所有者窗口).我究竟做错了什么?

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

我已经使用也尝试SetWindowLongPtr从方法user32.dll(编译为64位,因此不使用SetWindowLong),其被简要地描述在这里,并且在使用中所示此处.此方法适用于WinForms,但似乎在WPF中不起作用.帮助我Obi-Wan Kenobi,你是我唯一的希望.

Ste*_*les 6

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

为了获得所需的其他行为,我们需要在调用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

(注意:上面的代码一般是正确的,但在屏幕保护程序的情况下是不完整的,这是实际使用的代码.在这个代码被用于屏幕保护程序的配置窗口的情况下,为所有者句柄传入的字符串不是要用作所有者的控制面板窗口的句柄,而是控制面板窗口的子控件的句柄.这种情况下的额外步骤是获取句柄该控件的父,我们可以通过调用做到这一点GetParent,也是user32.dll,对传入的手柄,这将恢复我们要使用的所有者和真正的手柄EnableWindow电话.)

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