让子窗口和父窗口同时处于激活状态

                                    让子窗口和父窗口同时处于激活状态
                                             周银辉

一般情况下,激活父窗口的时候,子窗口会失去焦点,同理,激活子窗口的时候,父窗口也会失去焦点,这在某些时候不太好看,比如子窗口作为ToolWindow漂浮在父窗口上面时。Visual Studio好像也有这个问题,当激活其中某个处于浮动状态的DockingPanel时,Visual Studio主窗口会失去焦点。
上两幅图,更明白点,
一般效果如下:

我们现在追求的效果如下:

恩,这里有个简单的包装,呵呵,复制下代码就可以直接使用了(Framework版本需要3.5):

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace YourNamespace
{
    
public static class WindowActiveService
    {
        
internal class WindowActiveHelper
        {
            [DllImport(
"user32", CharSet = CharSet.Auto)]
            
private extern static int SendMessage(
               IntPtr handle, 
int msg, int wParam, IntPtr lParam);

            [DllImport(
"user32.dll")]
            
private static extern IntPtr GetForegroundWindow();

// ReSharper disable InconsistentNaming
            private const int WM_NCACTIVATE = 0x086;
// ReSharper restore InconsistentNaming
            private IntPtr ownerHwnd = IntPtr.Zero;
            
private IntPtr childHwnd = IntPtr.Zero;
            
private HwndSource ownerHwndSource;
            
private HwndSource childHwndSource;
            
private HwndSourceHook ownerHook;
            
private HwndSourceHook childHook;
            
private bool childActive;
            
private bool ownerActive;

            
private static IntPtr GetWindowHwnd(Window window)
            {
                var helper 
= new WindowInteropHelper(window);
                
return helper.Handle;
            }

            
private IntPtr FilterChildMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
            {
                
if (msg == WM_NCACTIVATE)
                {
                    
if (((int)wParam) == 0)
                    {
                        IntPtr handle 
= GetForegroundWindow();
                        
if (handle == childHwnd || handle == ownerHwnd)
                        {
                            
if (childActive == false)
                            {
                                childActive 
= true;
                                SendMessage(childHwnd, WM_NCACTIVATE, 
1, IntPtr.Zero);
                            }
                            
if (ownerActive == false)
                            {
                                ownerActive 
= true;
                                SendMessage(ownerHwnd, WM_NCACTIVATE, 
1, IntPtr.Zero);
                            }
                        }
                        
else
                        {
                            
if (childActive)
                            {
                                childActive 
= false;
                                SendMessage(childHwnd, WM_NCACTIVATE, 
0, IntPtr.Zero);
                            }
                            
if (ownerActive)
                            {
                                ownerActive 
= false;
                                SendMessage(ownerHwnd, WM_NCACTIVATE, 
0, IntPtr.Zero);
                            }
                        }
                    }
                    
if (((int)wParam) == 1)
                    {
                        
if (childActive == false)
                        {
                            childActive 
= true;
                            SendMessage(childHwnd, WM_NCACTIVATE, 
1, IntPtr.Zero);
                        }
                        
if (ownerActive == false)
                        {
                            ownerActive 
= true;
                            SendMessage(ownerHwnd, WM_NCACTIVATE, 
1, IntPtr.Zero);
                        }
                    }

                }

                
return IntPtr.Zero;
            }

            
private IntPtr FilterOwnerMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
            {
                
if (msg == WM_NCACTIVATE)
                {
                    
if (((int)wParam) == 0)
                    {
                        IntPtr handle 
= GetForegroundWindow();
                        
try
                        {
                            
if (handle == ownerHwnd || handle == childHwnd)
                            {
                                
if (ownerActive == false)
                                {
                                    ownerActive 
= true;
                                    SendMessage(ownerHwnd, WM_NCACTIVATE, 
1, IntPtr.Zero);
                                }
                                
if (childActive == false)
                                {
                                    childActive 
= true;
                                    SendMessage(childHwnd, WM_NCACTIVATE, 
1, IntPtr.Zero);
                                }
                            }
                            
else
                            {
                                
if (ownerActive)
                                {
                                    ownerActive 
= false;
                                    SendMessage(ownerHwnd, WM_NCACTIVATE, 
0, IntPtr.Zero);
                                }
                                
if (childActive)
                                {
                                    childActive 
= false;
                                    SendMessage(childHwnd, WM_NCACTIVATE, 
0, IntPtr.Zero);
                                }
                            }
                        }
// ReSharper disable EmptyGeneralCatchClause
                        catch (Exception)
// ReSharper restore EmptyGeneralCatchClause
                        {
                        }
                    }
                    
if (((int)wParam) == 1)
                    {
                        
if (ownerActive == false)
                        {
                            ownerActive 
= true;
                            SendMessage(ownerHwnd, WM_NCACTIVATE, 
1, IntPtr.Zero);
                        }
                        
if (childActive == false)
                        {
                            childActive 
= true;
                            SendMessage(childHwnd, WM_NCACTIVATE, 
1, IntPtr.Zero);
                        }
                    }


                }

                
return IntPtr.Zero;
            }


            
private void RemoveChildHook()
            {
                
if (childHwndSource != null && childHook != null)
                {
                    childHwndSource.RemoveHook(childHook);
                }
            }


            
private void RemoveOwnerHook()
            {
                
if (ownerHwndSource != null && ownerHook != null)
                {
                    ownerHwndSource.RemoveHook(ownerHook);
                }
            }

            
public void RegisterFloatingToolWindow(Window childWindow, Window ownerWindow)
            {
                childWindow.Owner 
= ownerWindow;


                childWindow.Unloaded 
+= ((sender, args) => RemoveChildHook());
                ownerWindow.Unloaded 
+= ((sender, args) => RemoveOwnerHook());

                childWindow.Activated 
+= ((sender, args) => childActive = true);
                ownerWindow.Activated 
+= ((sender, args) => ownerActive = true);

                childWindow.Deactivated 
+= ((sender, args) => childActive = false);
                ownerWindow.Deactivated 
+= ((sender, args) => ownerActive = false);


                childHwnd 
= GetWindowHwnd(childWindow);
                ownerHwnd 
= GetWindowHwnd(ownerWindow);
                childHwndSource 
= HwndSource.FromHwnd(childHwnd);
                ownerHwndSource 
= HwndSource.FromHwnd(ownerHwnd);
                childHook 
= new HwndSourceHook(FilterChildMessage);
                ownerHook 
= new HwndSourceHook(FilterOwnerMessage);

                
if (childHwndSource != null)
                {
                    childHwndSource.AddHook(childHook);
                }

                
if (ownerHwndSource != null)
                {
                    ownerHwndSource.AddHook(ownerHook);
                }
            }
        }

        
/// <summary>
        
/// (notes: call this before loading)
        
/// </summary>
        public static void RegisterAsActivePreemptionDisabledWindow(this Window window, Window owner)
        {
            var helper 
= new WindowActiveHelper();
            window.Loaded 
+= delegate
            {
                helper.RegisterFloatingToolWindow(window, owner);
                owner.Activate();
            };
        }
    }
}

如何使用上面的代码:
在子窗口Show之前,调用RegisterAsActivePreemptionDisabledWindow()方法。比如上图中,点击主窗口的Button,然后:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var child = 
new ChildWindow {Owner = this};
            
            child.RegisterAsActivePreemptionDisabledWindow(this);

            child.Show();
        }
原文地址:https://www.cnblogs.com/zhouyinhui/p/1623936.html