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)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • C++stl库_c++库

    C++stl库_c++库熟练使用STL标准库是每个C++程序员的必备技能。C++标准程序库发展至今,几乎所有内容都被设计为了模板的形式,STL已经成为C++程序库的重要组成部分。可以这么说,如果C++不支持STL标准模板库,就无法使用程序库。在大多数人看来,计算机既神秘有能干,但在程序员的眼中,计算机又蠢又笨,唯一的优点就是运算速度比人快,不给指令什么都干不了,就是给指令,计算机也不能灵活运用。比如说,在C++中,同样一个加法,不同的数据类型,要给出不同的运行代码:#include<iostrea

    2022年10月9日
  • [已发表,转载勘误]Android upx脱壳「建议收藏」

    [已发表,转载勘误]Android upx脱壳「建议收藏」已发在https://www.anquanke.com/post/id/197643不过有部分内容发布之后无法编辑,勘误后如下。Androidupx脱壳写在前面因为我不是pc平台过来的,而是直接从Android入门的,所以upx壳其实一开始并不了解,后来接触到,但是可以直接动态调试或者做个内存快照,对我来说加没加upx其实对我逆向分析影响不大。另一方面upx壳因为开源且其实有很多脱壳的教…

    2022年7月19日
  • php属于前端还是后端_php实时推送到前端

    php属于前端还是后端_php实时推送到前端功能说明使用第三方平台goeasy实现服务端向前端推送数据基本原理WebSocket使用准备申请goeasy账号并创建应用官网http://www.goeasy.io安装并开启goeasy插件(注意清除缓存)在插件配置中填写应用的Appkeys等配置项使用说明使用插件集成的事件插件在前台(index模块)和后台(admin模块)各集成了两个默认的事件订阅,可以在js中通过监听top来处理,例:也…

    2022年11月1日
  • 【Win7】【磁盘管理】删除相似“33fbc1d57e9aaf1ea88e6f08”缓存目录

    【Win7】【磁盘管理】删除相似“33fbc1d57e9aaf1ea88e6f08”缓存目录

    2021年12月31日
  • littlevgl移植_嵌入式ubuntu系统

    littlevgl移植_嵌入式ubuntu系统总述Littlevgl相比较于安卓、QT,占用资源少、使用简单,所以在linux系统下使用Littlevgl优势也比较明显。移植准备工作源码:lvgl:https://github.com/littlevgl/lvgl驱动:lv_drivers:https://github.com/littlevgl/lv_drivers例子:lv_examples:https://github.com/littlevgl/lv_examples下载慢可以将上面链接先导入到码云上再下载。配置工作源码

    2022年9月2日
  • js算法初窥05(算法模式02-动态规划与贪心算法)

    在前面的文章中(js算法初窥02(排序算法02-归并、快速以及堆排)我们学习了如何用分治法来实现归并排序,那么动态规划跟分治法有点类似,但是分治法是把问题分解成互相独立的子问题,最后组合它们的结果,而

    2022年3月25日

发表回复

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

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