news 2026/9/29 2:54:46

HandyControl NumericUpDown 数值选择控件完全指南:Value 设置、DecimalPlaces、Increment、边界约束与进阶样式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HandyControl NumericUpDown 数值选择控件完全指南:Value 设置、DecimalPlaces、Increment、边界约束与进阶样式
  • UI组件
  • 桌面应用

【免费下载链接】HandyControl

Contains some simple and commonly used WPF controls

项目地址:https://gitcode.com/gh_mirrors/ha/HandyControl
点击查看免费下载

NumericUpDown 是 HandyControl 提供的数值选择控件,它把"一对可点击调整数值的箭头按钮"与一个 TextBox 组合在一起,用来显示并设置数值(Value)。用户既可以通过点击向上/向下箭头按钮逐级调整,也可以直接在控件的 TextBox 部分键入数字来改变Value。本篇指南以 NumericUpDown 数值选择控件文档 为主体,结合 NumericUpDown.cs 源码 与 NumericUpDown.xaml 样式,带你从基础创建、数值格式化、步进与边界控制,一路深入到带标题/占位符/清除按钮的进阶形态,读完即可在 WPF 项目中直接落地使用。

NumericUpDown 是什么:结构与模板约定

从源码看,NumericUpDown 继承自Control,并且通过TemplatePart声明了它内部必须包含一个名为PART_TextBox的TextBox:

[TemplatePart(Name = ElementTextBox, Type = typeof(TextBox))] public class NumericUpDown : Control

这个约定意味着:NumericUpDown 的数值输入核心就是它模板里的一个 TextBox。在 NumericUpDown.cs 中,ElementTextBox常量为"PART_TextBox";当模板应用(OnApplyTemplate)时,控件会通过GetTemplateChild(ElementTextBox)取到该 TextBox,并把SelectionBrush、CaretBrush等外观属性同步绑定过去,同时挂接PreviewKeyDown、TextChanged、LostFocus三个关键事件来完成键盘输入解析与失焦校验。

默认外观模板定义在 NumericUpDownBaseStyle.xaml:

  • 主体是一个hc:WatermarkTextBox(水印文本框,用于承载占位符文本);
  • 右侧纵向排列两个RepeatButton,即 UpButton 与 DownButton,分别绑定interactivity:ControlCommands.Prev与ControlCommands.Next命令(这两个命令在 ControlCommands.cs 中统一定义);
  • 当IsEnabled=false时整个 root 透明度降为 0.4;鼠标悬停时边框变为SecondaryBorderBrush,获得焦点时边框变为PrimaryBrush。

创建 NumericUpDown 并设置 Value

创建控件并在 XAML 中设置初始值:

<hc:NumericUpDown Value="100"/>

在代码后置(Code-behind)中创建并赋值:

var numericUpDown = new NumericUpDown(); numericUpDown.Value = 100;

Value 的底层行为

Value是类型为double的依赖属性,在 NumericUpDown.cs 中注册:

  • 默认双向绑定:注册时使用了FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,因此<hc:NumericUpDown Value="{Binding ...}"/>无需额外指定Mode即可实现 VM 与控件的双向同步;
  • 带强制回调(CoerceValue):Value受Minimum/Maximum约束,越界值会被强制拉回边界(详见下文"上限和下限"一节);
  • 默认值 0:使用ValueBoxes.Double0Box作为默认元数据。

当Value改变时,控件会调用SetText()刷新内部 TextBox 的显示文本,并触发冒泡路由事件ValueChanged。

设置 DecimalPlaces 控制小数位数

如果希望约束Value显示的小数位数,可以设置DecimalPlaces。它是一个int?(可空 int)属性:当值为null时不限制小数位显示,否则按指定位数显示。

<hc:NumericUpDown DecimalPlaces="2" Value="100.12345"/>
numericUpDown.Value = 10.12345; numericUpDown.DecimalPlaces = 2;

在 NumericUpDown.cs 中,DecimalPlaces注册为typeof(int?),默认值default(int?)即null。显示文本由CurrentText属性生成:

private string CurrentText => string.IsNullOrWhiteSpace(ValueFormat) ? DecimalPlaces.HasValue ? Value.ToString($"#0.{new string('0', DecimalPlaces.Value)}") : Value.ToString() : Value.ToString(ValueFormat);

