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

    }
相关推荐
Scout-leaf4 天前
WPF新手村教程(三)—— 路由事件
c#·wpf
阿珊和她的猫6 天前
深入理解与使用 Cookie:Web 开发中的关键机制
前端·状态模式
阿珊和她的猫6 天前
实现网页锚点功能的技术指南
前端·javascript·vue.js·状态模式
柒.梧.6 天前
基于SpringBoot+JWT 实现Token登录认证与登录人信息查询
wpf
驴儿响叮当20106 天前
设计模式之状态模式
设计模式·状态模式
小王不爱笑1327 天前
LangChain4j 项目实战--4:硅谷小智(实现流式输出)
状态模式
茶本无香7 天前
设计模式之十六:状态模式(State Pattern)详解 -优雅地管理对象状态,告别繁琐的条件判断
java·设计模式·状态模式
木斯佳8 天前
前端八股文面经大全:字节跳动前端一面(2025-10-09)·面经深度解析
前端·状态模式
十月南城9 天前
Flink实时计算心智模型——流、窗口、水位线、状态与Checkpoint的协作
大数据·flink·wpf
山北雨夜漫步10 天前
点评Day06 剩下的卡拉米,我不都写,只写一些新奇的
状态模式