WPF自定义控件之水印文本(密码)框
首先来讲讲创建这个控件的初衷,一个让我很郁闷的问题。
公司的客户端项目采用WPF+MVVM技术实现,在近期地推客户端的过程中遇到了一个很奇葩的问题:在登录界面点击密码框就会直接闪退,没有任何提示
密码框是WPF原生的PasswordBox,这似乎没有什么不对。出现这个情况的一般是在xp系统(ghost的雨林木风版本或番茄花园),某些xp系统又不会出现。
出现这个问题的原因是因为客户的系统缺少PasswordBox使用的某种默认的字体,网上有人说是times new roman,又或者其它某种字体。其实只要找到了这个字体,并在程序启动的时候安装这种字体可以解决。
但我觉得,这个解决方案太麻烦。与其依赖PasswordBox使用的默认字体,不如重写PasswordBox,避免密码框字体的依赖。
现在让我们来重写一个自己的带水印的文本(密码)框吧
1.首先创建一个类,继承TextBox
public class SJTextBox : TextBox
2.指定依赖属性的实例重写基类型的元数据
static SJTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SJTextBox), new FrameworkPropertyMetadata(typeof(SJTextBox)));
}
3.定义依赖属性
public static DependencyProperty WaterRemarkProperty =
DependencyProperty.Register("WaterRemark", typeof(string), typeof(SJTextBox)); /// <summary>
/// 水印文字
/// </summary>
public string WaterRemark
{
get { return GetValue(WaterRemarkProperty).ToString(); }
set { SetValue(WaterRemarkProperty, value); }
} public static DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(SJTextBox)); /// <summary>
/// 边框角度
/// </summary>
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
} public static DependencyProperty IsPasswordBoxProperty =
DependencyProperty.Register("IsPasswordBox", typeof(bool), typeof(SJTextBox), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsPasswordBoxChnage))); /// <summary>
/// 是否为密码框
/// </summary>
public bool IsPasswordBox
{
get { return (bool)GetValue(IsPasswordBoxProperty); }
set { SetValue(IsPasswordBoxProperty, value); }
} public static DependencyProperty PasswordCharProperty =
DependencyProperty.Register("PasswordChar", typeof(char), typeof(SJTextBox), new FrameworkPropertyMetadata('●')); /// <summary>
/// 替换明文的单个密码字符
/// </summary>
public char PasswordChar
{
get { return (char)GetValue(PasswordCharProperty); }
set { SetValue(PasswordCharProperty, value); }
} public static DependencyProperty PasswordStrProperty =
DependencyProperty.Register("PasswordStr", typeof(string), typeof(SJTextBox), new FrameworkPropertyMetadata(string.Empty));
/// <summary>
/// 密码字符串
/// </summary>
public string PasswordStr
{
get { return GetValue(PasswordStrProperty).ToString(); }
set { SetValue(PasswordStrProperty, value); }
}
4.当设置为密码框时,监听TextChange事件,处理Text的变化,这是密码框的核心功能
private static void OnIsPasswordBoxChnage(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
(sender as SJTextBox).SetEvent();
} /// <summary>
/// 定义TextChange事件
/// </summary>
private void SetEvent()
{
if (IsPasswordBox)
this.TextChanged += SJTextBox_TextChanged;
else
this.TextChanged -= SJTextBox_TextChanged;
}
5.在TextChange事件中,处理Text为密码文,并将原字符记录给PasswordStr予以存储
private void SJTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (!IsResponseChange) //响应事件标识,替换字符时,不处理后续逻辑
return;
Console.WriteLine(string.Format("------{0}------", e.Changes.Count));
foreach (TextChange c in e.Changes)
{
Console.WriteLine(string.Format("addLength:{0} removeLenth:{1} offSet:{2}", c.AddedLength, c.RemovedLength, c.Offset));
PasswordStr = PasswordStr.Remove(c.Offset, c.RemovedLength); //从密码文中根据本次Change对象的索引和长度删除对应个数的字符
PasswordStr = PasswordStr.Insert(c.Offset, Text.Substring(c.Offset, c.AddedLength)); //将Text新增的部分记录给密码文
lastOffset = c.Offset;
}
Console.WriteLine(PasswordStr);
/*将文本转换为密码字符*/
IsResponseChange = false; //设置响应标识为不响应
this.Text = ConvertToPasswordChar(Text.Length); //将输入的字符替换为密码字符
IsResponseChange = true; //回复响应标识
this.SelectionStart = lastOffset + 1; //设置光标索引
Console.WriteLine(string.Format("SelectionStar:{0}", this.SelectionStart));
}
/// <summary>
/// 按照指定的长度生成密码字符
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
private string ConvertToPasswordChar(int length)
{
if (PasswordBuilder != null)
PasswordBuilder.Clear();
else
PasswordBuilder = new StringBuilder();
for (var i = 0; i < length; i++)
PasswordBuilder.Append(PasswordChar);
return PasswordBuilder.ToString();
}
ConvertToPasswordChar()方法用于返回指定个数的密码字符,替换Text为密码文就是调用此方法传递Text的长度完成的
6.如果用户设置了记住密码,密码文(PasswordStr)一开始就有值的话,别忘了在Load事件里事先替换一次明文
private void SJTextBox_Loaded(object sender, RoutedEventArgs e)
{
if (IsPasswordBox)
{
IsResponseChange = false;
this.Text = ConvertToPasswordChar(PasswordStr.Length);
IsResponseChange = true;
}
}
7.代码逻辑部分已经完成,替换明文为密码字符的功能已经实现了。自定义边框角度,水印功能,需要借助Style来完成,让我们来为它写一个Style
<Style TargetType="{x:Type local:SJTextBox}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="Cursor" Value="IBeam"/>
<Setter Property="Padding" Value="3,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SJTextBox}">
<Border x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding BorderCornerRadius}" <!--绑定自定义边框角度-->
SnapsToDevicePixels="True">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<TextBlock x:Name="txtRemark" Text="{TemplateBinding WaterRemark}" <!--绑定水印文字-->
Foreground="Gray" VerticalAlignment="Center"
Margin="{TemplateBinding Padding}"
Visibility="Collapsed"/> <!--默认水印文字隐藏-->
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Text" Value=""> <!--使用触发器来控制水印的隐藏显示:当文本框没有字符时显示水印文字-->
<Setter Property="Visibility" Value="Visible" TargetName="txtRemark"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
8.自定义水印文本(密码)框的调用
<local:SJTextBox Height="30"
BorderCornerRadius="3"
Margin="10,10"
Background="White"
WaterRemark="This is a TextBox"/> <!--水印文本框--> <local:SJTextBox Height="30"
BorderCornerRadius="3"
Margin="10,0"
Background="White"
WaterRemark="This is a PassworBox"
IsPasswordBox="True"
PasswordStr="{Binding Password}"/> <!--水印密码框-->
自定义的水印文本(密码)框已经完成了,它避免了对密码字体的依赖,同时密码文属性PasswordStr也支持数据绑定,非常方便。
效果图:
WPF自定义控件之水印文本(密码)框的更多相关文章
- WPF登录功能,对于密码框的操作,其实WPF有个PasswordBox专门的密码框控件,完全可以选择自己要显示的密码符号。
在链接数据库后,点击登录时需要判断用户名和密码框是否为空,而PasswordBox不像textbox那样判断 textbox判断文本框为空 if (this.UserName.Text.Trim()= ...
- WPF自定义控件三:消息提示框
需求:实现全局消息提示框 一:创建全局Message public class Message { private static readonly Style infoStyle = (Style)A ...
- WPF文本框密码框添加水印效果
WPF文本框密码框添加水印效果 来源: 阅读:559 时间:2014-12-31 分享: 0 按照惯例,先看下效果 文本框水印 文本框水印相对简单,不需要重写模板,仅仅需要一个VisualBrush ...
- WPF 之 文本框及密码框添加水印效果
1.文本框添加水印效果 文本框水印相对简单,不需要重写模板,仅仅需要一个 VisualBrush 和触发器验证一下Text是否为空即可. <TextBox Name="txtSerac ...
- WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展
一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要是对文本 ...
- 【转】WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展
一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要是对文本输入控件进行样式开发,及相关扩展功能开发,主要内容包括: 基本文 ...
- WPF自定义控件与样式(13)-自定义窗体Window & 自适应内容大小消息框MessageBox
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 自定义 ...
- 表单form的属性,单行文本框、密码框、单选多选按钮
基础表单结构: <body> <h1> <hr /> <form action="" name="myFrom" en ...
- JAVA 文本框、密码框、标签
//文本框,密码框,标签 import java.awt.*; import javax.swing.*; public class Jiemian5 extends JFrame{ JPanel m ...
随机推荐
- 兼容各种浏览器下调用iframe里面的函数
<script type="text/javascript"> var o = $(window.frames["menu"])[0].conten ...
- winform 中设置窗体的默认焦点
转载:http://www.cnblogs.com/weekzero/p/3504513.html winform的窗体中,有时候需要设置默认焦点,有时候需要取消默认焦点. 设置默认焦点,最简单的方法 ...
- Eclipse调试远程服务器
原文:https://blog.csdn.net/fengshizty/article/details/45126737 Eclipse提供能调试远程服务器的功能,最近做微信开发,需要部署到远程服务器 ...
- openresty记录响应body乱码问题
问题背景 最近新上了一个功能,openresty通过syslog记录请求日志,然后由logstash推送至ES.测试上线时未发现这个问题,在日常查看日志的过程中,发现logstash推送有错误日志,错 ...
- [转]黄聪:如何使用CodeSmith批量生成代码
本文转自:http://www.cnblogs.com/huangcong/archive/2010/06/14/1758201.html 在上一篇我们已经用PowerDesigner创建好了需要的测 ...
- 转:一位10年Java工作经验的架构师聊Java和工作经验
黄勇( 博客),从事近十年的 JavaEE 应用开发工作,现任阿里巴巴公司系统架构师.对分布式服务架构与大数据技术有深入研究,具有丰富的 B/S 架构开发经验与项目实战经验,擅长敏捷开发模式.国内开源 ...
- 用sencha touch的Cmd创建的MVC工程需要注意的问题
用ST的cmd创建的js文件都是ANSI编码格式的,所以导致无法正常显示中文.例如传输的参数为中文时就为乱码,导致各种问题... 解决办法:将js文件用记事本打开,另存为,选择编码为UTF-8,覆盖原 ...
- centos查看哪些包提供指定头文件
[问题]:项目迁移时,原来在suse上正常的代码在centos上报错: g++ -g -Wall -fPIC -I../include -I./ -I../src -I/share/comm_ext ...
- Centos6.8配置svn
svn的安装:yum -y install subversion 一.一个仓库放所有的项目 创建仓库,以后所有代码都放在这个下面,创建成功后在svn下面多了几个文件夹.1.创建仓库:svnadmin ...
- 这里先发布一个,自己写得unityUI的适配的方案(插播)
这个适配是依据坐标系的象限的思想来进项适配的.參考了部分的NGUI的适配方案. 在程序的事实上,来測量UI距离相机边界的像素然后依据比例来进行适配,个人认为还不错. 放码! . 有个前提哦就是你要先定 ...