现在的位置: 首页 > 综合 > 正文

WP7水印文本框控件开发详解.

2012年11月30日 ⁄ 综合 ⁄ 共 7689字 ⁄ 字号 评论关闭

1.首先是采取自定义控件还是用户控件开发,由于水印控件跟一般的TextBox区别无非就是增加了水印文本属性,故采取自定义控件,虽然用户控件可能简单一些...

贴一段源码:

View Code

  1  public class WatermarkedTextBox : Control
  2     {
  3         // Fields
  4         private bool _hasFocus;
  5         private bool _hasText;
  6         private TextBox _text;
  7         public static readonly DependencyProperty InputScopeProperty = DependencyProperty.Register("InputScope", typeof(InputScope), typeof(WatermarkedTextBox), new PropertyMetadata(null));
  8        
  9         public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(WatermarkedTextBox), new PropertyMetadata(string.Empty));
 10         public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register("TextWrapping", typeof(TextWrapping), typeof(WatermarkedTextBox), new PropertyMetadata((TextWrapping)1));
 11         public static readonly DependencyProperty WatermarkBrushProperty = DependencyProperty.Register("WatermarkBrush", typeof(Brush), typeof(WatermarkedTextBox), new PropertyMetadata(null));
 12         public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(string), typeof(WatermarkedTextBox), new PropertyMetadata(null));
 13 
 14         // Events
 15         public event TextChangedEventHandler TextChanged;
 16 
 17         // Methods
 18         public WatermarkedTextBox()
 19         {
 20             base.DefaultStyleKey = typeof(WatermarkedTextBox);
 21         }
 22 
 23         public override void OnApplyTemplate()
 24         {
 25             if (this._text != null)
 26             {
 27                 this._text.GotFocus -= new RoutedEventHandler(this.OnGotFocus);
 28                 this._text.LostFocus -= new RoutedEventHandler(this.OnLostFocus);
 29                 this._text.TextChanged -= new TextChangedEventHandler(this.OnTextChanged);
 30             }
 31             base.OnApplyTemplate();
 32             this._text = base.GetTemplateChild("_text") as TextBox;
 33             if (this._text != null)
 34             {
 35                 this._text.GotFocus += new RoutedEventHandler(this.OnGotFocus);
 36                 this._text.LostFocus += new RoutedEventHandler(this.OnLostFocus);
 37                 this._text.TextChanged += new TextChangedEventHandler(this.OnTextChanged);
 38             }
 39             this.UpdateVisualStates(false);
 40         }
 41 
 42         private void OnGotFocus(object sender, RoutedEventArgs e)
 43         {
 44             this._hasFocus = true;
 45             this.UpdateVisualStates(true);
 46         }
 47 
 48         private void OnLostFocus(object sender, RoutedEventArgs e)
 49         {
 50             this._hasFocus = false;
 51             this.UpdateVisualStates(true);
 52         }
 53 
 54         private void OnTextChanged(object sender, TextChangedEventArgs e)
 55         {
 56             this._hasText = !string.IsNullOrEmpty(this._text.Text);
 57             this.UpdateVisualStates(true);
 58             if (this.Text != this._text.Text)
 59             {
 60                 this.Text = this._text.Text;
 61             }
 62             TextChangedEventHandler textChanged = this.TextChanged;
 63             if (textChanged != null)
 64             {
 65                 textChanged.Invoke(this._text, e);
 66             }
 67         }
 68 
 69         private void UpdateVisualStates(bool useTransitions)
 70         {
 71             VisualStateManager.GoToState(this, this._hasText ? "Normal" : "Watermarked", useTransitions);
 72             VisualStateManager.GoToState(this, this._hasFocus ? "Focused" : "Unfocused", useTransitions);
 73         }
 74 
 75         // Properties
 76         public InputScope InputScope
 77         {
 78             get
 79             {
 80                 return (InputScope)base.GetValue(InputScopeProperty);
 81             }
 82             set
 83             {
 84                 base.SetValue(InputScopeProperty, value);
 85             }
 86         }
 87 
 88         public string Text
 89         {
 90             get
 91             {
 92                 return (base.GetValue(TextProperty) as string);
 93             }
 94             set
 95             {
 96                 base.SetValue(TextProperty, value);
 97             }
 98         }
 99 
