Processing math: 100%

最近学习WPF,突然想做PasswordBox明文显示的样式,在网上搜索了一下,代码都有问题,不能够直接复用。所以,在同事的帮助下,做了一个明文显示样式的Demo。

 

首先,创建一个WPF App的项目。

打开MainWindow.xaml文件,代码如下:

<Window x:Class="WpfApp4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp4"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
    </Grid>
</Window>

构建Grid布局,并创建两个控件,分别为TextBox、PasswordBox,代码如下:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <TextBox x:Name="userName" Grid.Row="0" Width="200" Height="40" HorizontalAlignment="Left"></TextBox>
    <PasswordBox x:Name="userPwd" Grid.Row="1" Width="200" Height="40" HorizontalAlignment="Left" Style="{StaticResource PasswordBoxStyle1}" FontSize="20" VerticalAlignment="Center" local:ControlAttachProperty.PlaceHolder="请输入密码" />
</Grid>

此时,Style="{StaticResource PasswordBoxStyle1}" 与 local:ControlAttachProperty.PlaceHolder="请输入密码" 会报错。(现在可以删掉这两句)

 

现在要实现的样式效果:

1、输入密码后,点击眼睛按钮可以显示密码明文效果。

2、密码框为空且没有获取焦点时,显示提示文字。

3、密码为空时,不允许点击眼睛按钮

样式代码需要放在Window标签下Grid标签前,代码如下:

<Window.Resources>
        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!--眼睛按钮的样式-->
        <Style TargetType="Button" x:Key="EyeButton">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border Background="{TemplateBinding Background}" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!--PassWordBox样式-->
        <SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
        <SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
        <SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
        <Style x:Key="PasswordBoxStyle1" TargetType="{x:Type PasswordBox}">
            <Setter Property="local:PasswordBoxHelper.Attach" Value="True"/>
            <Setter Property="PasswordChar" Value="●"/>
            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
            <Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
            <Setter Property="HorizontalContentAlignment" Value="Left"/>
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="AllowDrop" Value="true"/>
            <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
            <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type PasswordBox}">
                        <Border x:Name="border" CornerRadius="10" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                            <!--重写构造PasswordBox-->
                            <Grid x:Name="PART_InnerGrid">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <!--PasswordBox原有的显示节点-->
                                <ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" IsTabStop="False" VerticalAlignment="Stretch" Background="{x:Null}" VerticalContentAlignment="Center" Margin="5,5"/>
                                <!--创建明文显示的TextBox-->
                                <TextBox x:Name="PART_PasswordShower"  BorderBrush="Transparent" Text="{Binding Path=(local:PasswordBoxHelper.Password),RelativeSource={RelativeSource TemplatedParent}}" BorderThickness="0" Visibility="Collapsed" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,5"/>
                                <!--创建提示字符-->
                                <TextBlock x:Name="PART_PlaceHolder" Text="{Binding Path=(local:ControlAttachProperty.PlaceHolder),RelativeSource={RelativeSource TemplatedParent}}"  Visibility="Collapsed" Opacity="0.6" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5,5"/>
                                <!--触发按钮显示样式-->
                                <Button x:Name="PART_ToggleEye" Grid.Column="1" Width="40"  Margin="3,3" BorderThickness="0" Style="{StaticResource EyeButton}" >
                                    <Button.Background>
                                        <ImageBrush x:Name="img_eye" ImageSource="eye_slash.png"/>
                                    </Button.Background>
                                </Button>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Opacity" TargetName="border" Value="0.56"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
                            </Trigger>
                            <Trigger Property="IsKeyboardFocused" Value="true">
                                <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
                            </Trigger>
                            <!--密码框为空设置按钮禁用-->
                            <Trigger Property="local:PasswordBoxHelper.Password"  Value="">
                                <Setter TargetName="PART_ToggleEye" Property="IsEnabled" Value="False"/>
                            </Trigger>
                            <!--按住按钮,更改按钮背景图片并设置明文框显示且密码框不显示且不占用-->
                            <Trigger Property="IsPressed" SourceName="PART_ToggleEye" Value="true">
                                <Setter TargetName="PART_ToggleEye" Property="Background">
                                    <Setter.Value>
                                        <ImageBrush ImageSource="eye.png"/>
                                    </Setter.Value>
                                </Setter>
                                <Setter TargetName="PART_ContentHost" Property="Visibility" Value="Collapsed"/>
                                <Setter TargetName="PART_PasswordShower" Property="Visibility" Value="Visible"/>
                            </Trigger>
                            <!--密码框为空不且没有获取焦点时,设置提示文字显示-->
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="local:PasswordBoxHelper.Password"  Value=""/>
                                    <Condition Property="IsFocused" Value="False"/>
                                </MultiTrigger.Conditions>
                                <Setter TargetName="PART_PlaceHolder" Property="Visibility" Value="Visible"/>
                            </MultiTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
                        <Condition Property="IsSelectionActive" Value="false"/>
                    </MultiTrigger.Conditions>
                    <Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                </MultiTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

