让子窗口和父窗口同时处于"激活状态"
来源:互联网 发布:数据库的储存特点 编辑:程序博客网 时间:2024/06/01 08:09
让子窗口和父窗口同时处于"激活状态"
周银辉
一般情况下,激活父窗口的时候,子窗口会失去焦点,同理,激活子窗口的时候,父窗口也会失去焦点,这在某些时候不太好看,比如子窗口作为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();
};
}
}
}
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();
}
{
var child = new ChildWindow {Owner = this};
child.RegisterAsActivePreemptionDisabledWindow(this);
child.Show();
}
- 让子窗口和父窗口同时处于"激活状态"
- 父窗口和子窗口同时移动问题?
- 父窗口和子窗口
- c# 子窗口关闭父窗口(适用于机器码激活)
- 关闭父窗口同时关闭子窗口问题
- 子窗口怎么在关闭的同时刷新父窗口
- 子窗口保存修改并关闭,同时刷新父窗口
- 子窗口保存修改并关闭,同时刷新父窗口
- 子窗口保存时,同时刷新父窗口
- 【涨姿势】关闭子窗口的同时刷新父窗口
- MFC子窗口和父窗口
- 子窗口和父窗口之间杂谈
- 父窗口和子窗口通信 opener
- MFC子窗口和父窗口
- VC父窗口和子窗口
- MFC子窗口和父窗口
- Qt-父窗口和子窗口
- 子窗口父窗口
- 渐行渐远
- SICP学习笔记(2.2.3)
- SICP学习笔记 (2.2.4)
- SICP学习笔记(2.3.1~2.3.2)
- SICP学习笔记(2.3.3)
- 让子窗口和父窗口同时处于"激活状态"
- 呵呵呵,传说中的吉普赛读心术(WPF版)
- c# 中的delegate - 未完成
- SICP学习笔记(2.3.4)
- QQ返利圣诞8天购物狂欢节(12月19~12月26日)
- C#中 set 和 get 的用法
- 大家好
- 程序设计中的环境
- PLSQL Developer设置 保存布局