C# wpf 实现窗口靠近屏幕边缘自动吸附
参考:https://blog.csdn.net/qq_35831134/article/details/88751067
#region 侧吸
private new bool Hide = false; //用来表示当前隐藏状态,例如Hide=false就是不在隐藏状态
string type = ""; //用来表示窗口隐藏在哪个方向
private void SliderTimer_Tick(object sender, EventArgs e)
{
//this.TopMost = false; //窗体不显示在所有软件最前面
int dif = 20;
Mouses.POINT mp = new Mouses.POINT();//获得当前鼠标位置
Mouses.GetCursorPos(out mp);
Point pt = new Point(mp.X, mp.Y);
System.Windows.Forms.Screen screen = System.Windows.Forms.Screen.PrimaryScreen;
int width = screen.Bounds.Width; //获取屏幕的宽度
int height = screen.Bounds.Height; //获取屏幕的高度
if (!this.RestoreBounds.Contains(pt)) //判断鼠标是否在窗体内
{
//如果不在窗体内
if (Hide == false)
{
if (this.Left < 10) //窗口左边碰到屏幕最左边
{
this.Left = -this.Width + 3; //隐藏窗口,窗口宽度加3取反(为负数)
Hide = true;
type = "left"; //窗口隐藏在左边
}
else if (width - this.Left - this.Width < 10)//窗口右边碰到屏幕最右边
{
this.Left = width - 3; //隐藏窗口,窗口宽度加3取反(为负数)
Hide = true;
type = "right"; //窗口隐藏在右边
}
else if (this.Top < 10) //窗口上边碰到屏幕最上边
{
this.Top = -this.Height + 3; //隐藏窗口,窗口高度加3取反(为负数)
Hide = true;
type = "up"; //窗口隐藏在上边
}
}
}
else
{ //如果在窗体内
if (this.Left > dif && type == "left")
{
Hide = false;
}
else if (width - this.Left - this.Width > dif && type == "right")
{
Hide = false;
}
else if (this.Top > dif && type == "up")
{
Hide = false;
}
//如果在窗体内且之前是隐藏状态
if (Hide == true)
{
this.Topmost = true; //窗体显示在所有软件最前面
if (type == "left")
{
this.Left = 0;
Hide = false;
}
else if (type == "right")
{
this.Left = width - this.Width;
Hide = false;
}
else if (type == "up")
{
this.Top = 0;
Hide = false;
}
}
}
}
private DispatcherTimer SlideTimer;
private void EnableSlider()
{
this.SlideTimer = new DispatcherTimer();
this.SlideTimer.Tick += SliderTimer_Tick;
this.SlideTimer.Interval = TimeSpan.FromMilliseconds(10);
this.SlideTimer.Start();
this.SizeChanged += (o, e) =>
{
if (this.WindowState == WindowState.Minimized)
{
this.SlideTimer.Stop();
}
else if (this.WindowState == WindowState.Normal)
{
this.SlideTimer.Start();
}
};
}
#endregion
【出处】:https://blog.csdn.net/weixin_53370274/article/details/122843287
=======================================================================================
wpf仿qq边缘自动停靠,支持多屏
wpf完全模仿qq边缘自动隐藏功能,采用鼠标钩子获取鼠标当前状态,在通过当前鼠标的位置和点击状态来计算是否需要隐藏。
以下是实现的具体方法:
一、鼠标钩子实时获取当前鼠标的位置和点击状态
/// <summary> /// 鼠标全局钩子 /// </summary> public class MouseHook { private const int WM_MOUSEMOVE = 0x200; private const int WM_LBUTTONDOWN = 0x201; private const int WM_RBUTTONDOWN = 0x204; private const int WM_MBUTTONDOWN = 0x207; private const int WM_LBUTTONUP = 0x202; private const int WM_RBUTTONUP = 0x205; private const int WM_MBUTTONUP = 0x208; private const int WM_LBUTTONDBLCLK = 0x203; private const int WM_RBUTTONDBLCLK = 0x206; private const int WM_MBUTTONDBLCLK = 0x209; /// <summary> /// 点 /// </summary> [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } /// <summary> /// 钩子结构体 /// </summary> [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; public int hWnd; public int wHitTestCode; public int dwExtraInfo; } public const int WH_MOUSE_LL = 14; // mouse hook constant // 装置钩子的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); // 卸下钩子的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(int idHook); // 下一个钩挂的函数 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr GetModuleHandle(string lpModuleName); // 全局的鼠标事件 public event MouseEventHandler OnMouseActivity; // 钩子回调函数 public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); // 声明鼠标钩子事件类型 private HookProc _mouseHookProcedure; private static int _hMouseHook = 0; // 鼠标钩子句柄 /// <summary> /// 构造函数 /// </summary> public MouseHook() { } /// <summary> /// 析构函数 /// </summary> ~MouseHook() { Stop(); } /// <summary> /// 启动全局钩子 /// </summary> public void Start() { // 安装鼠标钩子 if (_hMouseHook == 0) { // 生成一个HookProc的实例. _mouseHookProcedure = new HookProc(MouseHookProc); ProcessModule cModule = Process.GetCurrentProcess().MainModule; var mh = GetModuleHandle(cModule.ModuleName); _hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, _mouseHookProcedure,mh,0); //如果装置失败停止钩子 if (_hMouseHook == 0) { Stop(); throw new Exception("SetWindowsHookEx failed."); } } } /// <summary> /// 停止全局钩子 /// </summary> public void Stop() { bool retMouse = true; if (_hMouseHook != 0) { retMouse = UnhookWindowsHookEx(_hMouseHook); _hMouseHook = 0; } // 如果卸下钩子失败 // if (!(retMouse)) // throw new Exception("UnhookWindowsHookEx failed."); } int isUp = 0; /// <summary> /// 鼠标钩子回调函数 /// </summary> private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam) { try { // 如果正常运行并且用户要监听鼠标的消息 if ((nCode >= 0) && (OnMouseActivity != null)) { MouseButtons button = MouseButtons.None; int clickCount = 0; switch (wParam) { case WM_LBUTTONDOWN: button = MouseButtons.Left; clickCount = 1; isUp = 1; break; case WM_LBUTTONUP: button = MouseButtons.Left; clickCount = 1; isUp = 2; break; case WM_LBUTTONDBLCLK: button = MouseButtons.Left; clickCount = 2; break; case WM_RBUTTONDOWN: button = MouseButtons.Right; clickCount = 1; isUp = 1; break; case WM_RBUTTONUP: button = MouseButtons.Right; clickCount = 1; isUp = 2; break; case WM_RBUTTONDBLCLK: button = MouseButtons.Right; clickCount = 2; break; default: if (isUp == 2) isUp = 0; break; } // 从回调函数中得到鼠标的信息 MouseHookStruct MyMouseHookStruct = (MouseHookStruct) Marshal.PtrToStructure(lParam, typeof (MouseHookStruct)); var x = MyMouseHookStruct.pt.x; var y = MyMouseHookStruct.pt.y; MouseEventArgs e = new MouseEventArgs(button, clickCount, x, y, isUp); // 如果想要限制鼠标在屏幕中的移动区域可以在此处设置 // 后期需要考虑实际的x、y的容差 if (!Screen.PrimaryScreen.Bounds.Contains(e.X, e.Y)) { //return 1; } OnMouseActivity(this, e); } } catch (Exception ex) { Debug.WriteLine(ex); } // 启动下一次钩子 return CallNextHookEx(_hMouseHook, nCode, wParam, lParam); } }
二、判断窗口是否在屏幕边缘
如果是在屏幕边缘,并且鼠标离开窗体,那么就需要隐藏窗口
/// <summary> /// 检测是否需要隐藏窗体 /// </summary> /// <param name="e"></param> /// <param name="rect"></param> private void CheckIsHide(MouseEventArgs e,System.Drawing.Rectangle rect) { var x = e.X; var y = e.Y; if (x < rect.Left) x = rect.Left; if (x > rect.Right) x = rect.Right; if (y < rect.Top) y = rect.Top; if (y > rect.Bottom) y = rect.Bottom; bool isLeave = !(x >= this.Left && x <= (this.Left + this.ActualWidth) && y >= this.Top && y <= this.Top + this.ActualHeight); if (!isLeave) { //鼠标在窗体内移动时解除双击状态 _isNoticefyShow = false; return; } //isLeave=true if (_isNoticefyShow == false) { //顶部判断 if (this.Top - _border < rect.Top) { SetIsHide(true,rect); //这里修正高度为边界高度,这样做的原因主要是避免鼠标移动到边框上面时出现闪动 _oldTop = rect.Top; UpdateLeft(rect); } //左边判断 else if (this.Left - _border < rect.Left) { SetIsHide(true, rect); //这里修正左边 _oldLeft = rect.Left; this.Left = rect.Left - this.ActualWidth; UpdateTop(rect); } //右边判断 else if (this.Left+this.ActualWidth + _border > rect.Right) { SetIsHide(true, rect); //修正右边 _oldLeft = rect.Right - this.ActualWidth; this.Left = rect.Right; UpdateTop(rect); } } }
三、窗口隐藏时根据鼠标位置判断是否需要显示
如果鼠标在边框位置,并且进入了上次窗体隐藏的边框内,那么就显示窗体
/// <summary> /// 判断鼠标时候在窗体边缘 /// </summary> /// <returns></returns> private bool CheckMouseIsWindowBorder(MouseEventArgs e, System.Drawing.Rectangle rect) { //获取边界的值 //判断top if (e.Y - _border <= rect.Top && e.X >= this.Left && e.X <= (this.Left + this.ActualWidth)) { return true; } //判断left if (e.X - _border<=rect.Left && e.Y >= this.Top && e.Y <= (this.Top + this.ActualHeight)) { //显示 return true; } //判断right if (this.Left > rect.Left + _border && e.X + _border >= rect.Right && e.Y >= this.Top && e.Y <= (this.Top + this.ActualHeight)) { return true; } //SystemInformation.VirtualScreen. //判断右边 return false; }
四、双击托盘图标显示窗体
显示窗体简单,直接展示就可以,关键是要实现窗体显示后如果窗体还在屏幕边框位置,那么需要判断什么情况下需要隐藏窗体,现在有以下两种情况需要隐藏:
1.鼠标在离开任务栏后经过窗口后在离开窗口,窗口需要自动隐藏
2.鼠标在离开任务栏后在窗口外的其它位置点击,触发窗口自动隐藏
1情况容易,在进入窗体时清空托盘图标点击的标记就可以了
2情况处理有点麻烦,由于在窗口外的其他位置点击这个事件在双击托盘图标的时候也会触发,我们要屏蔽掉这时这个触发条件,只有在托盘外面时去点击才有效,具体的方案是,在鼠标从托盘移动时才标记点击事件有效,这样就可以避免顺序错乱了,部分代码如下;
(1).在双击托盘图标时标记状态:
_isNoticefyShow = true; _isCanSet = false;
(2).鼠标双击后,移动
if (e.Delta == 0 && _isNoticefyShow && _isCanSet == false) { //鼠标双击后,移动,并且没有设置 _isCanSet = true; return; }
(3).在鼠标移除托盘图标后,点击鼠标后,接触托盘双击状态
if ((e.Delta == 1 || e.Delta == 2) && _isNoticefyShow && _isCanSet) { _isNoticefyShow = false; CheckIsHide(e,rect); return; }
具体的实现demo地址如下:
https://gitee.com/sczmzx/WindowAutoHide
【出处】:https://www.cnblogs.com/sczmzx/p/8996371.html
=======================================================================================
关注我】。(●'◡'●)
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的【因为,我的写作热情也离不开您的肯定与支持,感谢您的阅读,我是【Jack_孟】!
本文来自博客园,作者:jack_Meng,转载请注明原文链接:https://www.cnblogs.com/mq0036/p/17662246.html
【免责声明】本文来自源于网络,如涉及版权或侵权问题,请及时联系我们,我们将第一时间删除或更改!