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來實現,最大化不覆蓋任務欄前面的文章已經做了介紹,這裏不做介紹了。

本文源碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章