WPF窗体贴边自动隐藏

最近一个产品需要用到类似QQ的贴边自动隐藏功能,在网上搜索了不少,CV过去之后效果都不是很理想,而且网上能找到的代码基本上都写在一个方法里面,感觉维护也麻烦,于是研究了下其实现原理(无外乎就是实时监测鼠标位置,在鼠标位置满足条件的时候显示窗体;否则尝试隐藏),自己弄了一个,代码如下:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media.Animation;

namespace FAIS6.V3CS.Client.Phone.Core
{
    public class HideWindowHelper
    {
        private readonly Window _window;
        private readonly Timer _timer;
        private readonly List<HideCore> _hideLogicList = new List<HideCore>();

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern bool GetCursorPos(out Point pt);

        private struct Point
        {
            public int X;
            public int Y;

            // ReSharper disable once UnusedMember.Local
            public Point(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }
        }

        private bool _isHide;
        private bool _isStarted;
        private HideCore _lastHiderOn;
        private bool _isInAnimation;

        private HideWindowHelper(Window window)
        {
            _window = window;
            _timer = new Timer {Interval = 300};
            _timer.Tick += _timer_Tick;
        }

        public HideWindowHelper AddHider<THideCore>() where THideCore : HideCore, new()
        {
            if (_isStarted) throw new Exception("调用了Start方法后无法在添加隐藏逻辑");
            var logic = new THideCore();
            logic.Init(_window, AnimationReport);
            _hideLogicList.Add(logic);
            return this;
        }

        private void _timer_Tick(object sender, EventArgs e)
        {
            if (_isInAnimation) return;
            if (_window.IsActive) return;
            GetCursorPos(out var point); //获取鼠标相对桌面的位置
            var isMouseEnter = point.X >= _window.Left
                               && point.X <= _window.Left + _window.Width + 30
                               && point.Y >= _window.Top
                               && point.Y <= _window.Top
                               + _window.Height + 30;
            //鼠标在里面
            if (isMouseEnter)
            {
                //没有隐藏,直接返回
                if (!_isHide) return;

                //理论上不会出现为null的情况
                if (_lastHiderOn != null)
                {
                    _lastHiderOn.Show();
                    _isHide = false;
                    _window.ShowInTaskbar = true;
                    return;
                }
            }


            foreach (var core in _hideLogicList)
            {
                //鼠标在里面并且没有隐藏
                if (isMouseEnter && !_isHide) return;

                //鼠标在里面并且当期是隐藏状态且当前处理器成功显示了窗体
                if (isMouseEnter && _isHide && core.Show())
                {
                    _isHide = false;
                    _window.ShowInTaskbar = true;
                    return;
                }

                //鼠标在外面并且没有隐藏,那么调用当前处理器尝试隐藏窗体
                if (!isMouseEnter && !_isHide && core.Hide())
                {
                    _lastHiderOn = core;
                    _isHide = true;
                    _window.ShowInTaskbar = false;
                    return;
                }
            }
        }

        private void AnimationReport(bool isInAnimation)
        {
            _isInAnimation = isInAnimation;
        }

        public HideWindowHelper Start()
        {
            _isStarted = true;
            _timer.Start();
            return this;
        }

        public void Stop()
        {
            _timer.Stop();
            _isStarted = false;
        }

        public static HideWindowHelper CreateFor(Window window)
        {
            return new HideWindowHelper(window);
        }

        public void TryShow()
        {
            if (_lastHiderOn == null) return;
            _lastHiderOn.Show();
            _isHide = false;
            _window.Activate();
        }
    }

    #region 隐藏逻辑基类

    public abstract class HideCore
    {
        private Window _window;
        private Action<bool> _animationStateReport;

        internal void Init(Window window, Action<bool> animationStateReport)
        {
            _window = window;
            _animationStateReport = animationStateReport;
        }

        public abstract bool Show();

        public abstract bool Hide();

        protected Window WindowInstance => _window;

        protected void StartAnimation(DependencyProperty property, double from, double to)
        {
            _animationStateReport(true);
            var doubleAnimation = new DoubleAnimation(from, to, TimeSpan.FromSeconds(0.5));
            doubleAnimation.Completed += delegate
            {
                _window.BeginAnimation(property, null);
                _animationStateReport(false);
            };
            _window.BeginAnimation(property, doubleAnimation);
        }
    }

    #endregion

    #region 向上隐藏

