UI组件桌面应用【免费下载链接】HandyControlContains some simple and commonly used WPF controls项目地址https://gitcode.com/gh_mirrors/ha/HandyControl点击查看免费下载PinBox 是 HandyControl 提供的一种密码框的另一种形式见 pinBox 官方文档它不再是一个整体输入框而是将密码拆分成若干个独立的单字符单元每个单元一个格子适合 PIN 码、验证码、支付密码等逐位输入的场景。读完本文你将掌握 PinBox 的全部属性、Completed 事件用法并结合源码理解其安全模式下的密码存储机制与键盘交互实现。控件本质由 N 个单字符 PasswordBox 组成的组合控件PinBox 在源码层面继承自System.Windows.Controls.Control并通过[TemplatePart]约定模板中的命名部件PinBox.cs[TemplatePart(Name ElementPanel, Type typeof(Panel))] public class PinBox : Control其中ElementPanel对应名为PART_Panel的 Panel。在默认样式中这个 Panel 是一个UniformGrid列数通过{TemplateBinding Length}动态绑定PinBoxBaseStyle.xamlControlTemplate TargetTypehc:PinBox UniformGrid NamePART_Panel Columns{TemplateBinding Length} Rows1/ /ControlTemplate当模板应用OnApplyTemplate或Length变化时控件会调用UpdateItems()按长度向 Panel 中填充对应数量的PasswordBoxPinBox.cs。每个内部 PasswordBox 的关键特征MaxLength 1强制每次只能输入一个字符PasswordChar PasswordChar继承 PinBox 的掩码字符水平、垂直内容均居中且Padding为默认值SelectionBrush、SelectionTextBrush、SelectionOpacity、CaretBrush四个外观属性通过 Binding 从 PinBox 同步到每个单元其中SelectionTextBrush仅在 NET40~NET472 之外的目标框架下编译。因此PinBox 的实际交互单元就是 WPF 原生的PasswordBox这保证了每位密码都具备标准的掩码与焦点行为。属性详解| 属性 | 描述 | 默认值 | 备注 | | - | - | - | - | | Password | 密码 | | 出于安全考虑无法绑定 | | PasswordChar | 掩码字符 | ● | | | Length | 密码长度 | 4 | 最小值为 4 | | ItemMargin | 单元框间隔 | 4,0默认样式 | 类型为 Thickness | | ItemWidth | 单元框宽度 | DefaultControlHeight默认样式 | | | ItemHeight | 单元框高度 | DefaultControlHeight默认样式 | |Password只读密码不可绑定Password是 PinBox 的核心数据属性。它的 getter 实时把所有内部 PasswordBox 的Password拼成字符串返回PinBox.cspublic string Password { get _panel null ? string.Empty : string.Join(string.Empty, _panel.Children.OfTypeSystem.Windows.Controls.PasswordBox().Select(item item.Password)); ... }它并不是一个DependencyProperty因此无法作为 Binding 的目标——这正是官方文档标注出于安全考虑无法绑定的原因。你可以通过代码pinBox.Password读取但无法在 XAML 中对其做{Binding ...}或{x:Bind}。setter 的存在主要是为了支持 XAML 预置初始值如hc:PinBox Password1234/以及不安全模式下的回写。由于读取时机可能早于模板应用setter 会先把密码逐字符存入ListSecureString待OnApplyTemplate时再通过Marshal.SecureStringToGlobalAllocUnicode转出并逐个填充到单元框用完立即ZeroFreeGlobalAllocUnicode释放、password.Clear()清空PinBox.cs、PinBox.cs。从源码结构看这一过程刻意使用SecureString避免明文字符串在托管堆中长期驻留。Length密码长度最小 4不足自动回钳Length是最重要的布局参数注册时同时携带了校验与强制回调PinBox.cspublic static readonly DependencyProperty LengthProperty DependencyProperty.Register( nameof(Length), typeof(int), typeof(PinBox), new PropertyMetadata(MinLength, OnLengthChanged, CoerceLength), ValidateHelper.IsInRangeOfPosInt); private static object CoerceLength(DependencyObject d, object basevalue) (int) basevalue 4 ? MinLength : basevalue;默认值MinLength 4通过ValidateHelper.IsInRangeOfPosInt校验必须为正整数非法值会被拒绝CoerceLength会把任何小于 4 的值钳制回 4因此你无法得到 1~3 位的 PinBoxLength一旦变化会触发UpdateItems()重建全部单元框已输入的密码将丢失。PasswordChar掩码字符PasswordChar通过AddOwner复用了 WPF 原生PasswordBox.PasswordCharProperty默认值为●PinBox.cs因此它支持与原生 PasswordBox 相同的char赋值语法例如PasswordChar❤。该值会被透传给每个内部单元框。ItemMargin / ItemWidth / ItemHeight单元外观这三个属性分别控制每个单元框的间隔Thickness、宽度与高度double。需要注意它们只是普通属性不参与PART_Panel的网格布局计算面板列数由 Length 决定实际效果由默认样式的默认值决定ItemMargin默认4,0水平间距 4、垂直 0ItemWidth与ItemHeight默认均为主题资源DefaultControlHeight与控件标准高度一致PinBoxBaseStyle.xaml。若你希望单元框更小、间距更密例如验证码输入场景可覆盖这三项。事件CompletedCompleted是一个冒泡型RoutingStrategy.Bubble路由事件注册于控件类型PinBox.cspublic static readonly RoutedEvent CompletedEvent EventManager.RegisterRoutedEvent(Completed, RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(PinBox)); public event RoutedEventHandler Completed { add AddHandler(CompletedEvent, value); remove RemoveHandler(CompletedEvent, value); }触发时机当最后一个单元框输入了字符且所有单元框均已非空时触发PinBox.cs。触发前会先清除键盘焦点if (_inputIndex Length) { _inputIndex Length - 1; if (_panel.Children.OfTypeSystem.Windows.Controls.PasswordBox() .All(item item.Password.Any())) { FocusManager.SetFocusedElement(this, null); Keyboard.ClearFocus(); RaiseEvent(new RoutedEventArgs(CompletedEvent, this)); } return; }由于它是路由事件既可以在 XAML 中直接挂接hc:PinBox.Completed...也可以通过AddHandler在代码中订阅。事件参数的OriginalSource即 PinBox 本身可据此读取Password。官方演示PinBoxDemo.xaml.cs的做法是private void PinBox_OnCompleted(object sender, RoutedEventArgs e) { if (e.OriginalSource is PinBox pinBox) { Growl.Info(pinBox.Password); } }内置键盘交互逻辑PinBox 没有自定义按键来接收输入而是接管了单元之间的焦点流转相关逻辑集中在三个重写方法里自动前进PasswordBoxsPasswordChanged中当某位输入了字符Password.Length 0且未到末位时_inputIndex自增并把焦点移到下一个单元反之当某位被清空时焦点回退到上一个单元PinBox.cs。左右方向键OnPreviewKeyDown处理Key.Left/Key.Right在单元间移动焦点并SelectAll()选中当前位便于覆盖输入PinBox.cs。删除与退格OnPreviewKeyUp处理Key.Delete/Key.Back借助_isInternalAction标志避免删除动作再次触发密码变化事件造成焦点错乱随后把焦点退回前一个单元PinBox.cs。此外任一单元获得焦点时会记录当前索引并SelectAll()PasswordBoxsGotFocus保证用户直接点击任意格子后都能从该位开始输入。控件自身FocusableFalse初始聚焦由PinBox_Loaded中的FocusPasswordBox()完成——当 PinBox 自身处于焦点状态时会把焦点转移给第一个单元PinBox.cs。安全模式与 UnsafePasswordPinBox 从 HandyControl 的PasswordBox复用了两个附加在控件上的属性PinBox.csIsSafeEnabled安全模式开关默认True。为True时密码只存在于各单元 PasswordBox 内部不对外暴露为False时控件会把明文同步到UnsafePassword。UnsafePassword不安全模式下的明文密码注册时带BindsTwoWayByDefault默认绑定模式为双向。仅在IsSafeEnabled False时有效。官方演示正好展示了这一用法PinBoxDemo.xamlhc:UniformSpacingPanel Spacing16 OrientationVertical Margin32 VerticalAlignmentCenter hc:PinBox.CompletedPinBox_OnCompleted hc:PinBox Length4 Password1234/ hc:PinBox Length4 Password1234 NamepinBoxDemo IsSafeEnabledFalse/ TextBox Text{Binding UnsafePassword, ElementNamepinBoxDemo, UpdateSourceTriggerPropertyChanged}/ hc:PinBox Length6 Password123456 PasswordChar❤/ /hc:UniformSpacingPanel当需要把 PinBox 的密码双向绑定到 ViewModel 时标准做法是设置IsSafeEnabledFalse然后绑定UnsafePassword如果保持默认安全模式则只能通过代码读取Password这正是出于安全考虑无法绑定的完整含义。实战完整使用示例综合官方文档与演示工程一个可直接运行的典型用法如下xmlns:hc 为 HandyControl 命名空间StackPanel Margin32 VerticalAlignmentCenter hc:PinBox.CompletedPinBox_OnCompleted !-- 4 位 PIN默认掩码 ●默认样式自带 4,0 间隔与标准单元尺寸 -- hc:PinBox Length4 Password1234/ !-- 6 位 PIN自定义掩码字符并设置单元间隔与尺寸 -- hc:PinBox Length6 Password123456 Margin0,16,0,0 PasswordChar❤ ItemMargin8,0 ItemWidth48 ItemHeight48/ /StackPanel要点回顾Length最小为 4设小值会被自动钳制回 4设非正整数会被校验拒绝默认密码为●可换成任意char输入完最后一位且所有格子非空时触发Completed此时焦点已被清除可在处理函数中通过e.OriginalSource as PinBox读取Password需要绑定时改用IsSafeEnabledFalse 双向绑定UnsafePassword单元框尺寸与间距由ItemWidth/ItemHeight/ItemMargin控制默认值定义在 PinBoxBaseStyle.xaml整体样式通过 PinBox.xaml 以BasedOn方式挂接并在 Theme.xaml 中统一注册为默认主题样式引入 HandyControl 主题后即可直接使用。总结PinBox 用一组受控的单元 PasswordBox 实现了逐位输入的 PIN 码交互Length决定格子数量最小 4、PasswordChar决定掩码、Completed在输满时通知业务代码安全模式下密码以SecureString暂存且不可绑定需要双向绑定则显式关闭IsSafeEnabled。从源码PinBox.cs与默认样式PinBoxBaseStyle.xaml可以看出焦点自动流转、左右键移动与退格回退等细节均已内置接入时只需关注属性和事件即可。赞分享UI组件桌面应用【免费下载链接】HandyControlContains some simple and commonly used WPF controls项目地址https://gitcode.com/gh_mirrors/ha/HandyControl点击查看免费下载相关推荐HandyControl Pagination 页码条控件实战指南属性、事件与源码级分页原理HandyControl Pagination 页码条控件实战指南属性、事件与源码级分页原理 当列表数据量过多时使用分页拆分数据能显著提升浏览效率与界面整洁UI组件桌面应用HandyControl Divider 分割线控件完全指南属性详解、样式定制与源码实现HandyControl Divider 分割线控件完全指南属性详解、样式定制与源码实现 本指南围绕 HandyControl 中的 Divider分割线UI组件桌面应用HandyControl StepBar 步骤条控件详解属性、方法、事件与实战案例HandyControl StepBar 步骤条控件详解属性、方法、事件与实战案例 导读 StepBar步骤条是 HandyControl 中用于引导用户UI组件桌面应用上一篇如何在Shell中格式化并打印当前日期时间 - jbranchaud/til项目技巧下一篇如何快速部署Apache PredictionIO推荐引擎Docker完整安装指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考