wpf 自定义密码文本框,并且可以双向绑定

复制代码
<UserControl x:Class="项目.UcPassword"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:YouMin_MicroplateReader"
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:keyboard="clr-namespace:Hs.KeyBoard.WPF.Behavior;assembly=Hs.KeyBoard.WPF" >
    <UserControl.Resources>
        <Style TargetType="CheckBox" x:Key="CheckBoxStyle">
            <Setter Property="HorizontalAlignment" Value="Right"></Setter>
            <Setter Property="VerticalAlignment" Value="Center"></Setter>
            <Setter Property="Margin" Value="0 0 5 0"></Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="CheckBox">
                        <Image Margin="0 0 5 0" Height="30" Width="30" Stretch="Fill" x:Name="Img" 
                               Source="pack://application:,,,/项目名称;component/Images/GrayWhite.png"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="CheckBox" x:Key="LookStyle">
            <Setter Property="HorizontalAlignment" Value="Right"></Setter>
            <Setter Property="VerticalAlignment" Value="Center"></Setter>
            <Setter Property="Margin" Value="0 0 5 0"></Setter>
            <Setter Property="Cursor" Value="Hand" />
            <Setter Property="IsChecked" Value="False" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type CheckBox}">
                        <Image Margin="0 0 5 0" Height="50" Width="55" Stretch="Fill" x:Name="Img"/>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Opacity" Value="0.6"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="Img" Property="Source" Value="pack://application:,,,/项目名称;component/Images/Look.png" />
                            </Trigger>
                            <Trigger Property="IsChecked" Value="False">
                                <Setter TargetName="Img" Property="Source" Value="pack://application:,,,/项目名称;component/Images/UnLook.png" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Border Background="#F3FAFF" BorderBrush="#FFFFFF" BorderThickness="3" Height="56" Width="500" >
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBox Background="Transparent" BorderThickness="0" VerticalContentAlignment="Center" Padding="5,0,0,0"
                     Visibility="{Binding TbVisibility,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Mode=TwoWay}" 
                     Text="{Binding Password,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
                <i:Interaction.Behaviors>
                    <keyboard:KeyboardBehavior />
                </i:Interaction.Behaviors>
            </TextBox>
            <PasswordBox Background="Transparent" BorderThickness="0" local:PasswordBoxHelper.Attach="True" Padding="5,0,0,0" VerticalContentAlignment="Center"
                          Visibility="{Binding PwVisibility,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Mode=TwoWay}" 
                          local:PasswordBoxHelper.Password="{Binding Password,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                         InputMethod.IsInputMethodEnabled="False">
                <i:Interaction.Behaviors>
                    <keyboard:KeyboardBehavior />
                </i:Interaction.Behaviors>
            </PasswordBox>
            <CheckBox Grid.Column="1" Style="{StaticResource CheckBoxStyle}"  Panel.ZIndex="999"
                                       IsChecked="{Binding IsCleared,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Mode=TwoWay}" 
                                       Visibility ="{Binding ClearVisibility,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Mode=TwoWay}"/>
            <CheckBox Grid.Column="2" Style="{StaticResource LookStyle}"  Panel.ZIndex="999"
                                       IsChecked="{Binding IsChecked,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Mode=TwoWay}">
            </CheckBox>
        </Grid>
    </Border>
</UserControl>

PasswordBoxHelper.cs

复制代码
using System;
using System.Windows;
using System.Windows.Controls;

namespace 项目名称
{
    public static class PasswordBoxHelper
    {
        public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordBoxHelper), new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));
        public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached("Attach", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, Attach));
        private static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), typeof(PasswordBoxHelper));

        public static void SetAttach(DependencyObject dp, bool value)
        {
            dp.SetValue(AttachProperty, value);
        }
        public static bool GetAttach(DependencyObject dp)
        {
            return (bool)dp.GetValue(AttachProperty);
        }
        public static string GetPassword(DependencyObject dp)
        {
            return (string)dp.GetValue(PasswordProperty);
        }
        public static void SetPassword(DependencyObject dp, string value)
        {
            dp.SetValue(PasswordProperty, value);
        }
        private static bool GetIsUpdating(DependencyObject dp)
        {
            return (bool)dp.GetValue(IsUpdatingProperty);
        }
        private static void SetIsUpdating(DependencyObject dp, bool value)
        {
            dp.SetValue(IsUpdatingProperty, value);
        }
        private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender is not PasswordBox passwordBox || passwordBox == null) { return; }
            try
            {
                passwordBox.PasswordChanged -= PasswordChanged;
                if (!(bool)GetIsUpdating(passwordBox))
                {
                    passwordBox.Password = (string)e.NewValue;
                }
                passwordBox.PasswordChanged += PasswordChanged;
            }
            catch (Exception ex)
            {
                LogHelper.GetSingleObj().WriteLog(ex);
            }
        }
        private static void Attach(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender is not PasswordBox passwordBox || passwordBox == null) { return; }
            try
            {
                if ((bool)e.OldValue)
                {
                    passwordBox.PasswordChanged -= PasswordChanged;
                }
                if ((bool)e.NewValue)
                {
                    passwordBox.PasswordChanged += PasswordChanged;
                }
            }
            catch (Exception ex)
            {
                LogHelper.GetSingleObj().WriteLog(ex);
            }
        }

        private static void PasswordChanged(object sender, RoutedEventArgs e)
        {
            if (sender is not PasswordBox passwordBox || passwordBox == null) { return; }
            try
            {
                SetIsUpdating(passwordBox, true);
                SetPassword(passwordBox, passwordBox.Password);
                SetIsUpdating(passwordBox, false);
            }
            catch (Exception ex)
            {
                LogHelper.GetSingleObj().WriteLog(ex);
            }
        }
    }
}

调用

cs 复制代码
 xmlns:local="clr-namespace:项目名"           

<local:UcPassword Password="{Binding Password,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Row="2" Grid.Column="1" Panel.ZIndex="1" HorizontalAlignment="Left" Width="500" Height="56" />

ViewModel

cs 复制代码
  /// <summary>
        /// 密码
        /// </summary>
        [ObservableProperty]
        string _Password = string.Empty;
相关推荐
旋生万物9 小时前
【终极实战】用Python从零“生成“一个宇宙:螺旋干涉模型的代码实现
开发语言·前端·人工智能·react.js·php·wpf
Now喔14 小时前
WPF画刷介绍
wpf
李高钢20 小时前
WPF/WinForms 客户端通过 gRPC 与后端通信:从 Proto 契约到流式调用的完整指南
wpf·grpc·winforms
一见已难忘2 天前
基于 Harmony 6.0 应用的宠物寄养预约系统实现
wpf·宠物
fl1768312 天前
基于C#WPF实现的内存加速球清理类似360加速球内存清理
开发语言·c#·wpf
李高钢2 天前
【WPF】高级 UI 与性能优化实战:从卡顿到丝滑
ui·性能优化·wpf
Chris _data2 天前
WPF 上位机开发学习笔记 - 第四天
笔记·学习·wpf
李高钢2 天前
除了 IDE,C#/WPF 开发者每天离不开的 10 个工具
ide·c#·wpf
李高钢3 天前
用 JetBrains Rider 写 WPF 的 15 个高效技巧:从 VS 转过来也值得看
wpf
李高钢4 天前
【WPF】MVVM 与数据绑定实战:从原理到完整项目
wpf