    class HideOnTop : HideCore
    {
        public override bool Show()
        {
            if (WindowInstance.Top > 0) return false;
            StartAnimation(Window.TopProperty, WindowInstance.Top, 0);
            return true;
        }

        public override bool Hide()
        {
            if (WindowInstance.Top > 2) return false;
            StartAnimation(Window.TopProperty, WindowInstance.Top, 0 - WindowInstance.Top - WindowInstance.Height + 2);
            return true;
        }
    }

    #endregion

    #region 向左隐藏

    class HideOnLeft : HideCore
    {
        public override bool Show()
        {
            if (WindowInstance.Left > 0) return false;
            StartAnimation(Window.LeftProperty, WindowInstance.Left, 0);
            return true;
        }

        public override bool Hide()
        {
            if (WindowInstance.Left > 2) return false;
            StartAnimation(Window.LeftProperty, WindowInstance.Left, 0 - WindowInstance.Width + 2);
            return true;
        }
    }

    #endregion

    #region 向右隐藏

    class HideOnRight : HideCore
    {
        private readonly int _screenWidth;

        public HideOnRight()
        {
            foreach (var screen in Screen.AllScreens)
            {
                _screenWidth += screen.Bounds.Width;
            }
        }

        public override bool Show()
        {
            if (_screenWidth - WindowInstance.Left - WindowInstance.Width > 0) return false;
            StartAnimation(Window.LeftProperty, WindowInstance.Left, _screenWidth - WindowInstance.Width);
            return true;
        }

        public override bool Hide()
        {
            if (_screenWidth - WindowInstance.Left - WindowInstance.Width > 2) return false;
            StartAnimation(Window.LeftProperty, WindowInstance.Left, _screenWidth - 2);
            return true;
        }
    }

    #endregion
}

代码将公共逻辑抽离,然后由单独的子类实现具体的隐藏和显示逻辑,外部调用代码如下:

_hideWindowHelper = HideWindowHelper
                .CreateFor(this)
                .AddHider<HideOnLeft>()
                .AddHider<HideOnRight>()
                .AddHider<HideOnTop>();

初始化隐藏助手,并且添加需要实现的贴边功能,左右优先,然后是向上隐藏

 _hideWindowHelper.Start(); //启动隐藏
 _hideWindowHelper.TryShow();//用代码触发显示,适用于双击任务栏图标

用户也可以自行实现贴边功能,只需要继承HideCore类即可

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
WPF仿QQ贴边自动隐藏功能主要是通过设置窗口的动画效果来实现的。首先,需要监听窗口的位置变化事件,当窗口靠近屏幕边缘时,触发隐藏动画效果。其次,可以使用WPF自带的动画库,如DoubleAnimation、Storyboard等,来定义窗口隐藏时的动画效果。在动画完成后,将窗口的Visibility属性设置为Collapsed来实现窗口隐藏。 下面是实现这一功能的一段简单源码示例: ```csharp private void Window_LocationChanged(object sender, EventArgs e) { double screenWidth = SystemParameters.PrimaryScreenWidth; double screenHeight = SystemParameters.PrimaryScreenHeight; double pixelsFromTop = this.Top; double pixelsFromBottom = screenHeight - this.Top - this.ActualHeight; double pixelsFromLeft = this.Left; double pixelsFromRight = screenWidth - this.Left - this.ActualWidth; double boundary = 10; // 靠边触发隐藏的距离阈值 if (pixelsFromTop < boundary || pixelsFromBottom < boundary || pixelsFromLeft < boundary || pixelsFromRight < boundary) { // 如果靠近边缘,执行隐藏动画 DoubleAnimation animation = new DoubleAnimation(1, 0, new Duration(TimeSpan.FromSeconds(0.5))); this.BeginAnimation(UIElement.OpacityProperty, animation); } else { // 如果不靠近边缘,取消隐藏动画 DoubleAnimation animation = new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(0.5))); this.BeginAnimation(UIElement.OpacityProperty, animation); } } ``` 这段代码中,通过监听窗口的LocationChanged事件,计算窗口与屏幕边缘的距离,并根据一定的阈值来触发隐藏动画效果。当窗口靠近边缘时,执行隐藏动画,动画完成后将窗口的Opacity属性设置为0,实现窗口隐藏。当窗口远离边缘时,取消隐藏动画,并将窗口的Opacity属性设置为1,使窗口重新显示出来。通过这种方式,就可以实现仿QQ贴边自动隐藏的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值