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