WindowsPhone自定义控件详解(三) - 实战:自定义带水印的PasswordBox控件,WatermarkedPasswordBox

声明:这个控件是在WatermarkedTextBox的基础上改的。

原创地址:http://blog.csdn.net/mr_raptor/article/details/7251992

原理分析:

在PasswordBox后面加水印和在TextBox后面加水印差不多,有以下要求:

  1. PasswordBox里没内容时,显示水印
  2. PasswordBox里有内容时,不显示水印,而显示内容

最简单的想法就是,在PasswordBox控件后面加上一个类似TextBlock的控件,然后重写焦点回调方法,当有焦点时,水印不显示,无焦点时,根据是否有内容而决定是否显示水印。

思路如上,下面开始分析WatermarkedTextBox的代码,看看它的作者是不是和我们想法一样。

 

 

一、 分析WatermarkedTextBox代码

 

  1. themes/generic.xaml

自定义控件的样式文件必须要以generic.xaml命名,放到themes目录中。

[html]  view plain copy
  1. <ControlTemplate x:Key="PhoneDisabledTextBoxTemplate" TargetType="TextBox">  
  2.     <ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>  
  3. </ControlTemplate>  
  4.         <Style  TargetType="local:WatermarkedTextBox">  
  5.    <Setter Property="Template">  
  6.     <Setter.Value>  
  7.         <ControlTemplate TargetType="local:WatermarkedTextBox">  
  8.             <Grid Background="Transparent">  
  9.                 <Border x:Name="EnabledBorder">  
  10.                     <Grid>  
  11.                         <ContentControl x:Name="watermarkContent" Style="{TemplateBinding WatermarkStyle}" Content="{TemplateBinding Watermark}" Background="Transparent" Opacity="0.5"/>  
  12.                         <ContentControl x:Name="ContentElement" BorderThickness="0"  VerticalContentAlignment="Stretch"/>  
  13.                     </Grid>  
  14.                 </Border>  
  15.                 <Border x:Name="DisabledOrReadonlyBorder" Background="Transparent"  Visibility="Collapsed">  
  16.                     <TextBox x:Name="DisabledOrReadonlyContent" Background="Transparent" IsReadOnly="True" Text="{TemplateBinding Text}"  Template="{StaticResource PhoneDisabledTextBoxTemplate}"/>  
  17.                     </Border>  
  18.                 </Grid>  
  19.             </ControlTemplate>  
  20.         </Setter.Value>  
  21.     </Setter>  
  22. </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

[csharp]  view plain copy
  1. namespace WatermarkedTextBoxControl  
  2. {  
  3.     public class WatermarkedTextBox : TextBox  
  4.     {  
  5.         ContentControl WatermarkContent;  
  6.         public static readonly DependencyProperty WatermarkProperty =  
  7.       DependencyProperty.Register("Watermark"typeof(object), typeof(WatermarkedTextBox), new PropertyMetadata(OnWatermarkPropertyChanged));  
  8.    
  9.         public static readonly DependencyProperty WatermarkStyleProperty =  
  10.       DependencyProperty.Register("WatermarkStyle"typeof(Style), typeof(WatermarkedTextBox), null);  
  11.    
  12.         public Style WatermarkStyle  
  13.         {  
  14.             get { return base.GetValue(WatermarkStyleProperty) as Style; }  
  15.             set { base.SetValue(WatermarkStyleProperty, value); }  
  16.         }  
  17.    
  18.         public object Watermark  
  19.         {  
  20.             get { return base.GetValue(WatermarkProperty) as object; }  
  21.             set { base.SetValue(WatermarkProperty, value); }  
  22.         }  
  23.    
  24.         public WatermarkedTextBox()  
  25.         {  
  26.             DefaultStyleKey = typeof(WatermarkedTextBox);  
  27.         }  
  28.    
  29.         public override void OnApplyTemplate()  
  30.         {  
  31.             base.OnApplyTemplate();  
  32.             this.WatermarkContent = this.GetTemplateChild("watermarkContent"as ContentControl;  
  33.             if(WatermarkContent != null)  
  34.             {  
  35.               DetermineWatermarkContentVisibility();  
  36.             }  
  37.         }  
  38.    
  39.         protected override void OnGotFocus(RoutedEventArgs e)  
  40.         {  
  41.             if (WatermarkContent != null && string.IsNullOrEmpty(this.Text))  
  42.             {  
  43.                 this.WatermarkContent.Visibility = Visibility.Collapsed;  
  44.             }  
  45.             base.OnGotFocus(e);  
  46.         }  
  47.    
  48.         protected override void OnLostFocus(RoutedEventArgs e)  
  49.         {  
  50.             if (WatermarkContent != null && string.IsNullOrEmpty(this.Text))  
  51.             {  
  52.                 this.WatermarkContent.Visibility = Visibility.Visible;  
  53.             }  
  54.             base.OnLostFocus(e);  
  55.         }  
  56.    
  57.         private static void OnWatermarkPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)  
  58.         {  
  59.             WatermarkedTextBox watermarkTextBox = sender as WatermarkedTextBox;  
  60.             if(watermarkTextBox != null && watermarkTextBox.WatermarkContent !=null)  
  61.             {  
  62.               watermarkTextBox.DetermineWatermarkContentVisibility();  
  63.             }  
  64.         }  
  65.    
  66.         private void DetermineWatermarkContentVisibility()  
  67.         {  
  68.             if (string.IsNullOrEmpty(this.Text))  
  69.             {  
  70.                 this.WatermarkContent.Visibility = Visibility.Visible;  
  71.             }  
  72.             else  
  73.             {  
  74.                 this.WatermarkContent.Visibility = Visibility.Collapsed;  
  75.             }  
  76.         }  
  77.     }  
  78.     }  
  79. }  