100         public TextWrapping TextWrapping
101         {
102             get
103             {
104                 return (TextWrapping)base.GetValue(TextWrappingProperty);
105             }
106             set
107             {
108                 base.SetValue(TextWrappingProperty, value);
109             }
110         }
111 
112         public string Watermark
113         {
114             get
115             {
116                 return (base.GetValue(WatermarkProperty) as string);
117             }
118             set
119             {
120                 base.SetValue(WatermarkProperty, value);
121             }
122         }
123 
124         public Brush WatermarkBrush
125         {
126             get
127             {
128                 return (Brush)base.GetValue(WatermarkBrushProperty);
129             }
130             set
131             {
132                 base.SetValue(WatermarkBrushProperty, value);
133             }
134         }
135     }

该水印文本框控件具有水印文本,水印文本换行,水印画刷,虚拟键盘输入范围,文本框文本几个属性,为了能够在MVVM架构下进行数据绑定,我们把这几个属性定义为依赖属性;

 注意这段代码:base.DefaultStyleKey = typeof(WatermarkedTextBox);一般从Control派生出来的控件都要设置其默认样式,即控件外观;一般是在项目文件夹Theme/generic.xaml这个文件进行外观定义,该水印文本框控件外观定义XAML源码如下:

View Code

 1 <Style TargetType="Controls:WatermarkedTextBox" >
 2     <Setter Property="WatermarkBrush" Value="{StaticResource PhoneTextBoxReadOnlyBrush}"/>
 3     <Setter Property="Watermark" Value="enter text" />
 4     <Setter Property="Template">
 5       <Setter.Value>
 6         <ControlTemplate TargetType="Controls:WatermarkedTextBox">
 7           <Grid x:Name="Root">
 8             <VisualStateManager.VisualStateGroups>
 9               <VisualStateGroup x:Name="WatermarkStates">
10                 <VisualStateGroup.Transitions>
11                   <VisualTransition GeneratedDuration="00:00:00.2" />
12                 </VisualStateGroup.Transitions>
13                 <VisualState x:Name="Normal">
14                   <Storyboard>
15                     <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001"
16                                                    Storyboard.TargetName="_watermarkGrid"
17                                                    Storyboard.TargetProperty="(UIElement.Opacity)">
18                       <LinearDoubleKeyFrame KeyTime="00:00:00" Value="0" />
19                     </DoubleAnimationUsingKeyFrames>
20                   </Storyboard>
21                 </VisualState>
22                 <VisualState x:Name="Watermarked">
23                   <Storyboard>
24                     <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001"
25                                                    Storyboard.TargetName="_watermarkGrid"
26                                                    Storyboard.TargetProperty="(UIElement.Opacity)">
27                       <LinearDoubleKeyFrame KeyTime="00:00:00" Value="0.9" />
28                     </DoubleAnimationUsingKeyFrames>
29                   </Storyboard>
30                 </VisualState>
31               </VisualStateGroup>
32               <VisualStateGroup x:Name="FocusStates">
33                 <VisualStateGroup.Transitions>
34                   <VisualTransition GeneratedDuration="0" />
35                   <VisualTransition To="Focused" GeneratedDuration="0:0:0.1" />
36                 </VisualStateGroup.Transitions>
37                 <VisualState x:Name="Unfocused" />
38                 <VisualState x:Name="Focused">
39                   <Storyboard>
40                     <DoubleAnimation To="0.0"
41                                      Storyboard.TargetProperty="(UIElement.Opacity)"
42                                      Storyboard.TargetName="_watermark"/>
43                   </Storyboard>
44                 </VisualState>
45               </VisualStateGroup>
46             </VisualStateManager.VisualStateGroups>
47             <TextBox x:Name="_text"
48                      Text="{TemplateBinding Text}"
49                      TextWrapping="{TemplateBinding TextWrapping}"
50                      InputScope="{TemplateBinding InputScope}"
51                                  />
52             <Grid x:Name="_watermarkGrid" Margin="6,6,0,0">
53               <TextBlock
54                   Margin="{StaticResource PhoneTouchTargetOverhang}"
55                   Style="{StaticResource PhoneTextNormalStyle}"
56                   FontFamily="{StaticResource PhoneFontFamilyNormal}"
57                   FontSize="{StaticResource PhoneFontSizeMediumLarge}"
58                   x:Name="_watermark"
59                   IsHitTestVisible="False"
60                   TextWrapping="Wrap"
61                   Foreground="{TemplateBinding WatermarkBrush}"
62                   Text="{TemplateBinding Watermark}"
63                   VerticalAlignment="Top"
64                   HorizontalAlignment="Left" />
65             </Grid>
66           </Grid>
67         </ControlTemplate>
68       </Setter.Value>
69     </Setter>
70   </Style>

