WPF实现授权码显示密文并支持换行

 更新时间:2024年10月22日 15:19:37   作者:WPF开发者  
这篇文章主要为大家详细介绍了如何使用WPF实现授权码显示密文并支持换行,文中的示例代码讲解详细,有需要的小伙伴可以参考一下

WPF 授权码显示密文并支持换行

  • 框架使用.NET8
  • Visual Studio 2022;

有开发者需要制作一个授权码输入框输入内容后显示密文并且能 Enter 进行换行输入。由于无法使用 PasswordBox 控件本身不支持换行,因为它设计为单行输入控件。

所以最简单的方法是使用 TextBox 并通过自定义逻辑代码来掩盖输入的文本。这样可以实现多行输入,处理文本显示和密码掩码的逻辑。

接下来我们自定义一个控件 MultiLinePasswordBox 继承 TextBox 输入字符会以密码字符(如默认的 )显示。

私有字段如下:

  • passwordBuilder 用于存储密码。
  • previousText 用于存放上一次的文本。
  • isUpdating 用于记录是否正在编辑。

依赖属性如下:

  • PasswordChar:用于显示密码字符的字符,如果未显示则默认为
  • PlainText:控件中原始的未掩盖的文本。

构造函数:

  • 设置 TextWrapping = TextWrapping.Wrap; 支持多行显示。
  • 设置 AcceptsReturn = true 支持按下 Enter 换行。
  • 订阅 TextChanged 事件,文本更改时将输入的文本转换为密码掩码,如果 isUpdating 的标志为 true ,则直接返回,避免重复更新文本。
  • 计算当前输入文本和上一次文本之间的长度差异,如果长度是正数则插入,反之长度差异是负数则删除。
  • 调用 CreateMaskedTextWithLineBreaks 方法创建带有掩码和换行符的文本。
  • 更新控件的文本,保持光标位置不变,并更新PlainText。

1)MultiLinePasswordBox.cs 代码如下:

using System;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace WpfTextOrPasswordBox
{
    public class MultiLinePasswordBox : TextBox
    {
        private StringBuilder passwordBuilder = new StringBuilder();
        private string previousText = string.Empty;
        private bool isUpdating = false;

        public char PasswordChar
        {
            get { return (char)GetValue(PasswordCharProperty); }
            set { SetValue(PasswordCharProperty, value); }
        }

        public static readonly DependencyProperty PasswordCharProperty =
            DependencyProperty.Register("PasswordChar", typeof(char), typeof(MultiLinePasswordBox), new PropertyMetadata('●'));


        public string PlainText
        {
            get { return (string)GetValue(PlainTextProperty); }
            set { SetValue(PlainTextProperty, value); }
        }

        public static readonly DependencyProperty PlainTextProperty =
            DependencyProperty.Register("PlainText", typeof(string), typeof(MultiLinePasswordBox), new PropertyMetadata(string.Empty));


        public MultiLinePasswordBox()
        {
            AcceptsReturn = true;
            TextWrapping = TextWrapping.Wrap;
            VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
            TextChanged += PasswordTextBox_TextChanged;
        }

        private void PasswordTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (isUpdating)
                return;

            isUpdating = true;
            var caretIndex = CaretIndex;
            var input = Text;
            if (string.IsNullOrWhiteSpace(Text))
            {
                passwordBuilder.Clear();
            }
            else
            {
                var s = passwordBuilder.Length;
                int lengthDifference = input.Length - previousText.Length;
                if (lengthDifference > 0)
                {
                    var newText = input.Substring(caretIndex - lengthDifference, lengthDifference);
                    passwordBuilder.Insert(caretIndex - lengthDifference, newText);
                }
                else if (lengthDifference < 0)
                {
                    passwordBuilder.Remove(caretIndex, Math.Abs(lengthDifference));
                    if (passwordBuilder[caretIndex - 1].ToString() != input)
                    {
                        var index = passwordBuilder.ToString().IndexOf(passwordBuilder[caretIndex - 1]);
                        passwordBuilder.Replace(passwordBuilder[caretIndex - 1], input.Last());
                    }
                }
                var maskedText = CreateMaskedTextWithLineBreaks(passwordBuilder.ToString());
                TextChanged -= PasswordTextBox_TextChanged;
                Text = maskedText;
                TextChanged += PasswordTextBox_TextChanged;
            }
            previousText = Text;
            CaretIndex = caretIndex;
            PlainText = passwordBuilder.ToString();
            isUpdating = false;
        }

        private string CreateMaskedTextWithLineBreaks(string text)
        {
            var maskedText = new StringBuilder();
            foreach (char c in text)
            {
                if (c == '\r' || c == '\n')
                    maskedText.Append(c);
                else
                    maskedText.Append(PasswordChar.ToString());
            }
            return maskedText.ToString();
        }
    }
}

2)MultiLinePasswordBoxSample.xaml 代码如下:

<wd:Window
    x:Class="WpfTextOrPasswordBox.MultiLinePasswordBoxSample"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfTextOrPasswordBox"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers"
    Title="MultiLinePasswordBoxSample - WPF开发者"
    Width="800"
    Height="450"
    WindowStartupLocation="CenterScreen"
    mc:Ignorable="d">
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Margin="0,20">
                <Run Text="明文:" />
                <Run Text="{Binding ElementName=myMultiLinePasswordBox, Path=PlainText}" />
            </TextBlock>
            <local:MultiLinePasswordBox
                x:Name="myMultiLinePasswordBox"
                Width="200"
                Height="60"
                wd:ElementHelper.CornerRadius="3"
                wd:ElementHelper.Watermark="请输入授权码" />
        </StackPanel>
    </Grid>
</wd:Window>

效果图

到此这篇关于WPF实现授权码显示密文并支持换行的文章就介绍到这了,更多相关WPF授权码显示密文内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论