原创地址: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:

[html]  view plain copy
  1. <Style  TargetType="local:WatermarkedPasswordBox">  
  2.        <Setter Property="Template">  
  3.            <Setter.Value>  
  4.                <ControlTemplate TargetType="local:WatermarkedPasswordBox">  
  5.                    <Grid Background="Transparent">  
  6.                        <Border x:Name="EnabledBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">  
  7.                            <Grid>  
  8.                                <ContentControl x:Name="watermarkContent" Style="{TemplateBinding WatermarkStyle}" Content="{TemplateBinding Watermark}" Background="Transparent" Opacity="0.5"/>  
  9.                                <PasswordBox x:Name="ContentElement" Background="Transparent"  
  10.                 Password="{TemplateBinding Text}"   
  11.                                     BorderThickness="0" HorizontalContentAlignment="Stretch"  
  12.                                     Margin="-12,-12,-12,-12"   
  13.                                     VerticalContentAlignment="Stretch"/>  
  14.                            </Grid>  
  15.                        </Border>  
  16.                    </Grid>  
  17.                </ControlTemplate>  
  18.            </Setter.Value>  
  19.        </Setter>  
  20.    </Style>  

原创地址:http://blog.csdn.net/mr_raptor/article/details/7251992
C#:

[html]  view plain copy
  1. public class WatermarkedPasswordBox : TextBox  
  2.    {  
  3.        ContentControl WatermarkContent;  
  4.        private PasswordBox PasswordContent;  
  5.   
  6.        public object Watermark  
  7.        {  
  8.            get { return base.GetValue(WatermarkProperty) as object; }  
  9.            set { base.SetValue(WatermarkProperty, value); }  
  10.        }  
  11.        public static readonly DependencyProperty WatermarkProperty =  
  12.        DependencyProperty.Register("Watermark", typeof(object), typeof(WatermarkedPasswordBox), new PropertyMetadata(OnWatermarkPropertyChanged));  
  13.   
  14.        private static void OnWatermarkPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)  
  15.        {  
  16.            WatermarkedPasswordBox watermarkTextBox = sender as WatermarkedPasswordBox;  
  17.            if (watermarkTextBox != null && watermarkTextBox.WatermarkContent != null)  
  18.            {  
  19.                watermarkTextBox.DetermineWatermarkContentVisibility();  
  20.            }  
  21.   
  22.            Debug.WriteLine("OnWatermarkPropertyChanged");  
  23.        }  
  24.   
  25.        public Style WatermarkStyle  
  26.        {  
  27.            get { return base.GetValue(WatermarkStyleProperty) as Style; }  
  28.            set { base.SetValue(WatermarkStyleProperty, value); }  
  29.        }  
  30.        public static readonly DependencyProperty WatermarkStyleProperty =  
  31.        DependencyProperty.Register("WatermarkStyle", typeof(Style), typeof(WatermarkedPasswordBox), null);  
  32.   
  33.        public WatermarkedPasswordBox()  
  34.        {  
  35.            DefaultStyleKey = typeof(WatermarkedPasswordBox);  
  36.        }  
  37.   
  38.        public override void OnApplyTemplate()  
  39.        {  
  40.            base.OnApplyTemplate();  
  41.            this.WatermarkContent = this.GetTemplateChild("watermarkContent") as ContentControl;  
  42.            this.PasswordContent = this.GetTemplateChild("ContentElement") as PasswordBox;  
  43.            if (WatermarkContent != null && WatermarkContent != null)  
  44.            {  
  45.                PasswordContent.PasswordChanged += new RoutedEventHandler(PasswordContent_PasswordChanged);  
  46.                DetermineWatermarkContentVisibility();  
  47.            }  
  48.        }  
  49.   
  50.        void PasswordContent_PasswordChanged(object sender, RoutedEventArgs e)  
  51.        {  
  52.            PasswordBox passwdBx = sender as PasswordBox;  
  53.            this.Text = passwdBx.Password;  
  54.        }  
  55.   
  56.        protected override void OnGotFocus(RoutedEventArgs e)  
  57.        {  
  58.            if (WatermarkContent != null && WatermarkContent != null && string.IsNullOrEmpty(this.PasswordContent.Password))  
  59.            {  
  60.                this.WatermarkContent.Visibility = Visibility.Collapsed;  
  61.            }  
  62.            base.OnGotFocus(e);  
  63.        }  
  64.   
  65.        protected override void OnLostFocus(RoutedEventArgs e)  
  66.        {  
  67.            if (WatermarkContent != null && WatermarkContent != null && string.IsNullOrEmpty(this.PasswordContent.Password))  
  68.            {  
  69.                this.WatermarkContent.Visibility = Visibility.Visible;  
  70.            }  
  71.            base.OnLostFocus(e);  
  72.        }  
  73.   
  74.        private void DetermineWatermarkContentVisibility()  
  75.        {  
  76.            if (string.IsNullOrEmpty(this.PasswordContent.Password))  
  77.            {  
  78.                this.WatermarkContent.Visibility = Visibility.Visible;  
  79.            }  
  80.            else  
  81.            {  
  82.                this.WatermarkContent.Visibility = Visibility.Collapsed;  
  83.            }  
  84.        }  
  85.    }  


