WPF TextBox模仿PasswordBox的密码显示功能(二)(升级版)

发布时间:2025-12-09 14:00:43 浏览次数:4

WPF TextBox模仿PasswordBox的密码显示功能(二)(升级版)

这并不是多此一举,因为WPF的PasswordBox不支持继承,所以想扩展PasswordBox的属性就没法实现,所以有了本文内容,当然这个思路也可以扩展到其他语言。

一、新建自定义控件
二、下面是完整的类(这是创建了一个“自定义控件”)

using System.Windows;namespace SuperControl{ /// <summary>/// SuperPasswordBoxPro/// </summary>public class SuperPasswordBoxPro : TextBox{ static SuperPasswordBoxPro(){ DefaultStyleKeyProperty.OverrideMetadata(typeof(SuperPasswordBoxPro), new FrameworkPropertyMetadata(typeof(STextBox)));//重写Text属性改变回调方法TextProperty.OverrideMetadata(typeof(SuperPasswordBoxPro), new FrameworkPropertyMetadata(new PropertyChangedCallback(TextChangedCallback)));}//Text属性改变回调方法private static void TextChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e){ SuperPasswordBoxPro instance = (SuperPasswordBoxPro)d;//新的前端密码文本string text = e.NewValue.ToString();//已键入的文本长度int textLength = text.Length;//已保存的密码长度int psdLength = instance.Password.Length;//判断密码是否已修改if (textLength == psdLength && text == new string(instance.PasswordChar, text.Length)) return;//记住光标位置(设置完Text后会丢失,所以现在要记住)int selectionStart = instance.SelectionStart;//起始修改位置int startIndex = -1;for (int i = 0; i < textLength; i++){ if (text[i] != instance.PasswordChar){ startIndex = i;break;}}//结束修改位置int stopIndex = -1;for (int i = textLength - 1; i >= 0; i--){ if (text[i] != instance.PasswordChar){ stopIndex = i;break;}}//添加或修改了一个或连续的多个值if (startIndex != -1){ //累计修改长度int alterLength = stopIndex - startIndex + 1;//长度没变化,单纯的修改了一个或连续的多个值if (textLength == psdLength){ instance.Password = instance.Password.Substring(0, startIndex) + text.Substring(startIndex, alterLength) + instance.Password.Substring(stopIndex + 1);}//新增了内容else{ //新增且修改了原来内容if (alterLength > textLength - psdLength){ //计算未修改密码个数 textLength - alterLength//计算已修改密码个数 = 原密码长度 - 未修改密码个数 psdLength - (textLength - alterLength)//原密码该保留的后半部分的索引 = 已修改密码个数 + 起始修改位置instance.Password = instance.Password.Substring(0, startIndex) + text.Substring(startIndex, alterLength) + instance.Password.Substring(psdLength - (textLength - alterLength) + startIndex);}//单纯的新增了一个或多个连续的值else{ instance.Password = instance.Password.Substring(0, startIndex) + text.Substring(startIndex, alterLength) + instance.Password.Substring(startIndex);}}}//删除了一个或连续的多个值else{ //已删除的数据长度 SelectionStart 为 TextBox 的属性(获取或设置当前所选内容的起始位置的字符索引)int length = psdLength - textLength;if (instance.SelectionStart < textLength){ //改变了中间的数据instance.Password = instance.Password.Substring(0, instance.SelectionStart) + instance.Password.Substring(instance.SelectionStart + length);}else{ //删除了结尾的数据instance.Password = instance.Password.Substring(0, instance.SelectionStart);}}//设置光标位置instance.SelectionStart = selectionStart;}/// <summary>/// 密码/// </summary>public string Password{ get {  return (string)GetValue(PasswordProperty); }set {  SetValue(PasswordProperty, value); }}public static readonly DependencyProperty PasswordProperty =DependencyProperty.Register("Password", typeof(string), typeof(SuperPasswordBoxPro), new PropertyMetadata("", new PropertyChangedCallback(PasswordChangedCallback)));//Password属性改变回调方法private static void PasswordChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e){ SuperPasswordBoxPro instance = (SuperPasswordBoxPro)d;instance.Text = new string(instance.PasswordChar, e.NewValue.ToString().Length);}/// <summary>/// 密码显示字符/// </summary>public char PasswordChar{ get {  return (char)GetValue(PasswordCharProperty); }set {  SetValue(PasswordCharProperty, value); }}public static readonly DependencyProperty PasswordCharProperty =DependencyProperty.Register("PasswordChar", typeof(char), typeof(SuperPasswordBoxPro), new PropertyMetadata('●'));}}

三、如何使用
1、将命名空间改成你自己项目的,也就是nampspace和你项目保持一致
2、xaml里直接<local:SuperPasswordBoxPro />即可
3、Password属性才是真实的密码,请不要用Text属性
4、MVVM用到数据绑定的时候直接绑定Password属性即可

有问题欢迎留言,如果觉得有用请点个”赞”,谢谢!

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477