使用附加属性 实现wpf中的passwordBox 的明文/密文密码切换

csharp 复制代码
    public static class LoginPasswordBoxHelper
    {
        private static bool _isUpdatingPassword = false;

        public static string GetPassword(DependencyObject obj)
        {
            return (string)obj.GetValue(PasswordProperty);
        }

        public static void SetPassword(DependencyObject obj, string value)
        {
            obj.SetValue(PasswordProperty, value);
        }

        public static readonly DependencyProperty PasswordProperty =
            DependencyProperty.RegisterAttached("Password", typeof(string), typeof(LoginPasswordBoxHelper),
                new PropertyMetadata(string.Empty, OnPasswordPropertyChanged));

        public static bool GetIsPasswordBindingEnable(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsPasswordBindingEnableProperty);
        }

        public static void SetIsPasswordBindingEnable(DependencyObject obj, bool value)
        {
            obj.SetValue(IsPasswordBindingEnableProperty, value);
        }

        public static readonly DependencyProperty IsPasswordBindingEnableProperty =
            DependencyProperty.RegisterAttached("IsPasswordBindingEnable", typeof(bool), typeof(LoginPasswordBoxHelper),
                new FrameworkPropertyMetadata(OnIsPasswordBindingEnabledChanged));

        private static void OnIsPasswordBindingEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj is PasswordBox passwordBox)
            {
                passwordBox.PasswordChanged -= PasswordBoxPasswordChanged;
                if ((bool)e.NewValue)
                {
                    passwordBox.PasswordChanged += PasswordBoxPasswordChanged;
                    // Initialize PasswordProperty value to PasswordBox's current password
                    SetPassword(passwordBox, passwordBox.Password);
                }
            }
        }

        private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is PasswordBox passwordBox)
            {
                passwordBox.PasswordChanged -= PasswordBoxPasswordChanged;
                if (!_isUpdatingPassword && passwordBox.Password != (string)e.NewValue)
                {
                    passwordBox.Password = (string)e.NewValue ?? string.Empty;
                }
                passwordBox.PasswordChanged += PasswordBoxPasswordChanged;
            }
        }

        private static void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
        {
            if (sender is PasswordBox passwordBox)
            {
                _isUpdatingPassword = true;
                if (GetPassword(passwordBox) != passwordBox.Password)
                {
                    SetPassword(passwordBox, passwordBox.Password);
                }
                _isUpdatingPassword = false;
            }
        }
    }
csharp 复制代码
    public class BoolToContentConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is bool  b && b)
            {
                return "显示密码";
            }
            else
            {
                return "隐藏密码";
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return new object();
        }
    }

前端代码

html 复制代码
    <Window.Resources>
        <cvt:BoolToContentConverter x:Key="btcc" />
    </Window.Resources>

        <StackPanel
            Grid.Row="2"
            HorizontalAlignment="Center"
            Orientation="Horizontal">
            <Grid>
                <TextBox
                    x:Name="txtBox2"
                    Width="200"
                    Height="35"
                    Margin="0,50,0,0"
                    VerticalContentAlignment="Center"
                    Text="{Binding Pwd, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                    Visibility="{Binding TxtVis}" />

                <PasswordBox
                    x:Name="passTxt2"
                    Width="200"
                    Height="35"
                    Margin="0,50,0,0"
                    VerticalContentAlignment="Center"
                    deu:LoginPasswordBoxHelper.IsPasswordBindingEnable="True"
                    deu:LoginPasswordBoxHelper.Password="{Binding Pwd, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                    Visibility="{Binding PwdVis}" />
            </Grid>

            <ToggleButton
                Height="35"
                Margin="20,50,0,0"
                Command="{Binding TBtnCmdCommand}"
                CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsChecked}"
                Content="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsChecked, Converter={StaticResource btcc}}"
                Style="{DynamicResource ToggleButtonSuccess}" />
        </StackPanel>

ViewModel:

csharp 复制代码
    public partial class MainViewModel:ObservableObject
    {
        [ObservableProperty]
        private string pwd = string.Empty;

        [ObservableProperty]
        private Visibility pwdVis = Visibility.Visible;

        [ObservableProperty]
        private Visibility txtVis = Visibility.Hidden;

        [RelayCommand]
        public void TBtnCmd(bool isChecked)
        {
            if (isChecked)
            {
                TxtVis = Visibility.Visible;
                PwdVis = Visibility.Hidden;
            }
            else
            {
                TxtVis = Visibility.Hidden;
                PwdVis = Visibility.Visible;
            }
        }

    }
相关推荐
暮雪倾风13 小时前
【WPF】使用Costura.Fody将工程打包为单个EXE文件
wpf·exe·windows原生开发
咖啡の猫15 小时前
Jedis快速入门
wpf
Scout-leaf18 小时前
WPF新手村教程(五)— 附魔教学(绑定)
c#·wpf
阿珊和她的猫19 小时前
单例模式:确保唯一性与全局访问的设计方案
单例模式·状态模式
刘一说21 小时前
拒绝 500 与 404:Spring Boot 全局异常处理机制深度解析与常见 API 错误避坑指南
spring boot·后端·状态模式
SuperEugene21 小时前
前端基础实战:JS/TS与Vue体系化扫盲(47 篇完整目录 + 避坑)
javascript·vue.js·前端框架·npm·ecmascript·状态模式
数据知道2 天前
MongoDB灾难恢复计划:RTO/RPO目标下的应急响应完整方案
数据库·mongodb·wpf
蜜獾云2 天前
设计模式之状态模式:封装数据的状态流转逻辑
设计模式·状态模式
前端不太难2 天前
OpenClaw 源码架构解析
架构·状态模式
闻哥3 天前
深入剖析Redis数据类型与底层数据结构
java·jvm·数据结构·spring boot·redis·面试·wpf