WPF 仿QQ无边框窗体(自动隐藏/可缩放/最大化不覆盖任务栏)

今天做一个综合案例,WPF的仿QQ窗体,贴边自动隐藏,无边框窗体,可拖拽实现缩放,最大化不覆盖任务栏。
无边框窗体缩放,上一篇文章已经介绍了,不过今天使用的方法更简单,不会占用视图的资源,纯代码完成。
使用事件:
OnMouseLeftButtonDown(),OnMouseMove(),OnMouseLeave()三个事件完成这些操作。都使用当前窗体的三个事件完成,不需要借用子元素。
核心事件在OnMouseMove中,原理是,当鼠标移动到窗体边缘时,判断鼠标是否按下,如果按下了,即进行缩放操作并改变鼠标样式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Win32.POINT p;
if (!Win32.GetCursorPos( out p))
    return ;
if ( this .Left <= p.x && this .Left + RESIZE_BORDER >= p.x
    && this .Top <= p.y && this .Top + RESIZE_BORDER >= p.y)
{
    this .Cursor = Cursors.SizeNWSE;
    if (e.LeftButton == MouseButtonState.Pressed)
        Win32.SendMessage(_HwndSource.Handle, 0x112, (IntPtr)(61444), IntPtr.Zero);
}
else if ( this .Left <= p.x && this .Left + RESIZE_BORDER >= p.x
    && this .Top + this .ActualHeight - RESIZE_BORDER <= p.y && this .Top + this .ActualHeight >= p.y)
{
    this .Cursor = Cursors.SizeNESW;
    if (e.LeftButton == MouseButtonState.Pressed)
        Win32.SendMessage(_HwndSource.Handle, 0x112, (IntPtr)(61447), IntPtr.Zero);
}
else if ( this .Left + this .ActualWidth - RESIZE_BORDER <= p.x && this .Left + this .ActualWidth >= p.x
    && this .Top <= p.y && this .Top + RESIZE_BORDER >= p.y)
{
    this .Cursor = Cursors.SizeNESW;
    if (e.LeftButton == MouseButtonState.Pressed)
        Win32.SendMessage(_HwndSource.Handle, 0x112, (IntPtr)(61445), IntPtr.Zero);
}
else if ( this .Left + this .ActualWidth - RESIZE_BORDER <= p.x && this .Left + this .ActualWidth >= p.x
    && this .Top + this .ActualHeight - RESIZE_BORDER <= p.y && this .Top + this .ActualHeight >= p.y)
{
    this .Cursor = Cursors.SizeNWSE;
    if (e.LeftButton == MouseButtonState.Pressed)
        Win32.SendMessage(_HwndSource.Handle, 0x112, (IntPtr)(61448), IntPtr.Zero);
}
else if ( this .Top <= p.y && this .Top + RESIZE_BORDER >= p.y)
{
    this .Cursor = Cursors.SizeNS;
    if (e.LeftButton == MouseButtonState.Pressed)
        Win32.SendMessage(_HwndSource.Handle, 0x112, (IntPtr)(61443), IntPtr.Zero);
}
else if ( this .Left <= p.x && this .Left + RESIZE_BORDER >= p.x)
{
    this .Cursor = Cursors.SizeWE;
    if (e.LeftButton == MouseButtonState.Pressed)
        Win32.SendMessage(_HwndSource.Handle, 0x112, (IntPtr)(61441), IntPtr.Zero);
}
else if ( this .Top + this .ActualHeight - RESIZE_BORDER <= p.y && this .Top + this .ActualHeight >= p.y)
{
    this .Cursor = Cursors.SizeNS;
    if (e.LeftButton == MouseButtonState.Pressed)
        Win32.SendMessage(_HwndSource.Handle, 0x112, (IntPtr)(61446), IntPtr.Zero);
}
else if ( this .Left + this .ActualWidth - RESIZE_BORDER <= p.x && this .Left + this .ActualWidth >= p.x)
{
    this .Cursor = Cursors.SizeWE;
    if (e.LeftButton == MouseButtonState.Pressed)
        Win32.SendMessage(_HwndSource.Handle, 0x112, (IntPtr)(61442), IntPtr.Zero);
}
else
{
    this .Cursor = Cursors.Arrow;
}

我们知道当窗体拖拽移动时,也会激发这个事件,所以,我们再判断,窗体是否已经移动到屏幕边缘,如果是的话,让窗体隐藏,即移动窗体到屏幕上面,只保留一个小边,如果窗体已经隐藏,则显示窗体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
if ( this ._IsHidded)
{
    if ( this .Left < p.x && this .Left + this .ActualWidth > p.x && this .Top < p.y && this .Top + this .ActualHeight > p.y)
    {
        this .Top = 0;
        this .Topmost = false ;
    }
}
else
{
    if ( this .Top <= 0 && this .Left <= 0)
    {
        this .Left = 0;
        this .Top = HIDE_BORDER - this .ActualHeight;
        this ._Location = ELocation.LeftTop;
        this ._IsHidded = true ;
        this .Topmost = true ;
    }
    else if ( this .Top <= 0 && this .Left >= SystemParameters.VirtualScreenWidth - this .ActualWidth)
    {
        this .Left = SystemParameters.VirtualScreenWidth - this .ActualWidth;
        this .Top = HIDE_BORDER - this .ActualHeight;
        this ._Location = ELocation.RightTop;
        this ._IsHidded = true ;
        this .Topmost = true ;
    }
    else if ( this .Top <= 0)
    {
        this .Top = HIDE_BORDER - this .ActualHeight;
        this ._Location = ELocation.Top;
        this ._IsHidded = true ;
        this .Topmost = true ;
    }
    else
    {
        this ._Location = ELocation.None;
    }
}

OnMouseLeftButtonDown这个事件主要负责窗体移动,先获得鼠标坐标,判断鼠标坐标是否在窗体内(除边缘部分,因为边缘部分已经给拖放使用),如果是的话,使用DragMove()方法进行窗体移动。

1
2
3
4
5
6
7
8
9
10
11
Win32.POINT p;
if (!Win32.GetCursorPos( out p))
    return ;
if ( this .Left + RESIZE_BORDER < p.x && this .Left + this .ActualWidth - RESIZE_BORDER > p.x && this .Top + RESIZE_BORDER < p.y && this .Top + this .ActualHeight - RESIZE_BORDER > p.y)
{
    if ( this .WindowState == WindowState.Normal)
    {
        this ._Location = ELocation.None;
    }
    this .DragMove();
}

OnMouseLeave这个事件负责窗体显示,我们知道当窗体移动到屏幕边缘时,窗体可能不会立即隐藏,OnMouseMove事件阻拦,所以使用这个事件,保证当鼠标离开要隐藏的窗体时,自动隐藏窗体。

1
2
3
4
5
6
7
8
9
if ( this .WindowState == WindowState.Normal)
{
    if ( this ._IsHidded)
    {
        this .Top = HIDE_BORDER - this .ActualHeight;
        this ._IsHidded = true ;
        this .Topmost = true ;
    }
}

由于这里的鼠标坐标,是相对屏幕的坐标,所以使用了Win32 API,窗体移动使用的也是Win32 API来实现,最大化不覆盖任务栏前面的文章已经做了介绍,这里不做介绍了。

本文源码下载

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值