使用附加属性 实现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;
            }
        }

    }
相关推荐
未若君雅裁4 小时前
Spring Statemachine 实战入门:从零实现一个订单状态流转 Demo
java·spring·状态模式
前端不太难18 小时前
从失败到 87.5%:OpenClaw 的任务进化
状态模式·openclaw
前端不太难1 天前
鸿蒙PC和App:都在走向 System
华为·状态模式·harmonyos
heimeiyingwang2 天前
【架构实战】状态机架构:订单/工单状态流转设计
观察者模式·架构·wpf
必胜刻2 天前
全面解析 Token:从入门到 JWT 实战
golang·状态模式·web·前后端交互
木斯佳2 天前
前端八股文面经大全:腾讯前端实习二、三OC面(2026-04-27)·面经深度解析
前端·状态模式
KmSH8umpK3 天前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第三篇
redis·分布式·wpf
KmSH8umpK3 天前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案
redis·分布式·wpf
武藤一雄3 天前
WPF:MessageBox系统消息框
前端·microsoft·c#·.net·wpf
武藤一雄3 天前
WPF进阶:万字详解WPF如何性能优化
windows·性能优化·c#·.net·wpf·.netcore·鲁棒性