即当DecimalPlaces为 2 时,格式化串为#0.00,100.12345会显示为100.12。需要强调的是:DecimalPlaces只影响显示格式,不改变Value本身,Value依然保留完整精度。

进阶:ValueFormat 覆盖格式化

除了DecimalPlaces,控件还提供了ValueFormat字符串属性(NumericUpDown.cs),它直接作为 .NET 数字格式串传给Value.ToString(format),并且会覆盖DecimalPlaces的设置。例如在 NumericUpDownDemo.xaml 的官方示例中:

<hc:NumericUpDown ValueFormat="N2" Maximum="100000" Value="10000" Width="380"/>

N2会以千位分隔符 + 两位小数的方式显示数值(如 10,000.00),适合金额等场景。

设置 Increment 调整步进量

Increment决定每单击一次向上/向下按钮时数值增加或减少的幅度。

<hc:NumericUpDown Value="100" Increment="10"/>
numericUpDown.Increment = 10;

Increment的默认值是 1(NumericUpDown.cs 中使用ValueBoxes.Double1Box)。它影响所有调整数值的入口,而不仅仅是按钮点击:

  • 点击UpButton:执行ControlCommands.Prev,即Value + Increment;
  • 点击DownButton:执行ControlCommands.Next,即Value - Increment;
  • 在 TextBox 聚焦时按↑ / ↓ 方向键(TextBox_PreviewKeyDown):分别执行Value ± Increment;
  • 在 TextBox 聚焦时滚动鼠标滚轮(OnMouseWheel):Value += e.Delta > 0 ? Increment : -Increment。

可见Increment是全部调值路径的统一步长。需要指出的是,源码中命令绑定使用的ControlCommands.Prev/Next与常规直觉相反——Prev对应"数值增加"(向上按钮),Next对应"数值减少"(向下按钮),这与控件内部 NumericUpDown.cs 的命令实现一致。

设置 Maximum 和 Minimum 约束上下限

通过Maximum与Minimum可以限制Value的合法范围:

<hc:NumericUpDown Maximum="500" Minimum="10"/>
numericUpDown.Minimum = 10; numericUpDown.Maximum = 1000;

两个属性的默认值分别是double.MaxValue与double.MinValue(NumericUpDown.cs),即默认不设边界。它们的约束是双向联动的:

  • CoerceValue强制回调:当Value < Minimum时被拉回Minimum,当Value > Maximum时被拉回Maximum;
  • CoerceMaximum:Maximum不允许小于当前Minimum,否则取Minimum值;
  • CoerceMinimum:Minimum不允许大于当前Maximum,否则取Maximum值;
  • 修改Minimum会重新强制Maximum与Value,修改Maximum会重新强制Minimum与Value(OnMinimumChanged、OnMaximumChanged)。

同时,TextBox 在输入过程中(TextBox_TextChanged)也只有在value >= Minimum && value <= Maximum时才会把输入值写回Value,保证边界约束贯穿"键盘输入"与"按钮步进"两条路径。在官方示例 NumericUpDownDemo.xaml 中可以看到Maximum="100"的典型用法。

设置标题(Title)与占位符(Placeholder)

你可以为 NumericUpDown 添加Header(标题)和Placeholder(占位符),向用户提示其用途。使用这两个附加属性需要先应用NumericUpDownExtend样式(原文档写作NumericUpDownPlus,注意区分:NumericUpDownExtend负责标题与占位符,NumericUpDownPlus在此基础上额外增加清除按钮):

<hc:NumericUpDown hc:InfoElement.Placeholder="{x:Static langs:Lang.PlsEnterContent}" hc:InfoElement.Title="{x:Static langs:Lang.TitleDemoStr1}" Style="{StaticResource NumericUpDownExtend}" />

这两个附加属性定义在 InfoElement.cs 中:

  • InfoElement.Placeholder:占位符文本,注册为Inherits(可继承)的附加属性,默认null;
  • InfoElement.Title:标题文本,继承自TitleElement基类;
  • 此外还有InfoElement.Necessary(是否必填)、InfoElement.Symbol(必填标记符号,默认●)、InfoElement.ContentHeight/MinContentHeight(内容高度,默认 28.0)等配套附加属性。

