Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >打造一把UWP像素尺

打造一把UWP像素尺

作者头像
Edi Wang
发布于 2019-07-10 09:23:35
发布于 2019-07-10 09:23:35
1.1K00
代码可运行
举报
文章被收录于专栏:汪宇杰博客汪宇杰博客
运行总次数:0
代码可运行

在特定应用里,我们需要用标尺来标识屏幕上的像素。然而唯一内置的尺是在InkToolbar控件里的,我们没法拿出来用。今天我就教大家如何自己打造一把UWP引用里随处可用的像素尺。

样例应用

新建一个名为PixelRulerUwp的UWP应用,版本设置为Windows 10, version 1803 (10.0; Build 17134)。

// 不用1809是因为这个版本实在是人类历史上最可怕的药丸啊,微软别打我,这行注释了你们看不见……

Win2D

官方文档描述

Win2D is an easy-to-use Windows Runtime API for immediate mode 2D graphics rendering with GPU acceleration. It is available to C#, C++ and VB developers writing apps for the Windows Universal Platform (UWP). It utilizes the power of Direct2D, and integrates seamlessly with XAML and CoreWindow.

我们将使用Win2D绘制标尺。使用NuGet将Win2D安装到我们的工程里:

Install-Package Win2D.uwp

创建PixelRuler用户控件

在工程里添加一个名为“PixelRuler.xaml”的用户控件

Win2D能够在CanvasControl上绘制图形,因此我们需要添加一个名为“RulerCanvas”的CanvasControl,之后我们会在它上面绘制像素尺。

UserControl属性里加入一个新的命名空间

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
xmlns:xaml="using:Microsoft.Graphics.Canvas.UI.Xaml"

然后添加CanvasControl

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<xaml:CanvasControl x:Name="RulerCanvas"                     VerticalAlignment="Top" />

这不是最终的XAML代码,我们将继续完成它。

创建绑定属性

这把尺至少需要一个宽度和一个背景色,在PixelRuler.xaml.cs中加入它们。

实现INotifyPropertyChanged接口来进行数据绑定

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using System.ComponentModel;

然后

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public sealed partial class PixelRuler : UserControl, INotifyPropertyChanged

实现接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

然后创建RulerWidth属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static readonly DependencyProperty RulerWidthProperty = DependencyProperty.Register(
    nameof(RulerWidth),
    typeof(int),
    typeof(PixelRuler),
    new PropertyMetadata(null)
);
public int RulerWidth
{
    get => (int)GetValue(RulerWidthProperty);
    set => SetValue(RulerWidthProperty, value);
}

DependencyProperty通常用于UserControl里,这样使用者能够对你的UserControl进行属性的设定。

类似的,添加BackgroundColor属性。

加入命名空间

using Windows.UI;

加入属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static readonly DependencyProperty BackgroundColorProperty = DependencyProperty.Register(
    nameof(BackgroundColor),
    typeof(Color),
    typeof(PixelRuler),
    new PropertyMetadata(null)
);
public Color BackgroundColor
{
    get => (Color)GetValue(BackgroundColorProperty);
    set { SetValue(BackgroundColorProperty, value); OnPropertyChanged(); }
}

在构造函数里给它们设置默认值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public PixelRuler()
{
    this.InitializeComponent();
    RulerWidth = 50;
    BackgroundColor = Color.FromArgb(128, 238, 238, 238);
}

现在,修改PixelRuler.xaml,绑定这两个属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<xaml:CanvasControl x:Name="RulerCanvas" 
                    Height="{x:Bind RulerWidth, Mode=OneWay}"
                    ClearColor="{x:Bind BackgroundColor, Mode=OneWay}"
                    VerticalAlignment="Top" />

PixelRuler用户控件添加到MainPage.xaml里

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<local:PixelRuler HorizontalAlignment="Stretch"
                  VerticalAlignment="Top" />

绘制尺

要在CanvasControl上绘制图形,使用Draw事件,处理函数命名为RulerCanvas_OnDraw

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<xaml:CanvasControl x:Name="RulerCanvas" 
                    VerticalAlignment="Top" 
                    Height="{x:Bind RulerWidth, Mode=OneWay}"
                    ClearColor="{x:Bind BackgroundColor, Mode=OneWay}"
                    Draw="RulerCanvas_OnDraw" />

