zoukankan      html  css  js  c++  java
  • UWP 自定义密码框控件

    1. 概述

    微软官方有提供自己的密码控件,但是控件默认的行为是输入密码,会立即显示掩码,比如 *。如果像查看真实的文本,需要按查看按钮。

    而我现在自定义的密码控件是先显示你输入的字符2s,然后再显示成掩码。当然这种场景并不一定适用于密码,也可以用在Pin码。

    a. 微软官方的密码框

     

    b. 自定义的效果

    2. 密码框控件实现

    要想实现自定义的密码框,我们当然要继承微软的TextBox控件,然后加入我们自己需要的东西。

    a. 这里添加了一个加密类型的密码 Password 字段,真实密码文本 RealPassword 字段,一个Timer定时器来控制显示掩码

    internal class CustomPasswordBox : TextBox
        {
            #region Member Variables
            public static readonly DependencyProperty PasswordProperty =
                DependencyProperty.Register("Password", typeof(SecureString), typeof(CustomPasswordBox), new PropertyMetadata(new SecureString()));
    
            public static readonly DependencyProperty RealPasswordProperty =
                DependencyProperty.Register("RealPassword", typeof(string), typeof(CustomPasswordBox), new PropertyMetadata(string.Empty));
    
            private DispatcherTimer maskTimer;
            #endregion
        }

    b. 公开控件属性字段

    public SecureString Password
            {
                get
                {
                    return (SecureString)GetValue(PasswordProperty);
                }
    
                set
                {
                    SetValue(PasswordProperty, value);
                }
            }
    
    
            public string RealPassword
            {
                get
                {
                    return (string)GetValue(RealPasswordProperty);
                }
    
                set
                {
                    SetValue(RealPasswordProperty, value);
                }
            }

    c. 然后再构造函数里添加一个需要相应的事件,还有初始化Timer

    public CustomPasswordBox()
            {
                PreviewKeyDown += CustomPasswordBox_PreviewKeyDown;
                CharacterReceived += CustomPasswordBox_CharacterReceived;
                BeforeTextChanging += CustomPasswordBox_BeforeTextChanging;
                SelectionChanged += CustomPasswordBox_SelectionChanged;
                ContextMenuOpening += CustomPasswordBox_ContextMenuOpening;
                TextCompositionStarted += CustomPasswordBox_TextCompositionStarted;
    
                maskTimer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 2) };
                maskTimer.Tick += MaskTimer_Tick;
            }


    在PreviewKeyDown、CharacterReceived、BeforeTextChanging这三个事件里,主要处理字符的输入删除等逻辑。
    在SelectionChanged事件里,我们主要处理不让用户选中文本
    在ContextMenuOpening,主要是屏蔽右键菜单,比如复制剪切粘贴
    在TextCompositionStarted主要屏蔽中文等组合输入法

    另外,在我的场景里面,我们只让用户输入数字,所以加入了数字验证,以及在Xbox上开启了InputScope=NumbericPin模式。

    d. 添加事件响应代码

    private void CustomPasswordBox_PreviewKeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
            {
                switch (e.OriginalKey)
                {
                    case VirtualKey.Back:
                    case VirtualKey.Delete:
                        if (SelectionLength > 0)
                        {
                            RemoveFromSecureString(SelectionStart, SelectionLength);
                        }
                        else if (e.OriginalKey == VirtualKey.Delete && SelectionStart < Text.Length)
                        {
                            RemoveFromSecureString(SelectionStart, 1);
                        }
                        else if (e.OriginalKey == VirtualKey.Back && SelectionStart > 0)
                        {
                            int caretIndex = SelectionStart;
                            if (SelectionStart > 0 && SelectionStart < Text.Length)
                                caretIndex = caretIndex - 1;
                            RemoveFromSecureString(SelectionStart - 1, 1);
                            //SelectionStart = caretIndex;
                        }
    
                        e.Handled = true;
                        break;
    
                    default:
                        //e.Handled = true;
                        break;
                }
            }
    
            private void CustomPasswordBox_CharacterReceived(UIElement sender, Windows.UI.Xaml.Input.CharacterReceivedRoutedEventArgs args)
            {
                if (!char.IsDigit(args.Character))
                    return;
    
                AddToSecureString(args.Character.ToString());
                args.Handled = true;
            }
    
            private void CustomPasswordBox_BeforeTextChanging(TextBox sender, TextBoxBeforeTextChangingEventArgs args)
            {
                args.Cancel = args.NewText.Any(c => !char.IsDigit(c) && !char.ToString(c).ToString().Equals(""));
                //if (args.NewText.Replace("●", "") != "")
                //    AddToSecureString(args.NewText.Replace("●", ""));
            }
    
            private void CustomPasswordBox_ContextMenuOpening(object sender, ContextMenuEventArgs e)
            {
                e.Handled = true;
            }
    
            private void CustomPasswordBox_SelectionChanged(object sender, RoutedEventArgs e)
            {
                SelectionStart = Text.Length;
                SelectionLength = 0;
            }
    
            private void CustomPasswordBox_TextCompositionStarted(TextBox sender, TextCompositionStartedEventArgs args)
            {
                return;
            }
    
            private void MaskTimer_Tick(object sender, object e)
            {
                MaskAllDisplayText();
            }

    e. 实现Timer里面的2s后将字符串变成掩码

    2s后看TextBox里面的字符数,然后设置对应长度的掩码

            private void MaskAllDisplayText()
            {
                maskTimer.Stop();
                int caretIndex = SelectionStart;
                Text = new string('', Text.Length);
                SelectionStart = caretIndex;
            }

    f. 添加字符和删除字符

     private void AddToSecureString(string text)
            {
                if (SelectionLength > 0)
                {
                    RemoveFromSecureString(SelectionStart, SelectionLength);
                }
    
                if (Password.Length >= 4 || RealPassword.Length >= 4)
                    return;
                foreach (char c in text)
                {
                    System.Diagnostics.Debug.WriteLine(text);
                    int caretIndex = SelectionStart;
                    if (caretIndex - 1 < 0)
                        Password.InsertAt(0, c);
                    else
                        Password.InsertAt(caretIndex - 1, c);
                    RealPassword += c.ToString();
                    //MaskAllDisplayText();
                    if (caretIndex == Text.Length)
                    {
                        maskTimer.Stop();
                        maskTimer.Start();
                        //Text = Text.Insert(caretIndex++, c.ToString());
                    }
                    else
                    {
                        //Text = Text.Insert(caretIndex++, "●");
                    }
                    SelectionStart = Text.Length;
                }
            }
    
            private void RemoveFromSecureString(int startIndex, int trimLength)
            {
                int caretIndex = SelectionStart;
                for (int i = 0; i < trimLength; ++i)
                {
                    Password.RemoveAt(startIndex);
                    RealPassword = RealPassword.Remove(startIndex, 1);
                }
    
                Text = Text.Remove(startIndex, trimLength);
                SelectionStart = caretIndex;
            }

    3. 控件使用方法

    <local:CustomPasswordBox 
                InputScope="NumericPin"
                MaxLength="4" />

    一个例子

    <Grid>
            <local:CustomPasswordBox 
                x:Name="PSW" 
                InputScope="NumericPin" 
                Padding="200 0 0 0" 
                Style="{StaticResource MyTextBox}" 
                Height="Auto" 
                MaxLength="4" 
                CharacterSpacing="1000" 
                FontSize="100" 
                VerticalAlignment="Top"/>
            <TextBlock 
                x:Name="realPSW" 
                FontSize="88" 
                Margin="0 200"
                HorizontalAlignment="Center" 
                Text="{Binding ElementName=PSW, Path=RealPassword, Mode=OneWay}"/>
        </Grid>

    你也可以看我在Youtube上的视频演示

    https://youtu.be/eHhDG3dW1bI

    欢迎点击右下角的订阅按钮,还有红色小铃铛。谢谢

  • 相关阅读:
    NFC性价比高频读卡器首选方案:FM17550
    关于ESP8266和ESP8285的对比
    有没有比NRF51822更好的智能穿戴蓝牙方案
    zigbee CC2530首选方案模组:TZU06A1
    PAN3501兼容AS3933-BTST
    NRF51822和NRF52832的主要区别
    集成模拟温度传感器低成本2.4G CC2500RGPR 中文手册
    USB2.0主机控制器 UPD720114 简单详解
    存储器HK1225-7EQ 使用说明书资料
    爬虫 + 数据
  • 原文地址:https://www.cnblogs.com/hupo376787/p/13372655.html
Copyright © 2011-2022 走看看