编译通过,将生成的库引入到Demo程序里,然后将控件加上,成功,效果如下。

左图,未输入内容,显示水印,右图,输入内容时显示效果。

 

 

++++++++++++++++++++++++++++++++++++++++++

本文系本站原创,欢迎转载! 转载请注明出处:

http://blog.csdn.net/mr_raptor/article/details/7251992

++++++++++++++++++++++++++++++++++++++++++

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你不想使用自定义控件,你仍然可以在WPF中禁止PasswordBox控件的复制和粘贴操作。以下是一种方法: 1. 使用Attached Property(附加属性)来控制PasswordBox的行为。 ```csharp public static class PasswordBoxHelper { public static readonly DependencyProperty IsCopyPasteEnabledProperty = DependencyProperty.RegisterAttached("IsCopyPasteEnabled", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(true, OnIsCopyPasteEnabledChanged)); public static bool GetIsCopyPasteEnabled(DependencyObject obj) { return (bool)obj.GetValue(IsCopyPasteEnabledProperty); } public static void SetIsCopyPasteEnabled(DependencyObject obj, bool value) { obj.SetValue(IsCopyPasteEnabledProperty, value); } private static void OnIsCopyPasteEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is PasswordBox passwordBox) { if ((bool)e.NewValue) { passwordBox.PreviewKeyDown += PasswordBox_PreviewKeyDown; DataObject.AddPastingHandler(passwordBox, PasswordBox_Pasting); } else { passwordBox.PreviewKeyDown -= PasswordBox_PreviewKeyDown; DataObject.RemovePastingHandler(passwordBox, PasswordBox_Pasting); } } } private static void PasswordBox_PreviewKeyDown(object sender, KeyEventArgs e) { if ((e.Key == Key.V || e.Key == Key.C || e.Key == Key.X) && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) { e.Handled = true; } } private static void PasswordBox_Pasting(object sender, DataObjectPastingEventArgs e) { e.CancelCommand(); } } ``` 在上述代码中,我们创建了一个名为IsCopyPasteEnabled的附加属性,并使用PreviewKeyDown事件和DataObject的Pasting事件来禁止复制和粘贴操作。 2. 在XAML中将该附加属性应用于PasswordBox控件。 ```xml <PasswordBox local:PasswordBoxHelper.IsCopyPasteEnabled="False" /> ``` 通过将IsCopyPasteEnabled属性设置为"False",我们禁用了PasswordBox控件的复制和粘贴操作。 这样,你可以在不使用自定义控件的情况下禁止PasswordBox的复制和粘贴功能。 希望对你有所帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值