该控件的控件模板设计思路是:水印文本用TextBlock定义(用只有一个单元格的Grid进行包裹),默认文本框还是TextBox定义,最后把这两个控件用只含有一个单元格的Grid进行包裹;然后就是定义其视觉状态组,在这个控件里我们只关注水印状态视觉组和Focus状态视觉组;

定义好控件外观后,我们需要设置其事件,套用外观模板,我们需要重写Control控件的OnApplyTemplate方法,源码如下:

View Code

 1 public override void OnApplyTemplate()
 2         {
 3             if (this._text != null)
 4             {
 5                 this._text.GotFocus -= new RoutedEventHandler(this.OnGotFocus);
 6                 this._text.LostFocus -= new RoutedEventHandler(this.OnLostFocus);
 7                 this._text.TextChanged -= new TextChangedEventHandler(this.OnTextChanged);
 8             }
 9             base.OnApplyTemplate();
10             this._text = base.GetTemplateChild("_text") as TextBox;
11             if (this._text != null)
12             {
13                 this._text.GotFocus += new RoutedEventHandler(this.OnGotFocus);
14                 this._text.LostFocus += new RoutedEventHandler(this.OnLostFocus);
15                 this._text.TextChanged += new TextChangedEventHandler(this.OnTextChanged);
16             }
17             this.UpdateVisualStates(false);
18         }

然后贴各种事件和视觉状态更新方法源码如下:

View Code

 1 private void OnGotFocus(object sender, RoutedEventArgs e)
 2         {
 3             this._hasFocus = true;
 4             this.UpdateVisualStates(true);
 5         }
 6 
 7         private void OnLostFocus(object sender, RoutedEventArgs e)
 8         {
 9             this._hasFocus = false;
10             this.UpdateVisualStates(true);
11         }
12 
13         private void OnTextChanged(object sender, TextChangedEventArgs e)
14         {
15             this._hasText = !string.IsNullOrEmpty(this._text.Text);
16             this.UpdateVisualStates(true);
17             if (this.Text != this._text.Text)
18             {
19                 this.Text = this._text.Text;
20             }
21             TextChangedEventHandler textChanged = this.TextChanged;
22             if (textChanged != null)
23             {
24                 textChanged.Invoke(this._text, e);
25             }
26         }
27 
28         private void UpdateVisualStates(bool useTransitions)
29         {
30             VisualStateManager.GoToState(this, this._hasText ? "Normal" : "Watermarked", useTransitions);
31             VisualStateManager.GoToState(this, this._hasFocus ? "Focused" : "Unfocused", useTransitions);
32         }

抱歉!评论已关闭.