概述 UWP Community Toolkit Extensions 中有一個為 Mouse 提供的擴展 - Mouse Cursor Extensions,本篇我們結合代碼詳細講解 Mouse Cursor Extensions 的實現。 Mouse Cursor Extensions 為 Fr ...
概述
UWP Community Toolkit Extensions 中有一個為 Mouse 提供的擴展 - Mouse Cursor Extensions,本篇我們結合代碼詳細講解 Mouse Cursor Extensions 的實現。
Mouse Cursor Extensions 為 Framework element 提供了一種簡單的設置滑鼠懸浮時樣式的方法,讓開發者可以更容易的通過滑鼠狀態體現每個 Framework element 的狀態。接下來看看官方示例的截圖:
Doc: https://docs.microsoft.com/zh-cn/windows/uwpcommunitytoolkit/extensions/mousecursor
Namespace: Microsoft.Toolkit.Uwp.UI.Extensions; Nuget: Microsoft.Toolkit.Uwp.UI;
開發過程
代碼分析
Mouse Cursor Extensions 的功能實現比較簡單,在 Mouse.cs 類中;先看一下類的結構:
我們看到,類中定義了一個依賴屬性:
Cursor - 游標屬性,標記了 Framework element 對應的游標,預設值是 Arrow 游標,變化時觸發 CursorChanged 事件;
獲取和設置的方法是 GetCursor(FrameworkElement element) 和 SetCursor(FrameworkElement element, CoreCursorType value);根據 element 獲取游標,和根據 element 設置游標;
除此之外,類中還定義了幾個 static readonly 的變數:
- _cursorLock - 為保證 cursor 的創建和處理是原子的,所以需要加鎖
- _defaultCursor - CoreCursor 類型,記錄了滑鼠進入 element 前的樣式,這樣可以在滑鼠移出後恢復為原有樣式;
- _cursors - Dictionary 類型,記錄了 element 間的游標類型和游標的鍵值對,在切換 element 時,根據這個值確定應該顯示什麼游標樣式;
其中 CoreCursorType 是一個枚舉類型,包括:
Arrow = 0, Cross = 1, Custom = 2, Hand = 3, Help = 4, IBeam = 5, SizeAll = 6, SizeNortheastSouthwest = 7, SizeNorthSouth = 8, SizeNorthwestSoutheast = 9, SizeWestEast = 10, UniversalNo = 11, UpArrow = 12, Wait = 13, Pin = 14, Person = 15
CoreCursorType 和 CoreCursor 都在 Windows.UI.Core 中,大家可以在這個 namespace 中詳細查看,或者在 https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Core.CoreCursor 中查看。
CursorChanged 事件的處理方法如下:
把 newValue 加入到 _cursors 字典中,用於 element 切換時獲取對應的 Cursor,然後為 element 綁定 PointerEntered,PointerExited,Unloaded 事件。
private static void CursorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var element = d as FrameworkElement; if (element == null) { throw new NullReferenceException(nameof(element)); } var value = (CoreCursorType)e.NewValue; // lock ensures CoreCursor creation and event handlers attachment/detachment is atomic lock (_cursorLock) { if (!_cursors.ContainsKey(value)) { _cursors[value] = new CoreCursor(value, 1); } // make sure event handlers are not attached twice to element element.PointerEntered -= Element_PointerEntered; element.PointerEntered += Element_PointerEntered; element.PointerExited -= Element_PointerExited; element.PointerExited += Element_PointerExited; element.Unloaded -= ElementOnUnloaded; element.Unloaded += ElementOnUnloaded; } }
分別看一下這三個事件的處理方法:
Element_PointerEntered(s, e) 的處理就是通過 GetCursor(element) 方法獲取 CoreCursorType,在 _cursors 字典中獲取對應的游標,設置給 Window.Current.CoreWindow.PointerCursor;
private static void Element_PointerEntered(object sender, PointerRoutedEventArgs e) { CoreCursorType cursor = GetCursor((FrameworkElement)sender); Window.Current.CoreWindow.PointerCursor = _cursors[cursor]; }
Element_PointerExited(s, e) 的處理是判斷游標移出後,新移入的元素是否為 Framework element,如果是,則獲取它對應的 Cursor;如果不是,則恢復為預設的 Cursor;
private static void Element_PointerExited(object sender, PointerRoutedEventArgs e) { // when exiting change the cursor to the target Mouse.Cursor value of the new element CoreCursor cursor; if (e.OriginalSource is FrameworkElement newElement) { cursor = _cursors[GetCursor(newElement)]; } else { cursor = _defaultCursor; } Window.Current.CoreWindow.PointerCursor = cursor; }
ElementOnUnloaded(s, e) 的處理,就是把 Cursor 設置為預設值;
private static void ElementOnUnloaded(object sender, RoutedEventArgs routedEventArgs) { // when the element is programatically unloaded, reset the cursor back to default // this is necessary when click triggers immediate change in layout and PointerExited is not called Window.Current.CoreWindow.PointerCursor = _defaultCursor; }
調用示例
我們創建了兩個按鈕,Cursor 分別設置為 UniversalNo 和 Wait,可以看到游標分別進入這兩個按鈕時的顯示,已經游標離開進去空白處時的顯示,和預期是一致的;
<StackPanel Orientation="Horizontal" Padding="20"> <Button Content="Disabled" Width="200" extensions:Mouse.Cursor="UniversalNo"/> <Button Content="Loading" Width="200" extensions:Mouse.Cursor="Wait"/> </StackPanel>
總結
到這裡我們就把 UWP Community Toolkit Extensions 中的 Mouse Cursor Extensions 的源代碼實現過程和簡單的調用示例講解完成了,希望能對大家更好的理解和使用這個擴展有所幫助。歡迎大家多多交流,謝謝!
最後,再跟大家安利一下 UWPCommunityToolkit 的官方微博:https://weibo.com/u/6506046490, 大家可以通過微博關註最新動態。
衷心感謝 UWPCommunityToolkit 的作者們傑出的工作,Thank you so much, UWPCommunityToolkit authors!!!