WindowsPhone自定义控件详解(三) - 实战:自定义带水印的PasswordBox控件,WatermarkedPasswordBox
来源:互联网 发布:mysql读写分离实现 编辑:程序博客网 时间:2024/06/09 16:44
声明:这个控件是在WatermarkedTextBox的基础上改的。
- 从http://www.windowsphonegeek.com/articles/WP7-WatermarkedTextBox-custom-control上下载WatermarkedTextBox控件
原创地址:http://blog.csdn.net/mr_raptor/article/details/7251992
原理分析:
在PasswordBox后面加水印和在TextBox后面加水印差不多,有以下要求:
- PasswordBox里没内容时,显示水印
- PasswordBox里有内容时,不显示水印,而显示内容
最简单的想法就是,在PasswordBox控件后面加上一个类似TextBlock的控件,然后重写焦点回调方法,当有焦点时,水印不显示,无焦点时,根据是否有内容而决定是否显示水印。
思路如上,下面开始分析WatermarkedTextBox的代码,看看它的作者是不是和我们想法一样。
一、 分析WatermarkedTextBox代码
- themes/generic.xaml
自定义控件的样式文件必须要以generic.xaml命名,放到themes目录中。
- <ControlTemplate x:Key="PhoneDisabledTextBoxTemplate" TargetType="TextBox">
- <ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>
- </ControlTemplate>
- <Style TargetType="local:WatermarkedTextBox">
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="local:WatermarkedTextBox">
- <Grid Background="Transparent">
- <Border x:Name="EnabledBorder">
- <Grid>
- <ContentControl x:Name="watermarkContent" Style="{TemplateBinding WatermarkStyle}" Content="{TemplateBinding Watermark}" Background="Transparent" Opacity="0.5"/>
- <ContentControl x:Name="ContentElement" BorderThickness="0" VerticalContentAlignment="Stretch"/>
- </Grid>
- </Border>
- <Border x:Name="DisabledOrReadonlyBorder" Background="Transparent" Visibility="Collapsed">
- <TextBox x:Name="DisabledOrReadonlyContent" Background="Transparent" IsReadOnly="True" Text="{TemplateBinding Text}" Template="{StaticResource PhoneDisabledTextBoxTemplate}"/>
- </Border>
- </Grid>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
注:上面省略了一部分无关紧要代码。
http://blog.csdn.net/mr_raptor/article/details/7251992
上面的XAML文件,定义了WatermarkedTextBox的样式:
- 文件开始,定义了一个ControlTemplate元素,由前两节知识可知,它是要对一个控件设置模板,从后面的TargetType="TextBox"可知,是针对TextBox类型控件,它里面自定义了一个ContentControl类名字为ContentElement。
- 通过TargetType="local:WatermarkedTextBox" 可知,它是针对WatermarkedTextBox的控件样式。
- 在EnabledBorder里定义了两个内容控件元素:watermarkContent和ContentElement,watermarkContent里,绑定了依赖属性Watermark(在WatermarkTextBox.cs里声明)。
- 在下面的DisabledOrReadonlyBorder里面是一个TextBox 控件,它绑定了WatermarkedTextBox里的Text属性,同时这个TextBox 控件,的模板设置为:PhoneDisabledTextBoxTemplate,它这么做的目的是,可以设置WatermarkedTextBox的属性为Disabled,这时,水印就消失了,而显示原先的TextBox控件。
2. WatermarkTextBox.cs
- namespace WatermarkedTextBoxControl
- {
- public class WatermarkedTextBox : TextBox
- {
- ContentControl WatermarkContent;
- public static readonly DependencyProperty WatermarkProperty =
- DependencyProperty.Register("Watermark", typeof(object), typeof(WatermarkedTextBox), new PropertyMetadata(OnWatermarkPropertyChanged));
- public static readonly DependencyProperty WatermarkStyleProperty =
- DependencyProperty.Register("WatermarkStyle", typeof(Style), typeof(WatermarkedTextBox), null);
- public Style WatermarkStyle
- {
- get { return base.GetValue(WatermarkStyleProperty) as Style; }
- set { base.SetValue(WatermarkStyleProperty, value); }
- }
- public object Watermark
- {
- get { return base.GetValue(WatermarkProperty) as object; }
- set { base.SetValue(WatermarkProperty, value); }
- }
- public WatermarkedTextBox()
- {
- DefaultStyleKey = typeof(WatermarkedTextBox);
- }
- public override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
- this.WatermarkContent = this.GetTemplateChild("watermarkContent") as ContentControl;
- if(WatermarkContent != null)
- {
- DetermineWatermarkContentVisibility();
- }
- }
- protected override void OnGotFocus(RoutedEventArgs e)
- {
- if (WatermarkContent != null && string.IsNullOrEmpty(this.Text))
- {
- this.WatermarkContent.Visibility = Visibility.Collapsed;
- }
- base.OnGotFocus(e);
- }
- protected override void OnLostFocus(RoutedEventArgs e)
- {
- if (WatermarkContent != null && string.IsNullOrEmpty(this.Text))
- {
- this.WatermarkContent.Visibility = Visibility.Visible;
- }
- base.OnLostFocus(e);
- }
- private static void OnWatermarkPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
- {
- WatermarkedTextBox watermarkTextBox = sender as WatermarkedTextBox;
- if(watermarkTextBox != null && watermarkTextBox.WatermarkContent !=null)
- {
- watermarkTextBox.DetermineWatermarkContentVisibility();
- }
- }
- private void DetermineWatermarkContentVisibility()
- {
- if (string.IsNullOrEmpty(this.Text))
- {
- this.WatermarkContent.Visibility = Visibility.Visible;
- }
- else
- {
- this.WatermarkContent.Visibility = Visibility.Collapsed;
- }
- }
- }
- }
- }
原创地址:http://blog.csdn.net/mr_raptor/article/details/7251992
由这个WatermarkedTextBox类可知:
- 它继承了TextBox类
- 增加了Watermark和WatermarkStyle两个依赖属性,用于用户设置它的水印内容和样式,在Watermark属性里添加了属性改变事件:OnWatermarkPropertyChanged
- 重载了OnApplyTemplate方法来取得generic.xaml文件里声明的元素引用:watermarkContent,并且根据generic.xaml里的TextBox :DisabledOrReadonlyContent,取得它里面是否有内容,如果有内容,则WatermarkContent不可见,否则WatermarkContent可见。
- 重载了OnGotFocus,OnLostFocus,当该自定义控件得到焦点时,设置WatermarkContent不可见,否则WatermarkContent可见。
由上面的分析可知,当用户设置了自定义控件的Watermark属性时,回调注册的OnWatermarkPropertyChanged方法,在该方法里,判断是否WatermarkContent里有内容,如果有,WatermarkContent不可见,否则WatermarkContent可见。两样,重载了OnGotFocus,OnLostFocus,在得到和失去焦点时也要判断是否将WatermarkContent设置为可见与否。
二、 自定义WatermarkedPasswordBox
根据前面的分析,我们可以试着做以下修改:
- 新建类WatermarkedPasswordBox
- 将WatermarkTextBox.cs拷贝到类WatermarkedPasswordBox里,改下类名,让WatermarkedPasswordBox继承了Password类
- 在themes/generic.xaml里,拷贝 <Style TargetType="local:WatermarkedPasswordBox">里的全部代码,改为WatermarkedPasswordBox的代码,中间细节自己改就行了,我们不打算支持Disabled属性,所以DisabledOrReadonlyBorder去掉就行了,将EnabledBorder里的ContentElement去掉,换成PasswordBox,名字还是ContentElement
编译时,错误出现了:WatermarkedPasswordBox里this.Text出错,这是因为Password没有Text属性,它有个Password属性,所以要做下面的修改:
- 让WatermarkedPasswordBox类继承TextBox,但是添加一个属性:PasswordBox类型的PasswordContent
- 在OnApplyTemplate方法里,获得自己加的PasswordBox控件的引用ContentElement,为PasswordBox控件添加PasswordChanged事件,当密码框里内容改变时,将TextBox的Text属性的值为PasswordBox.Password的值
- 同样,在XAML样式文件里,在PasswordBox控件里加上 Password="{TemplateBinding Text}"
修改后的代码如下:
XAML:
- <Style TargetType="local:WatermarkedPasswordBox">
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="local:WatermarkedPasswordBox">
- <Grid Background="Transparent">
- <Border x:Name="EnabledBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">
- <Grid>
- <ContentControl x:Name="watermarkContent" Style="{TemplateBinding WatermarkStyle}" Content="{TemplateBinding Watermark}" Background="Transparent" Opacity="0.5"/>
- <PasswordBox x:Name="ContentElement" Background="Transparent"
- Password="{TemplateBinding Text}"
- BorderThickness="0" HorizontalContentAlignment="Stretch"
- Margin="-12,-12,-12,-12"
- VerticalContentAlignment="Stretch"/>
- </Grid>
- </Border>
- </Grid>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
原创地址:http://blog.csdn.net/mr_raptor/article/details/7251992
C#:
- public class WatermarkedPasswordBox : TextBox
- {
- ContentControl WatermarkContent;
- private PasswordBox PasswordContent;
- public object Watermark
- {
- get { return base.GetValue(WatermarkProperty) as object; }
- set { base.SetValue(WatermarkProperty, value); }
- }
- public static readonly DependencyProperty WatermarkProperty =
- DependencyProperty.Register("Watermark", typeof(object), typeof(WatermarkedPasswordBox), new PropertyMetadata(OnWatermarkPropertyChanged));
- private static void OnWatermarkPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
- {
- WatermarkedPasswordBox watermarkTextBox = sender as WatermarkedPasswordBox;
- if (watermarkTextBox != null && watermarkTextBox.WatermarkContent != null)
- {
- watermarkTextBox.DetermineWatermarkContentVisibility();
- }
- Debug.WriteLine("OnWatermarkPropertyChanged");
- }
- public Style WatermarkStyle
- {
- get { return base.GetValue(WatermarkStyleProperty) as Style; }
- set { base.SetValue(WatermarkStyleProperty, value); }
- }
- public static readonly DependencyProperty WatermarkStyleProperty =
- DependencyProperty.Register("WatermarkStyle", typeof(Style), typeof(WatermarkedPasswordBox), null);
- public WatermarkedPasswordBox()
- {
- DefaultStyleKey = typeof(WatermarkedPasswordBox);
- }
- public override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
- this.WatermarkContent = this.GetTemplateChild("watermarkContent") as ContentControl;
- this.PasswordContent = this.GetTemplateChild("ContentElement") as PasswordBox;
- if (WatermarkContent != null && WatermarkContent != null)
- {
- PasswordContent.PasswordChanged += new RoutedEventHandler(PasswordContent_PasswordChanged);
- DetermineWatermarkContentVisibility();
- }
- }
- void PasswordContent_PasswordChanged(object sender, RoutedEventArgs e)
- {
- PasswordBox passwdBx = sender as PasswordBox;
- this.Text = passwdBx.Password;
- }
- protected override void OnGotFocus(RoutedEventArgs e)
- {
- if (WatermarkContent != null && WatermarkContent != null && string.IsNullOrEmpty(this.PasswordContent.Password))
- {
- this.WatermarkContent.Visibility = Visibility.Collapsed;
- }
- base.OnGotFocus(e);
- }
- protected override void OnLostFocus(RoutedEventArgs e)
- {
- if (WatermarkContent != null && WatermarkContent != null && string.IsNullOrEmpty(this.PasswordContent.Password))
- {
- this.WatermarkContent.Visibility = Visibility.Visible;
- }
- base.OnLostFocus(e);
- }
- private void DetermineWatermarkContentVisibility()
- {
- if (string.IsNullOrEmpty(this.PasswordContent.Password))
- {
- this.WatermarkContent.Visibility = Visibility.Visible;
- }
- else
- {
- this.WatermarkContent.Visibility = Visibility.Collapsed;
- }
- }
- }
编译通过,将生成的库引入到Demo程序里,然后将控件加上,成功,效果如下。
左图,未输入内容,显示水印,右图,输入内容时显示效果。
++++++++++++++++++++++++++++++++++++++++++
本文系本站原创,欢迎转载! 转载请注明出处:
http://blog.csdn.net/mr_raptor/article/details/7251992
++++++++++++++++++++++++++++++++++++++++++
- WindowsPhone自定义控件详解(三) - 实战:自定义带水印的PasswordBox控件,WatermarkedPasswordBox
- WindowsPhone自定义控件详解(三) - 实战:自定义带水印的PasswordBox控件,WatermarkedPasswordBox
- WindowsPhone自定义控件详解
- WindowsPhone自定义控件详解(一) - 控件类库分析
- WindowsPhone自定义控件详解(一)- 控件类库分析
- WindowsPhone自定义控件详解(一) - 控件类库分析
- WindowsPhone自定义控件详解(二) - 模板类库分析
- WindowsPhone自定义控件详解(二) - 模板类库分析
- 自定义控件实战<三> 动态圆弧控件
- 自定义控件(三)
- 自定义控件三:自定义属性详解
- Android自定义控件实战
- 自定义控件ViewGroup实战
- 自定义控件实战
- 简单的自定义控件三
- Android自定义控件(三)继承控件
- .net自定义控件(三)
- 自定义控件入门(三)
- 系统权限数据库设计方案
- 10.4 UIScrollview概念和用法:单张图片缩放
- 你知道这些程序出现这些结果的原因吗?
- 【IPV6基础知识】IPV6邻居发现协议
- PL/SQL Developer集成Oracle数据库客户端版安装教程
- WindowsPhone自定义控件详解(三) - 实战:自定义带水印的PasswordBox控件,WatermarkedPasswordBox
- POJ 1201 Intervals
- Java中“this”的理解
- 给eclipse安装插件
- Java 生成本文文件的时候,Dos格式转成Unix格式
- SQL优化大总结
- UVA 10905(为什么)
- (34)DOM应用之搜索表格中的内容(多关键字搜索)
- 发大幅度会飞的