代码中使用了PasswordBoxHelper及ControlAttachProperty的类,PasswordBoxHelper用于获取PasswordwordBox的密码,提供给显示框显示明文密码。ControlAttachProperty用于创建提示文字的依赖属性。(注意:两个类放在MainWindow.xaml同级目录中)

 

PasswordBoxHelper代码如下:

public 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)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            passwordBox.PasswordChanged -= PasswordChanged;
            if (!(bool)GetIsUpdating(passwordBox))
            {
                passwordBox.Password = (string)e.NewValue;
            }
            passwordBox.PasswordChanged += PasswordChanged;
        }
        private static void Attach(DependencyObject sender,
            DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            if (passwordBox == null)
                return;
            if ((bool)e.OldValue)
            {
                passwordBox.PasswordChanged -= PasswordChanged;
            }
            if ((bool)e.NewValue)
            {
                passwordBox.PasswordChanged += PasswordChanged;
            }
        }
        private static void PasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            SetIsUpdating(passwordBox, true);
            SetPassword(passwordBox, passwordBox.Password);
            SetIsUpdating(passwordBox, false);
        }
    }

 

ControlAttachProperty代码如下:

public class ControlAttachProperty
    {
        public static string GetPlaceHolder(DependencyObject obj)
        {
            return (string)obj.GetValue(PlaceHolderProperty);
        }

        public static void SetPlaceHolder(DependencyObject obj, string value)
        {
            obj.SetValue(PlaceHolderProperty, value);
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PlaceHolderProperty =
            DependencyProperty.RegisterAttached("PlaceHolder", typeof(string), typeof(ControlAttachProperty), new PropertyMetadata(string.Empty));
    }

 

现在,需要把之前删掉的两句(Style="{StaticResource PasswordBoxStyle1}" 与 local:ControlAttachProperty.PlaceHolder="请输入密码" )加进来。 Style是设置PasswordBox的样式, 在样式里可以重构PasswordBox。local:ControlAttachProperty.PlaceHolder是为passwordbox新增的依赖属性。

运行代码即可获取实现的效果。

需要注意的是:

①代码中用了两个图片,分别时eye.png与eye_slash.png, 在写Demo的时候,是直接放在MainWindow.xaml同级文件夹里。

②xmlns:local="clr-namespace:WpfApp4" , 这里是创建wpf项目的命名空间,喜欢复制代码的兄弟,记得更改为当前创建项目的命名空间。

代码下载:密码明文显示/隐藏

posted @ 2021-03-26 17:07 Anna•兮月 阅读(3474) 评论(1) 推荐(4) 编辑
摘要: 这是我第二次安装SVN了,上次是在MyEclipse上安装SVN,好像是因为版本的问题,一直都安装不上去,花了很长时间安装上去了,最后系统被我弄崩溃了!过了段时间后,我在安装SVN,却只记得需要把subclipse.tigris上下载svn的插件,要把插件丢在IDE的安装目录下。具体操作却忘记了。所... 阅读全文
posted @ 2013-02-05 15:47 Anna•兮月 阅读(318) 评论(0) 推荐(0) 编辑
摘要: 软件开发总会有 BUG 和更新的需求,之前每次更新都是将整项目打包为不同的文件名来记录,但项目多了之后管理也是个很麻烦的问题,所以第一次引入了源代码版本控制工具,就用 VC6 自带的 VSS,用起来感觉还不错,很容易上手。装完 VSS,按软件的默认置,服务端管理数据库中的名字为 Admin,配置里默... 阅读全文
posted @ 2012-01-05 21:14 Anna•兮月 阅读(419) 评论(2) 推荐(1) 编辑
摘要: 第一种方法:通过URL链接地址传递Request.QueryStringsend.aspx: protected void Button1_Click(object sender, EventArgs e) { Request.Redirect("Default2.aspx?username=honge"); } receive.aspx:string username = Request.QueryString["username"];这样可以得到参数值。第二种方法:通过post方式Request。send.aspx<form id=" 阅读全文
posted @ 2011-06-27 12:00 Anna•兮月 阅读(191) 评论(0) 推荐(0) 编辑
摘要: API技巧全集API技巧集(一)一、拖动无标题窗体:包含头文件:#include #@60;winuser.h#@62;在窗体或组件的 OnMouseDown 事件中加入以下代码:if(Button == mbLeft){ReleaseCapture();SendMessage( Handle,... 阅读全文
posted @ 2011-06-24 11:59 Anna•兮月 阅读(457) 评论(0) 推荐(1) 编辑
摘要: 方法很简单public string GetMoney(double dd) { string s = dd.ToString("#L#E#D#C#K#E#D#C#J#E#D#C#I#E#D#C#H#E#D#C#G#E#D#C#F#E#D#C#.0B0A"); string d = Regex.Re... 阅读全文
posted @ 2011-06-15 10:55 Anna•兮月 阅读(236) 评论(0) 推荐(0) 编辑
摘要: 如何在Visual Studio.net中让同一解决方案中包含多个不同类型的项目1.通过“文件”-->“新建”-->“空白解决方案”建立一个新的解决方案MySolution1。2.添加项目 “解决方案资源管理器”中,在“解决方案MySolution1”上右键,添加新项,选择“asp.net Web应... 阅读全文
posted @ 2011-06-15 10:25 Anna•兮月 阅读(749) 评论(0) 推荐(0) 编辑
摘要: 最近做一个网站,什么资料素材都没有~。所以前台设计和效果都要一人包办。这几天做了几个效果,其中就有鼠标滑过图片显示大图的一个效果。虽然网上有很多这样的案例,但是还是决定把这个效果作为博文发表出来。会做的,大家路过看一下,不会的可以参考参考。View Code 1 2 3 4 5 图片效果 ... 阅读全文
posted @ 2011-04-13 17:15 Anna•兮月 阅读(386) 评论(5) 推荐(1) 编辑
摘要: 公司一个新同事,做上传下载的功能。他在网上copy了一段代码。其中有这样一个upload.ashx的文件。他需要在这个文件里获取Session["key"]的值,不论怎么写都会报“未将对象引用实例”。这个时候大家会想难道Session["key"]里面没有赋值?但是,Session["key"]调试的时候的确赋过值。那是不是没有实例化?怎么在Handler里面实例化Session呢?大家都知道Session是一个作用域,用来保存状态的。所以在Handler里面一定要引用一个命名空间。“using System.Web.SessionS 阅读全文
posted @ 2011-04-08 17:29 Anna•兮月 阅读(1400) 评论(2) 推荐(2) 编辑
点击右上角即可分享
微信分享提示