为了教程目的,我暂时使用硬编码来写

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void RulerCanvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
    var session = args.DrawingSession;
    session.DrawLine(0, 0, 1920, 0, Colors.Black, 1);
    session.DrawLine(0, RulerWidth, 1920, RulerWidth, Colors.Black, 1);
}

方法签名是这样的

public void DrawLine(float x0, float y0, float x1, float y1, Color color, float strokeWidth);

这里,1920是屏幕的宽度,(x0, y0)是线条起点坐标,(x1, y1)是线条终点坐标,0是画布的左上角位置

运行这个工程,你会得到一个带上下边和背景色的空尺子:

现在你了解了如何使用Win2D在CanvasControl上绘制图形并在一个应用页面里使用的过程,让我们来更深入的完成这把尺子。

绘制刻度

一把尺有小刻度和大刻度,我们允许用户自定义刻度的步长。

加入代表这两种刻度的属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static readonly DependencyProperty LargeStepsProperty = DependencyProperty.Register(
    nameof(LargeSteps),
    typeof(int),
    typeof(PixelRuler),
    new PropertyMetadata(null)
);
public int LargeSteps
{
    get => (int)GetValue(LargeStepsProperty);
    set => SetValue(LargeStepsProperty, value);
}
public static readonly DependencyProperty SmallStepsProperty = DependencyProperty.Register(
    nameof(SmallSteps),
    typeof(int),
    typeof(PixelRuler),
    new PropertyMetadata(null)
);
public int SmallSteps
{
    get => (int)GetValue(SmallStepsProperty);
    set => SetValue(SmallStepsProperty, value);
}

在构造函数里设置默认值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public PixelRuler()
{
    // …
    LargeSteps = 50;
    SmallSteps = 10;
}

为了教程目的,我依然暂时使用硬编码,现在RulerCanvas_OnDraw 的代码为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void RulerCanvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
    var session = args.DrawingSession;
    session.DrawLine(0, 0, 1920, 0, Colors.Black, 1);
    session.DrawLine(0, RulerWidth, 1920, RulerWidth, Colors.Black, 1);
    for (int x = 0; x < 1920; x += LargeSteps)
    {
        for (int x1 = x + SmallSteps; x1 < x + LargeSteps; x1 += SmallSteps)
        {
            session.DrawLine(x1, 0, x1, 10, Colors.Black, 1);
        }
        session.DrawLine(x, 0, x, 20, Colors.Black, 1);
    }
}

这里10代表小刻度的长度,20代表大刻度的长度。

运行工程,你能看见一把带有大、小刻度的尺

绘制数值文本

一把尺也需要在大刻度上标明数值,将下面代码添加到RulerCanvas_OnDraw事件处理函数里:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for (int x = 0; x < 1920; x += LargeSteps)
{
    session.DrawText(x.ToString(), x, 30, Colors.Black, new CanvasTextFormat()
    {
        FontSize = (float)FontSize,
        FontFamily = FontFamily.Source,
        HorizontalAlignment = CanvasHorizontalAlignment.Center,
        VerticalAlignment = CanvasVerticalAlignment.Center
    });
}

其中30代表尺的顶端到文本的距离,等于大刻度的长度加10个像素。

FontSizeFontFamily不需要额外创建两个属性,它们继承于UserControl本身,所以用户已经可以控制这两者的值了,例如在MainPage.xaml里:

<local:PixelRuler HorizontalAlignment="Stretch"

VerticalAlignment="Top" FontSize="12" FontFamily="Consolas" />

运行工程,你会得到一个带有刻度和数字的尺

现在你已经完成了像素尺的基本功能,我们来让它更加完善。

更完美的功能

我们的UserControl需要在不同场景下使用,因此我们要让用户能尽可能自定义每一处设置,而不是硬编码进程序里。

例如,关于屏幕宽度,我之前硬编码了1920。我们把它设置为用户屏幕分辨率的大边。获取屏幕分辨率的简单方法可以安装我的UWP助手库获得:

Install-Package Edi.UWP.Helpers

现在你可以把每一处1920都改成largePixel了:

var pixelW = Edi.UWP.Helpers.UI.GetScreenWidth();

