『7x24小时有问必答』
前言
在WPF应用程序开发中,用户界面的友好性和安全性是至关重要的。特别是在涉及敏感信息(如密码)输入时,提供一个既安全又便捷的输入方式显得尤为重要。
WPF以其强大的UI设计能力,为开发者提供了丰富的控件和灵活的定制选项。然而,默认的 
PasswordBox
 控件在某些场景下可能无法满足所有需求,例如需要支持数据绑定或动态控制密码的显示与隐藏。
正文
设计并实现了一个自定义的WPF密码框控件,该控件不仅继承了 
PasswordBox
 的基本功能,还增加了对数据绑定的支持以及密码显示/隐藏的功能切换。
通过这一自定义控件,我们可以更轻松地创建出符合用户体验要求的安全输入界面,同时简化代码逻辑,提升开发效率。
Converter 类
using System;

using System.Collections.Generic;

using System.Globalization;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Data;

using System.Windows;

namespaceWpfApp1

{

    /// 

    /// 

    /// 

    publicclassBooleanToVisibilityConverter : IValueConverter

    {

        publicbool IsInversed { getset; }

        /// 

        /// 

        /// 

        /// 

        /// 

        /// 

        /// 

        /// 

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            if (valueisbool realValue)

            {

                if (IsInversed)

                    realValue = !realValue;

                return realValue ? Visibility.Visible : Visibility.Collapsed;

            }

            return Visibility.Collapsed;

        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            thrownew NotImplementedException();

        }

    }

}

控件代码
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

namespaceWpfApp1

