概述

UWP Community Toolkit Extensions 中有一个为 Mouse 提供的扩展 - Mouse Cursor Extensions,本篇我们结合代码详细讲解 Mouse Cursor Extensions 的实现。

Mouse Cursor Extensions 为 Framework element 提供了一种简单的设置鼠标悬浮时样式的方法,让开发者可以更容易的通过鼠标状态体现每个 Framework element 的状态。接下来看看官方示例的截图:

Source: https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI/Extensions/Mouse

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 = ,
Cross = ,
Custom = ,
Hand = ,
Help = ,
IBeam = ,
SizeAll = ,
SizeNortheastSouthwest = ,
SizeNorthSouth = ,
SizeNorthwestSoutheast = ,
SizeWestEast = ,
UniversalNo = ,
UpArrow = ,
Wait = ,
Pin = ,
Person = 

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] = );
        }

        // 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!!!

Extensions in UWP Community Toolkit - Mouse Cursor的更多相关文章

  1. Extensions in UWP Community Toolkit - Overview

    概述 UWP Community Toolkit  中有一个 Extensions 的集合,它们可以帮助开发者实现很多基础功能,省去自己造轮子的过程,本篇我们先来看一下 Extensions 的功能都 ...

  2. Extensions in UWP Community Toolkit - FrameworkElement Extensions

    概述 UWP Community Toolkit Extensions 中有一个为FrameworkElement 提供的扩展 - FrameworkElement Extensions,本篇我们结合 ...

  3. Extensions in UWP Community Toolkit - SurfaceDialTextbox

    概述 UWP Community Toolkit Extensions 中有一个为TextBox 提供的 SurfaceDial 扩展 - SurfaceDialTextbox,本篇我们结合代码详细讲 ...

  4. Extensions in UWP Community Toolkit - ViewExtensions

    概述 UWP Community Toolkit Extensions 中有一个为 View 提供的扩展 - View Extensions,本篇我们结合代码详细讲解 View Extensions  ...

  5. Extensions in UWP Community Toolkit - Visual Extensions

    概述 UWP Community Toolkit Extensions 中有一个为可视元素提供的扩展 - VisualExtensions,本篇我们结合代码详细讲解 VisualExtensions ...

  6. Extensions in UWP Community Toolkit - WebViewExtensions

    概述 UWP Community Toolkit Extensions 中有一个为 WebView 提供的扩展 - WebViewExtensions,本篇我们结合代码详细讲解 WebView Ext ...

  7. Extensions in UWP Community Toolkit - ListViewExtensions

    概述 UWP Community Toolkit Extensions 中有一个为 ListView 提供的扩展 - ListViewExtensions,本篇我们结合代码详细讲解 ListView  ...

  8. New UWP Community Toolkit

    概述 UWP Community Toolkit 是一个 UWP App 自定义控件.应用服务和帮助方法的集合,能够很大程度的简化和指引开发者的开发工作,相信广大 UWPer 并不陌生. 下面是截取自 ...

  9. New UWP Community Toolkit - Carousel

    概述 New UWP Community Toolkit  V2.2.0 的版本发布日志中提到了 Carousel 的调整,本篇我们结合代码详细讲解  Carousel 的实现. Carousel 是 ...

随机推荐

  1. 关于一道面试题【字符串 '1 + (5 - 2) * 3',怎么算出结果为10,'eval'除外】

    最近徘徊在找工作和继续留任的纠结之中,在朋友的怂恿下去参加了一次面试,最后一道题目是: 写一个函数,输入一个字符串的运算式,返回计算之后的结果.例如这样的: '1 + (5 - 2) * 3',计算出 ...

  2. ### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to chec

    数据库连接超时,是数据库连接时的相关配置写错,例如:数据库密码,驱动等问题

  3. Idea中开启assert断言

    先打开相应的配置面板,有以下两种方式.   然后在VM栏里输入 -enableassertions 或者 -ea 就好了 然后编写程序试试 我的目录结构如下:(因为Main class那里要写类的全限 ...

  4. bat脚本:Java一键编译(Javac java)

    bat脚本:Java一键编译(Javac java) D:    是指D盘 javat是要编译的.java文件所在的文件夹 也就是D:\javat bat代码: :start COLOR 0A cls ...

  5. 简单使用git和github来管理代码----配置与使用

    在以前没听说过github之前,自己写的代码很容易丢或者遗失,等到用时才知码到用时方恨丢,现在用了github,真的是替自己生省不少的事,闲话不多说,上教程. 1 在github上注册账号 https ...

  6. 排序算法Java实现(快速排序)

    算法描述:对于一组给定的记录,通过一趟排序后,将原序列分为两部分,其中前一部分的所有记录均比后一部分的所有记录小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中的所有记录均有序为止. ...

  7. 在linux下如何使用yum查看安装了哪些软件包

    $yum list installed //列出所有已安装的软件包 yum针对软件包操作常用命令: 1.使用YUM查找软件包 命令:yum search 2.列出所有可安装的软件包 命令:yum li ...

  8. 深入解读 Js 中的面向对象编程

    前言:今天看了一篇文章觉得很不错,所以给大家分享一下,也许很多人都看过面向对象编程甚至写过这样博客,觉得面向对象编程就那样,没啥好说的,那可能是因为你对这方面知识已经了解,可以选择性跳过.那如果有更通 ...

  9. 【Linux】 linux中的进程信息相关的一些内容

    _ linux进程信息 ■ top top命令用于动态地查看系统的进程和其他一些资源的信息.开启top的时候可以加上-t <sec>来设置top更新的频率高低.进入top界面之后,可以输入 ...

  10. 国内可用的Internet时间同步服务器地址(NTP时间服务器)

    不知道什么鬼我这系统自带的Internet时间同步服务器地址居然不可用,终端ping系统自带服务器两个居然都不通???难道时间服务器也和谐么? 好在阿里云提供了7个NTP时间服务器也就是Interne ...