var pixelH = Edi.UWP.Helpers.UI.GetScreenHeight();

var largePixel = pixelW > pixelH ? pixelW : pixelH;

session.DrawLine(0, 0, (int)largePixel, 0, Colors.Black, 1);

session.DrawLine(0, RulerWidth, (int)largePixel, RulerWidth, Colors.Black, 1);

我也添加了如下的属性帮助自定义这把尺

  • DrawBorder (是否绘制边框)
  • ScaleMarkPosition (刻度位置:左、右、两者都要)
  • ScaleMarkLength (刻度长度)
  • ScaleMarkColor (刻度颜色)
  • TextColor (数字颜色)
  • TextMargin (数字边距)

你可以深度自定义像素尺

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<local:PixelRuler HorizontalAlignment="Stretch"
                  VerticalAlignment="Top"
                  RulerWidth="80"
                  LargeSteps="50"
                  SmallSteps="10"
                  ScaleMarkLength="20"
                  FontSize="12"
                  ScaleMarkPosition="Both"
                  ScaleMarkColor="#CCC"
                  TextColor="#CCC"
                  FontFamily="Segoe UI"
                  TextMargin="10"
                  BackgroundColor="#333" 
                  DrawBorder="True"
                  Height="80" />

完整的案例代码在我的GitHub上:

https://github.com/EdiWang/PixelRulerUwp

你也可以在微软应用商店找到样例APP:

https://www.microsoft.com/en-us/p/pixelruleruwp-demo/9nblggh5fjhn

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-11-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 汪宇杰博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
[UWP]用Win2D实现镂空文字
后来试玩了Win2D,这次就用Win2D实现文字的镂空效果,配合PointLight做一个内敛不张扬的番茄钟。
dino.c
2019/11/27
6800
Win2D 中的游戏循环:CanvasAnimatedControl
发布于 2018-11-11 21:35 更新于 2018-11-28 08:25
walterlv
2020/02/10
9770
win10 uwp 使用 Border 布局
在 UWP 写一个界面需要将元素排列,在排列元素的时候有特殊的元素叫容器。容器的意思是元素里面包含元素,在 UWP 用到的容器有很多,也可以自己写一个。简单的容器是 Border 边框控件,如控件说的,这个容器就是用来做元素的边框。提供元素边框和背景,只能在这个容器里面放一个元素
林德熙
2019/04/22
1.1K0
win10 uwp 使用 Border 布局
win10 uwp win2d 离屏渲染
离屏渲染(Offscreen drawing)是一个不错的科技,在系统有空的时候,提前先画出部分界面。这样在需要直接渲染的时候就可以直接拿出来而不需要等待进行渲染的时候才画出来。
林德熙
2018/09/19
6850
win10 uwp win2d 离屏渲染
win2d CanvasCommandList 使用方法 直接显示相对移动复用命令与 CanvasRenderTarget 的区别特效
在 win2d 可以通过 CanvasCommandList 定义很多命令,这些命令不是直接渲染到 Canvas 上,而是作为一个缓存。可以将 CanvasCommandList 作为输入,输入到其他的特效或参与其他的渲染。 特别在用 Win2d 写一个渲染框架的时候,通过 CanvasCommandList 可以实现内部元素容器的偏移和统一的效果
林德熙
2019/03/13
5110
win2d CanvasCommandList 使用方法
            直接显示相对移动复用命令与 CanvasRenderTarget 的区别特效
win10 uwp 毛玻璃 Compositor 创建毛玻璃win2D最简单方法
毛玻璃在UWP很简单,不会和WPF那样伤性能。 本文告诉大家,如何在 UWP 使用 win2d 做毛玻璃。
林德熙
2018/09/18
1.1K0
win10 uwp 毛玻璃
            Compositor 创建毛玻璃win2D最简单方法
dotnet WinUI3 Win2D 翻转图片
本文将告诉大家如何在 WinUI3 里面使用 Win2D 进行图片的翻转,本文的方法也适用于 UWP 框架
林德熙
2024/07/08
1490
win10 uwp 商业游戏 界面添加图标感谢
在显示启动的时候,是需要加载游戏需要使用的资源,如果觉得这时需要控制进度条,就需要使用注入的方法,给他知道现在的进度,不过我现在不去做这里,于是就很简单的代码做出来启动页面。
林德熙
2018/09/18
7940
win10 uwp 商业游戏 
            界面添加图标感谢