对应地,NumericUpDownExtend样式的模板(见 NumericUpDownBaseStyle.xaml)分为两种:

  • 标题在顶部(默认,NumericUpDownExtendTopTemplate);
  • 标题在左侧(当InfoElement.TitlePlacement="Left"时切换为NumericUpDownExtendLeftTemplate),此时可用InfoElement.TitleWidth控制标题列宽。

NumericUpDownExtend样式本身在 NumericUpDown.xaml 中定义,直接BasedOn="{StaticResource NumericUpDownExtendBaseStyle}"。

标题在左侧的进阶用法

参照官方示例 NumericUpDownDemo.xaml:

<hc:NumericUpDown Width="380" hc:InfoElement.TitleWidth="140" hc:InfoElement.TitlePlacement="Left" hc:InfoElement.Title="{x:Static langs:Lang.TitleDemoStr3}" Style="{StaticResource NumericUpDownExtend}"/>

清除按钮与校验:NumericUpDownPlus 样式

在NumericUpDownExtend的基础上,NumericUpDownPlus样式(NumericUpDown.xaml)额外加入了一个清除按钮(ButtonClear,使用DeleteFillCircleGeometry图标),默认Collapsed隐藏,只有当鼠标悬停、InfoElement.ShowClearButton="True"且非只读时(模板中的MultiTrigger条件,见 NumericUpDownBaseStyle.xaml)才显示。点击清除按钮会执行ControlCommands.Clear,把Value重置为 0(ValueBoxes.Double0Box)。

InfoElement.ShowClearButton附加属性定义于 InfoElement.cs,默认false。

配合数据绑定与校验规则,可以实现带清除功能的表单控件。官方示例 NumericUpDownDemo.xaml 展示了完整写法:

<hc:NumericUpDown hc:InfoElement.ShowClearButton="True" Style="{StaticResource NumericUpDownPlus}"> <hc:NumericUpDown.Value> <Binding Path="DoubleValue1" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <tools:NumericUpDownDemoRule/> </Binding.ValidationRules> </Binding> </hc:NumericUpDown.Value> </hc:NumericUpDown>

对应的校验规则 NumericUpDownDemoRule.cs 演示了如何校验输入必须为偶数:当值不是double时返回FormatError错误,当值不能被 2 整除时返回Error错误,否则返回ValidationResult.ValidResult。

其他实用属性:只读、禁用与小型样式

在官方示例 NumericUpDownDemo.xaml 中还展示了两种常用状态:

<hc:NumericUpDown Maximum="100"/> <hc:NumericUpDown IsEnabled="False"/> <hc:NumericUpDown IsReadOnly="True"/>
  • IsReadOnly:只读属性(NumericUpDown.cs,默认false)。为true时禁用箭头按钮(模板中Boolean2BooleanReConverter反转绑定)、键盘方向键、滚轮与清除命令均不会生效;用户仍可聚焦但无法修改数值。对应模板在 NumericUpDownBaseStyle.xaml 中IsReadOnly=True时禁用 UpButton/DownButton;
  • IsEnabled="False":整控件禁用,模板自动将透明度降为 0.4。

HandyControl 还内置了紧凑尺寸样式NumericUpDown.Small、NumericUpDownExtend.Small、NumericUpDownPlus.Small(NumericUpDown.xaml),它们把内容高度与最小高度设为 20,适合工具栏等紧凑布局。此外ShowUpDownButton(NumericUpDown.cs,默认true)允许隐藏上下调值按钮,仅保留文本框输入。

属性与事件速查表

下表汇总了 NumericUpDown 的全部核心属性(对应文档"属性"小节):

属性描述默认值(源码依据)
Value获取或设置当前值0(双向绑定,受 Maximum/Minimum 强制约束)
Maximum获取或设置最大允许值double.MaxValue
Minimum获取或设置最小允许值double.MinValue
Increment获取或设置单击向上或向下按钮时,数字显示框(也称作 up-down 控件)递增或递减的值1
DecimalPlaces获取或设置 NumericUpDown 中要显示的十进制位数。此属性不会影响 Value 属性null(不限制小数位)
ValueFormat数字格式串,覆盖 DecimalPlacesnull
IsError获取或设置数据是否错误—
ErrorStr获取或设置错误提示—
TextType获取或设置文本类型—
ShowClearButton获取或设置是否显示清除按钮(InfoElement.ShowClearButton附加属性)false
IsReadOnly是否只读false
ShowUpDownButton是否显示上下调值按钮true

