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;
相关推荐
玉面小君17 小时前
从 WPF 到 Avalonia 的迁移系列实战篇4:控件模板与 TemplatedControl
wpf
何双新1 天前
第 2 讲:Kafka Topic 与 Partition 基础
kafka·wpf·linq
我要打打代码1 天前
WPF依赖属性和依赖属性的包装器:
wpf
cplmlm2 天前
WPF+IOC学习记录
c#·wpf
c#上位机2 天前
wpf之Canvas
c#·wpf
c#上位机2 天前
wpf之样式
c#·wpf
玉面小君2 天前
从 WPF 到 Avalonia 的迁移系列实战篇2:路由事件的异同点与迁移技巧
wpf·avalonia
c#上位机2 天前
wpf之WrapPanel
c#·wpf
c#上位机2 天前
wpf之StackPanel
c#·wpf