win2d 渐变颜色
在 UWP 的 Win2d 使用渐变颜色需要 CanvasLinearGradientBrush 做颜色,本文告诉大家如何在 win2d 使用 CanvasLinearGradientBrush 做渐变。
林德熙
2018/09/19
1.5K0
win2d 渐变颜色
win10 uwp 进度条 WaveProgressControl
昨天看到了有个大神做出好看的进度条样式,于是我就去抄袭他的代码,但是发现看不懂,于是本文主要翻译就是大神说这个控件如何做。
林德熙
2018/09/18
7900
win10 uwp 进度条 WaveProgressControl
[UWP 自定义控件]了解模板化控件(2):模仿ContentControl
ContentControl是最简单的TemplatedControl,而且它在UWP出场频率很高。ContentControl和Panel是VisualTree的基础,可以说几乎所有VisualTree上的UI元素的父节点中总有一个ContentControl或Panel。
dino.c
2019/01/18
6900
win10 uwp 进度条 Marquez
本文将告诉大家,如何做一个带文字的进度条,这个进度条可以用在游戏,现在我做的挂机游戏就使用了他。
林德熙
2018/09/18
4450
win10 uwp 进度条 Marquez
WPF 应用完全模拟 UWP 的标题栏按钮
发布于 2018-08-04 09:35 更新于 2018-08-05 02:21
walterlv
2018/09/18
2.2K0
WPF 应用完全模拟 UWP 的标题栏按钮
使用 Win2D 实现融合效果
在 CSS 中有一种实现融合效果的技巧,使用模糊滤镜(blur)叠加对比度滤镜(contrast)使两个接近的元素看上去“粘”在一起,如下图所示:
dino.c
2022/10/05
5160
使用 Win2D 实现融合效果
win10 uwp win2d 特效 AlphaMaskEffectArithmeticCompositeEffect
在开始之前先创建一个项目,这里创建 SeexerefaspeaRoulejur 最低版本 17134 选择比较新的版本可以解决之前一些版本存在的坑
林德熙
2019/03/13
5350
win10 uwp win2d 特效
            AlphaMaskEffectArithmeticCompositeEffect
win10 uwp 自定义控件 SplitViewItem SplitView 从右划出
本文主要是因为汉堡菜单里面列出的菜单很多重复的图标和文字,我把它作为控件,因为是随便写,可能存在错误,如果发现了,请和我说或关掉浏览器,请不要发不良言论。
林德熙
2018/09/18
5390
win10 uwp 自定义控件 SplitViewItem
            SplitView 从右划出
win10 uwp win2d 入门 看这一篇就够了
本文主要翻译,可能带有一定的主观性和局限性,说的东西可能不对或者不符合每个人的预期。如果觉得我有讲的不对的,就多多包含,或者直接关掉这篇文章,但是请勿生气或者发怒吐槽,可以在我博客评论 http://blog.csdn.net/lindexi_gd
林德熙
2018/09/19
1.6K0
win10 uwp win2d 入门 看这一篇就够了
[UWP]用Shape做动画
相对于WPF/Silverlight,UWP的动画系统可以说有大幅提高,不过本文无意深入讨论这些动画API,本文将介绍使用Shape做一些进度、等待方面的动画,除此之外也会介绍一些相关技巧。
dino.c
2019/01/18
2K0
[UWP]用Shape做动画
WPF实现列表分页控件的示例代码分享
[TemplatePart(Name = CountPerPageTextBoxTemplateName, Type = typeof(TextBox))]
用户7718188
2022/11/06
1.3K0
[WPF自定义控件]从ContentControl开始入门自定义控件
我去年写过一个在UWP自定义控件的系列博客,大部分的经验都可以用在WPF中(只有一点小区别)。这篇文章的目的是快速入门自定义控件的开发,所以尽量精简了篇幅,更深入的概念在以后介绍各控件的文章中实际运用到才介绍。
dino.c
2019/05/17
4.1K0
推荐阅读
相关推荐
[UWP]用Win2D实现镂空文字
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文