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

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

大家好,又见面了,我是你们的朋友全栈君。

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属性即可

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/161499.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • js定时器与延时器_JS做定时器倒计时

    js定时器与延时器_JS做定时器倒计时定时器创建定时器window.setInterval(方法类型,间隔时间(1000=1秒))vartimer=window.setInterval(func,2000);vari=0functionfunc(){console.log(“你好”,i)i+=1}清除定时器window.clearInterval(定时器名)functionting(){//清除定时器window.clearInterval(timer…

    2025年8月24日
    4
  • c语言整数取位_c语言的位运算符号

    c语言整数取位_c语言的位运算符号案例:#include <stdio.h>#include <stdint.h>int main(void){ int8_t i8 = 100; int16_t i16 = 666; int32_t product = i8*i16; printf(“product=%d\n”,product); return 0;}结果:…

    2022年8月18日
    14
  • 男生喜欢收到女朋友什么样的礼物?

    男生喜欢收到女朋友什么样的礼物?首先你的男朋友不抽烟、不喝酒,这个习惯还是挺好的。其实每个人都有爱好的一方面,你可以根据他平时的爱好所选择。根据你提问的文字中,说到了女朋友三个字,我想你们应该是恋爱了吧。既然已经在一起了,那你就应该知道他的兴趣爱好啊。如果不知道,也可以问他一下,不要直接问,用需要去套他的话。那说到男生喜欢收到什么礼物,我认为只要是自己女朋友送的,男生都应该喜欢,因为他明白,你是有这份心意的,在你心里也是有份量的。其次,就是刚才说的“对症下药。”你要先明白你送礼物的目的是什么?如果你们还没在一起,只是你

    2022年7月25日
    11
  • 对于Hadoop的MapReduce编程makefile[通俗易懂]

    对于Hadoop的MapReduce编程makefile

    2022年1月17日
    43
  • Perl threads 摘要

    Perl threads 摘要最近又写了一个多线程的小工具 对一些多线程的使用有了进一步的心得 Perl 创建线程有两种方式 正常通过 threads create 创建线程 用 async nbsp 创建一个调用匿名过程的线程 具体参考 perldocthrea 线程共享变量需要使用 threads shared 共享变量只能存储 scalar 共享变量的引用 如果存储 ListHash 的引用需使用 shared clo

    2025年6月30日
    2
  • 区块链–Arbitrum Rollup(Layer2)

    区块链–Arbitrum Rollup(Layer2)Arbitrum是OffchainLabs团队开发的以太坊Layer2层扩容方案,可以实现高吞吐量,让开发者以低成本部署、运营智能合约,同时可以保持无需信任的安全性总结:Rollup的主要特点是所有交易数据都记录在链上,也就是说,Arbitrum把关乎安全的部分放在以太坊链上,将实际计算和存储放在链下执行。

    2022年5月11日
    42

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号