{

    /// 

    /// 通用密码框

    /// 

    [TemplatePart(Name = PART_PasswordBox, Type = typeof(PasswordBox))]

    [TemplatePart(Name = PART_TextBox, Type = typeof(TextBox))]

    publicclassCommonPasswordBoxWithToggle : UserControl

    {

        #region 常量

        publicconststring PART_PasswordBox = "PART_PasswordBox";

        publicconststring PART_TextBox = "PART_TextBox";

        #endregion

        #region 属性

        /// 

        /// 密码框

        /// 

        private PasswordBox PARTPasswordBox { getset; }

        /// 

        /// 文本框

        /// 

        private TextBox PARTTextBox { getset; }

        #endregion

        #region 依赖属性

        /// 

        /// 密码

        /// 

        publicstring Password

        {

            get { return (string)GetValue(PasswordProperty); }

            set { SetValue(PasswordProperty, value); }

        }

        // Using a DependencyProperty as the backing store for Password.  This enables animation, styling, binding, etc...

        publicstaticreadonly DependencyProperty PasswordProperty =

            DependencyProperty.Register("Password"typeof(string), typeof(CommonPasswordBoxWithToggle), new PropertyMetadata(string.Empty));

        /// 

        /// 是否显示密码

        /// 

        publicbool IsPasswordVisible

        {

            get { return (bool)GetValue(IsPasswordVisibleProperty); }

            set { SetValue(IsPasswordVisibleProperty, value); }

        }

        // Using a DependencyProperty as the backing store for IsPasswordVisible.  This enables animation, styling, binding, etc...

        publicstaticreadonly DependencyProperty IsPasswordVisibleProperty =

            DependencyProperty.Register("IsPasswordVisible"typeof(bool), typeof(CommonPasswordBoxWithToggle), new PropertyMetadata(false));

        /// 

        /// 左侧图标按钮内容

        /// 

        /// 

        publicstring LeftIconButtonContent

        {

            get { return (string)GetValue(LeftIconButtonContentProperty); }

            set { SetValue(LeftIconButtonContentProperty, value); }

        }

        // Using a DependencyProperty as the backing store for LeftIconButtonContent.  This enables animation, styling, binding, etc...

        publicstaticreadonly DependencyProperty LeftIconButtonContentProperty =

            DependencyProperty.Register("LeftIconButtonContent"typeof(string), typeof(CommonPasswordBoxWithToggle), new PropertyMetadata(string.Empty));

        /// 

        /// 左侧图标按钮显示

        /// 

        /// 

        public Visibility LeftIconButtonVisibility

        {

            get { return (Visibility)GetValue(LeftIconButtonVisibilityProperty); }

            set { SetValue(LeftIconButtonVisibilityProperty, value); }

        }

        // Using a DependencyProperty as the backing store for LeftIconButtonVisibility.  This enables animation, styling, binding, etc...

        publicstaticreadonly DependencyProperty LeftIconButtonVisibilityProperty =

            DependencyProperty.Register("LeftIconButtonVisibility"typeof(Visibility), typeof(CommonPasswordBoxWithToggle), new PropertyMetadata(Visibility.Collapsed));

        publicstring WaterText

        {

            get { return (string)GetValue(WaterTextProperty); }

            set { SetValue(WaterTextProperty, value); }

        }

        // Using a DependencyProperty as the backing store for WaterText.  This enables animation, styling, binding, etc...

        publicstaticreadonly DependencyProperty WaterTextProperty =

            DependencyProperty.Register("WaterText"typeof(string), typeof(CommonPasswordBoxWithToggle), new PropertyMetadata(string.Empty));

        /// 

        /// 隐藏密码图标

        /// 

        publicstring HidePasswordIcon

        {

            get { return (string)GetValue(HidePasswordIconProperty); }

            set { SetValue(HidePasswordIconProperty, value); }

        }

        // Using a DependencyProperty as the backing store for HidePasswordIcon.  This enables animation, styling, binding, etc...

        publicstaticreadonly DependencyProperty HidePasswordIconProperty =

            DependencyProperty.Register("HidePasswordIcon"typeof(string), typeof(CommonPasswordBoxWithToggle), new PropertyMetadata(string.Empty));

        /// 

        /// 显示密码图标

        /// 

        publicstring ShowPasswordIcon

        {

            get { return (string)GetValue(ShowPasswordIconProperty); }

            set { SetValue(ShowPasswordIconProperty, value); }

        }

        // Using a DependencyProperty as the backing store for ShowPasswordIcon.  This enables animation, styling, binding, etc...

        publicstaticreadonly DependencyProperty ShowPasswordIconProperty =

            DependencyProperty.Register("ShowPasswordIcon"typeof(string), typeof(CommonPasswordBoxWithToggle), new PropertyMetadata(string.Empty));

        #endregion

        #region 构造

        static CommonPasswordBoxWithToggle()

        {

            DefaultStyleKeyProperty.OverrideMetadata(typeof(CommonPasswordBoxWithToggle), new FrameworkPropertyMetadata(typeof(CommonPasswordBoxWithToggle)));

        }

        #endregion

        #region 方法

        /// 

        /// 应用模板

        /// 

        override public void OnApplyTemplate()

        {

            base.OnApplyTemplate();

            try

            {

                PARTPasswordBox = Template.FindName(PART_PasswordBox, thisas PasswordBox;

                PARTPasswordBox.PasswordChanged -= PARTPasswordBox_PasswordChanged;

                PARTPasswordBox.PasswordChanged += PARTPasswordBox_PasswordChanged;

                PARTTextBox = Template.FindName(PART_TextBox, thisas TextBox;

                PARTTextBox.TextChanged -= PARTTextBox_TextChanged;

                PARTTextBox.TextChanged += PARTTextBox_TextChanged;

            }

            catch (Exception ex)

            {

            }

        }

        private void PARTTextBox_TextChanged(object sender, TextChangedEventArgs e)

        {

            if (IsPasswordVisible)

            {

                PARTPasswordBox.Password = PARTTextBox.Text;

            }

            Password = PARTTextBox.Text;

        }

        private void PARTPasswordBox_PasswordChanged(object sender, RoutedEventArgs e)

        {

            Password = PARTPasswordBox.Password;

        }

        #endregion

    }

}

控件样式
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

<local:BooleanToVisibilityConverter x:Key="InversedBooleanToVisibilityConverter" IsInversed="True"/>

<sys:String x:Key="LockIcon">M11.2668 6.4V4.26667C11.2668 1.93333 9.33343 0 7.0001 0C4.66676 0 2.73343 1.93333 2.73343 4.26667V6.4H0.600098V16H13.4001V6.4H11.2668ZM3.8001 4.26667C3.8001 2.46667 5.2001 1.06667 7.0001 1.06667C8.8001 1.06667 10.2001 2.46667 10.2001 4.26667V6.4H3.8001V4.26667ZM12.3334 7.46667V11.7333H1.66676V7.46667H12.3334ZM1.66676 14.9333V12.8H12.3334V14.9333H1.66676Z

<sys:String x:Key="HidePasswordIcon">M15.1657 6.0505C15.3195 5.82104 15.2666 5.5159 15.0648 5.33685C14.8354 5.15782 14.5302 5.20825 14.3512 5.43772C14.326 5.46293 11.4966 8.8017 8.13263 8.8017C4.86953 8.8017 1.91407 5.43772 1.88885 5.4125C1.70982 5.20823 1.37947 5.18303 1.17522 5.36207C0.97095 5.54112 0.945752 5.87145 1.12479 6.07572C1.17522 6.15137 1.78799 6.8398 2.75634 7.60388L1.45513 8.95552C1.25087 9.15978 1.27606 9.49012 1.48033 9.66917C1.53077 9.77003 1.65938 9.82298 1.78547 9.82298C1.91407 9.82298 2.04017 9.77255 2.14355 9.66917L3.54562 8.21665C4.20883 8.6756 4.99813 9.10933 5.8656 9.41447L5.331 11.2251C5.25535 11.505 5.40665 11.7849 5.68909 11.8631H5.84291C6.07237 11.8631 6.27664 11.7092 6.32707 11.4798L6.86169 9.66917C7.27021 9.74482 7.70394 9.79777 8.13515 9.79777C8.56889 9.79777 9.00262 9.74734 9.40862 9.66917L9.94322 11.4545C9.99365 11.684 10.2231 11.8378 10.4274 11.8378C10.4778 11.8378 10.5283 11.8378 10.556 11.8126C10.8359 11.737 10.9897 11.4545 10.9141 11.1746L10.3719 9.38925C11.2394 9.08412 12.0287 8.65038 12.6919 8.19143L14.0687 9.61873C14.1696 9.7196 14.2982 9.77255 14.4268 9.77255C14.5554 9.77255 14.6815 9.72212 14.7849 9.61873C14.9892 9.41447 14.9892 9.10933 14.8101 8.90508L13.5114 7.55345C14.5529 6.78937 15.1657 6.05048 15.1657 6.05048V6.0505Z

<sys:String x:Key="ShowPasswordIcon">M8.01681 3.91217C11.2069 3.91217 13.9167 6.06444 15.2487 7.34645C15.5671 7.65338 15.7501 8.09132 15.7501 8.54611C15.7501 9.00089 15.5671 9.43883 15.2487 9.74577C13.9167 11.0278 11.2069 13.18 8.01681 13.18C4.82494 13.18 2.11168 11.024 0.779687 9.74015C0.461204 9.43509 0.279968 8.99902 0.279968 8.54611C0.279968 8.09319 0.462964 7.65713 0.779687 7.35206C2.11168 6.06819 4.82318 3.91217 8.01681 3.91217ZM8.01681 11.9448C10.818 11.9448 13.2621 9.99468 14.4692 8.83058C14.573 8.73139 14.5888 8.60974 14.5888 8.54611C14.5888 8.48247 14.573 8.36083 14.4692 8.26163C13.2603 7.09941 10.8163 5.14739 8.01681 5.14739C5.21205 5.14739 2.768 7.10128 1.55918 8.26725C1.45712 8.36457 1.44129 8.48435 1.44129 8.54611C1.44129 8.60787 1.45712 8.72578 1.55918 8.82497C2.768 9.99094 5.21381 11.9448 8.01681 11.9448ZM5.95087 8.54655C5.95087 7.40748 6.87743 6.48248 8.01493 6.48248C9.15399 6.48248 10.079 7.40592 10.079 8.54498C10.079 9.68405 9.15243 10.609 8.01493 10.609C6.87743 10.609 5.95087 9.68561 5.95087 8.54655ZM6.98368 8.54655C6.98368 9.1153 7.44618 9.5778 8.01493 9.5778C8.58368 9.5778 9.04618 9.1153 9.04618 8.54655C9.04618 7.9778 8.58368 7.5153 8.01493 7.5153C7.44618 7.5153 6.98368 7.9778 6.98368 8.54655Z

<Style x:Key="CommonPasswordBoxWithToggleStyle"

       TargetType="{x:Type local:CommonPasswordBoxWithToggle}">

    <Setter Property="ShowPasswordIcon" Value="{DynamicResource ShowPasswordIcon}"/>

    <Setter Property="HidePasswordIcon" Value="{DynamicResource HidePasswordIcon}"/>

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="{x:Type local:CommonPasswordBoxWithToggle}">

                <Grid>

                    <Border x:Name="PART_Border"

                            Background="White" 

                            BorderBrush="#FFABADB3"

                            BorderThickness="1">

                        <Grid>

                            <Grid.ColumnDefinitions>

                                <ColumnDefinition Width="12"/>

                                <ColumnDefinition Width="auto"/>

                                <ColumnDefinition Width="*"/>

                                <ColumnDefinition Width="auto"/>

                            

                            

                            <Path Grid.Column="1" 

                                  x:Name="PathUC"

                                  Height="16"

                                  Width="16"

                                  HorizontalAlignment="Center"

                                  VerticalAlignment="Center"

                                  Data="{Binding LeftIconButtonContent, RelativeSource={RelativeSource Mode=TemplatedParent}}"

                                  Fill="{TemplateBinding Foreground}"

                                  Stretch="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=IconStretch}" 

                                  Margin="0 0 6 0"/>

                            

                            <Border Grid.Column="2"

                                    Name="PART_WaterMark"

                                    Panel.ZIndex="100"

                                    IsHitTestVisible="False"

                                    BorderBrush="{TemplateBinding BorderBrush}"

                                    Opacity="0">

                                <Border.Background>

                                    <VisualBrush AlignmentX="Left"

                                                 Stretch="None">

                                        <VisualBrush.Visual>

                                            <TextBlock Text="{TemplateBinding WaterText}" 

                                                       FontSize="14"

                                                       Foreground="{DynamicResource FontSecondaryBodyColor}"/>

                                        

                                    

                                

                            

                            

                            <PasswordBox Grid.Column="2" 

                                         x:Name="PART_PasswordBox"

                                         Visibility="{Binding IsPasswordVisible,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource InversedBooleanToVisibilityConverter}}"

                                         PasswordChar="●"

                                         VerticalAlignment="Center"

                                         VerticalContentAlignment="Center"

                                         BorderThickness="0"

                                         FontSize="12"/>

                            

                            <TextBox Grid.Column="2" 

                                     x:Name="PART_TextBox" 

                                     Visibility="{Binding IsPasswordVisible, RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibilityConverter}}"

                                     Text="{Binding Password, RelativeSource={RelativeSource TemplatedParent},UpdateSourceTrigger=PropertyChanged}"

                                     VerticalAlignment="Center"

                                     VerticalContentAlignment="Center"

                                     BorderThickness="0"

                                     FontSize="12"/>

                            

                            <ToggleButton Grid.Column="3"

                                          Margin="5,0"

                                          IsChecked="{Binding IsPasswordVisible,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"

                                          Width="16"

                                          Height="16">

                                <ToggleButton.Style>

                                    <Style TargetType="ToggleButton">

                                        <Setter Property="Template">

                                            <Setter.Value>

                                                <ControlTemplate TargetType="ToggleButton">

                                                    <Border Background="Transparent">

                                                        <Path x:Name="EyeIcon"

                                                              Data="{Binding HidePasswordIcon,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:CommonPasswordBoxWithToggle}}"

                                                              Fill="#666"

                                                              Stretch="Uniform"/>

                                                    

                                                    <ControlTemplate.Triggers>

                                                        <Trigger Property="IsChecked" 

                                                         Value="True">

                                                            <Setter TargetName="EyeIcon" 

                                                                    Property="Data"

                                                                    Value="{Binding ShowPasswordIcon,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:CommonPasswordBoxWithToggle}}"/>

                                                        

                                                    

                                                

                                            

                                        

                                    

                                

                            

                        

                    

                

                <ControlTemplate.Triggers>

                    <Trigger Property="Password" Value="">

                        <Setter TargetName="PART_WaterMark" Property="Opacity" Value="1"/>

                    

                    <Trigger Property="Password" Value="{x:Null}">

                        <Setter TargetName="PART_WaterMark" Property="Opacity" Value="1"/>

                    

                    <Trigger Property="IsMouseOver" Value="True">

                        <Setter TargetName="PART_Border" Property="BorderBrush"

                        Value="LightBlue"/>

                    

                    <Trigger Property="IsFocused" Value="True">

                        <Setter TargetName="PART_Border" Property="BorderBrush"

                        Value="LightBlue"/>

                    

                

            

        

    

调用控件
<local:CommonPasswordBoxWithToggle Style="{DynamicResource CommonPasswordBoxWithToggleStyle}"

        WaterText="请输入密码"

        Password="{Binding YourPassword,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"

        LeftIconButtonVisibility="Visible"

        LeftIconButtonContent="{DynamicResource LockIcon}"

        Width="300"

        Height="34"/>

控件效果
总结
通过本项目所实现的自定义WPF密码框控件,我们解决了标准 
PasswordBox
 控件在实际应用中的局限性。该控件不仅支持双向数据绑定,使得MVVM模式下的开发更加顺畅,还允许用户根据需要自由切换密码的显示与隐藏状态,极大地提升了用户体验。另外,简洁的设计和灵活的配置选项使得该控件易于集成到现有项目中,帮助大家快速构开发既美观又实用的用户界面。
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
作者:苏秦与真相
出处:cnblogs.com/JqkAman/p/18755005
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!

END

觉得有收获?不妨分享让更多人受益
关注「DotNet技术匠」,共同提升技术实力

收藏
点赞
分享
在看

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码