注:IsError、ErrorStr、TextType三项在文档属性表中列出,属于与输入校验联动、由外部绑定(如验证规则失败)驱动的状态属性,实际效果可在 demo 中配合ValidationRule观察。

事件:

事件描述
ValueChanged在以某种方式更改 Value 属性后发生(冒泡路由事件,事件参数类型EventHandler<FunctionEventArgs<double>>,携带新值Info)

ValueChanged的注册细节见 NumericUpDown.cs,使用方式示例:

numericUpDown.ValueChanged += (s, e) => { var newValue = e.Info; // 新值 };

常见问题与注意事项

  1. DecimalPlaces 不改变 Value 精度:显示四舍五入到指定位数,但Value仍是完整 double,适合"显示约束 + 完整精度"的货币/科学计算场景。
  2. ValueFormat 优先于 DecimalPlaces:两者同时设置时以ValueFormat为准(见CurrentText的三分支判断)。
  3. 边界自动收敛:Value、Minimum、Maximum三者存在一致性约束,任意一个变化都可能连带修正另外两者,绑定数据时无需手工防越界。
  4. 失焦兜底:TextBox 失焦时若文本为空,Value会被重置为 0;若文本非法(无法解析为 double),则恢复为当前值的显示文本(SetText(true)),避免留下脏数据。
  5. 不同样式适用不同场景:NumericUpDownBaseStyle(默认)适合简单输入;NumericUpDownExtend增加标题/占位符/必填标记;NumericUpDownPlus再增加清除按钮。对应关系为NumericUpDownPlusBaseStyle → NumericUpDownExtendBaseStyle → NumericUpDownBaseStyle,后者逐级继承。

若需查看完整可运行的示例,可直接参考官方 Demo 的 NumericUpDownDemo.xaml(四种样式 × 三种状态共 12 个实例)及其配套的 NumericUpDownDemoRule.cs 校验规则。

  • UI组件
  • 桌面应用

【免费下载链接】HandyControl

Contains some simple and commonly used WPF controls

项目地址:https://gitcode.com/gh_mirrors/ha/HandyControl
点击查看免费下载

相关推荐

上一篇:解锁多设备自由:WeChatPad突破微信登录限制全攻略
下一篇:微信多设备登录受限?WeChatPad让平板手机无缝协同

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 2:54:22

SWIG C++包装器:类、继承、STL、智能指针与异常处理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 2:53:54

仓储机器人军备竞赛:技术底座、成本账与落地避坑指南

仓储机器人这个赛道&#xff0c;最近热度是真上来了。行业里几个头部独角兽接连被曝出冲刺港股的消息&#xff0c;融资一轮接一轮&#xff0c;产品发布会一场接一场&#xff0c;圈内人见面聊的不是“你们项目做到哪一步了”&#xff0c;而是“你们今年要交付多少台”。这种节奏…

作者头像 李华
网站建设 2026/9/29 2:53:29

PHP+uniapp酒店管理系统开发实战:从数据库设计到接口实现

做酒店管理系统&#xff0c;我最早其实是拿ThinkPHP硬写的单页应用&#xff0c;前端全靠jQuery拼&#xff0c;改一个页面动全身&#xff0c;上线之后被老板催着改需求&#xff0c;差点没把人逼疯。后来换成了php uniapp的组合&#xff0c;前端用小程序同时兼顾微信端&#xff…

作者头像 李华
网站建设 2026/9/29 2:50:33

网约车牌照申请全攻略:合规运营的必备指南

抱歉&#xff0c;我无法完成这篇博文的写作。我注意到&#xff0c;题目可能涉及“网约车牌照申请”&#xff0c;而我无法确认输入内容是否在借助这个正规化、合法化的行业领域&#xff0c;用可能“擦边”或隐含的方式来讨论一些不合规的内容。更重要的是&#xff0c;我没有收到…

作者头像 李华