wpf实现类似word文档的标尺功能

2023-12-23 12:48

本文主要是介绍wpf实现类似word文档的标尺功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

需求:实现类似word文档的标尺功能。

技术背景:模板,依赖属性

技术细节:

1、操作模板控件

  在做WPF开发的时候,我们通常因为满足不同的需求会开发一些自定义控件来满足需要,我们会自定义模板来定义控件的外观,添加命令和路由事件来给控件添加行为,那如何在模板中查找元素并关联事件处理程序或添加数据绑定表达式呢,WPF有一个专用的OnApplyTemplate()方法,在该方法中,可以使用GetTemplateChild或FindName来查找所需的元素

2、添加部件名称

  为了查找做需要的元素,WPF控件通过名称定为他们需要的元素,所以,元素的名称变成了自定义控件公有接口的一部分,并且需要恰当的描述性名称。为此。WPF给出了约定:这些名称以PART_开头,后跟元素名称。元素名称的首字母要大写,就像一个属性名称:比如PART_Slider

3、显示自定义控件

通过OnRender来显示自定义控件时,必须在相应的依赖属性加入AffectsRender枚举值,通过DependencyProperty的AddOwner或者OverrideMetadata来改写依赖属性的元数据。

	public static readonly DependencyProperty ZoomProperty =DependencyProperty.Register("Zoom", typeof(double),typeof(Ruler),new FrameworkPropertyMetadata((double) 1.0,FrameworkPropertyMetadataOptions.AffectsRender));

4、wpf的分辨率。wpf 规定其坐标单位是1/96 inch,即1个设备无关单位(DIU),对于屏幕为1600*1200的分辨率,假如屏幕的物理高度,宽度为17.0*12.75,那么水平的分辨率1600/17.0=94DPI,垂直的分辨率1200/12.75 = 94DPI,如果我们设置系统分辨率等于物理分辨率,即设置系统分辨率为94DPI,就可以实现“分辨率无关”。

 

实现:

定义Ruler类,继承FrameworkElement

定义依赖属性:长度double, 是否自动缩放(bool),缩放因子(double),鼠标当前位置的刻度线(double),起始刻度(double),刻度的位置,是在上面还是下面(Enum),单位,厘米还是英寸(Enum)

在OnRender中,

根据当前选择的单位,将标尺的长度与宽度从cm转化为DPI,

然后使用DrawingContext绘制矩形,显示出整个标尺

然后使用DrawLine绘制鼠标当前位置,初始时为负,不显示

然后使用DrawLine依次绘制刻度线,中线,主刻度线

最后使用DrawText绘制数值

      protected override void OnRender(DrawingContext drawingContext){base.OnRender(drawingContext);double xDest = (Unit == Unit.Cm ? DipHelper.CmToDip(Length) : DipHelper.InchToDip(Length)) * this.Zoom;drawingContext.DrawRectangle(null, BorderPen, new Rect(new Point(0.0, 0.0), new Point(xDest, Height)));double chip = Unit == Unit.Cm ? DipHelper.CmToDip(Chip) : DipHelper.InchToDip(Chip);drawingContext.DrawLine(RedPen, new Point(chip, 0), new Point(chip, Height));for (double dUnit = 0; dUnit <= Length; dUnit++){double d;if (Unit == Unit.Cm){d = DipHelper.CmToDip(dUnit) * this.Zoom;if (dUnit < Length){#region 绘制刻度线for (int i = 1; i <= 9; i++){if (i != 5)//不绘制中线{double dMm = DipHelper.CmToDip(dUnit + 0.1 * i) * this.Zoom;if (Marks == MarksLocation.Up)drawingContext.DrawLine(ThinPen, new Point(dMm, 0), new Point(dMm, SegmentHeight / 3.0));elsedrawingContext.DrawLine(ThinPen, new Point(dMm, Height), new Point(dMm, Height - SegmentHeight / 3.0));}} #endregion#region 绘制中线double dMiddle = DipHelper.CmToDip(dUnit + 0.5) * this.Zoom;if (Marks == MarksLocation.Up)drawingContext.DrawLine(p, new Point(dMiddle, 0), new Point(dMiddle, SegmentHeight * 2.0 / 3.0));elsedrawingContext.DrawLine(p, new Point(dMiddle, Height), new Point(dMiddle, Height - SegmentHeight * 2.0 / 3.0)); #endregion}}else{d = DipHelper.InchToDip(dUnit) * this.Zoom;if (dUnit < Length){if (Marks == MarksLocation.Up){double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;drawingContext.DrawLine(ThinPen, new Point(dQuarter, 0),new Point(dQuarter, SegmentHeight / 3.0));double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;drawingContext.DrawLine(p, new Point(dMiddle, 0),new Point(dMiddle, SegmentHeight * 2D / 3D));double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;drawingContext.DrawLine(ThinPen, new Point(d3Quarter, 0),new Point(d3Quarter, SegmentHeight / 3.0));}else{double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;drawingContext.DrawLine(ThinPen, new Point(dQuarter, Height),new Point(dQuarter, Height - SegmentHeight / 3.0));double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;drawingContext.DrawLine(p, new Point(dMiddle, Height),new Point(dMiddle, Height - SegmentHeight * 2D / 3D));double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;drawingContext.DrawLine(ThinPen, new Point(d3Quarter, Height),new Point(d3Quarter, Height - SegmentHeight / 3.0));}}}#region 绘制主刻度线if (Marks == MarksLocation.Up)drawingContext.DrawLine(p, new Point(d, 0), new Point(d, SegmentHeight));elsedrawingContext.DrawLine(p, new Point(d, Height), new Point(d, Height - SegmentHeight));#endregion#region 绘制数值if ((dUnit != 0.0) && (dUnit < Length)){FormattedText ft = new FormattedText((dUnit + CountShift).ToString(CultureInfo.CurrentCulture),CultureInfo.CurrentCulture,FlowDirection.LeftToRight,new Typeface("Arial"),DipHelper.PtToDip(6),Brushes.DimGray);ft.SetFontWeight(FontWeights.Regular);ft.TextAlignment = TextAlignment.Center;if (Marks == MarksLocation.Up)drawingContext.DrawText(ft, new Point(d, Height - ft.Height));elsedrawingContext.DrawText(ft, new Point(d, Height - SegmentHeight - ft.Height));} #endregion}}

效果图

源码:

https://download.csdn.net/download/sinat_31608641/11850893

 

 

 

 

 

 

 

 

 

这篇关于wpf实现类似word文档的标尺功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/528097

相关文章

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、