1
ļ»æ// Copyright Ā© Microsoft Corporation.
2
// This source is subject to the Microsoft Source License for Silverlight Controls (March 2008 Release).
3
// Please see http://go.microsoft.com/fwlink/?LinkID=111693 for details.
4
// All other rights reserved.
6
namespace System.Windows.Controls
8
using System.Diagnostics;
9
using System.Globalization;
12
using System.Windows.Input;
13
using System.Windows.Markup;
14
using System.Windows.Media.Animation;
17
/// WatermarkedTextBox is a specialized form of TextBox which displays custom visuals when its contents are empty
19
[TemplatePart(Name = WatermarkedTextBox.ElementRootName, Type = typeof(FrameworkElement))]
20
[TemplatePart(Name = WatermarkedTextBox.ElementContentName, Type = typeof(ContentControl))]
21
[TemplatePart(Name = WatermarkedTextBox.StateNormalName, Type = typeof(Storyboard))]
22
[TemplatePart(Name = WatermarkedTextBox.StateMouseOverName, Type = typeof(Storyboard))]
23
[TemplatePart(Name = WatermarkedTextBox.StateNormalWatermarkedName, Type = typeof(Storyboard))]
24
[TemplatePart(Name = WatermarkedTextBox.StateMouseOverWatermarkedName, Type = typeof(Storyboard))]
25
[TemplatePart(Name = WatermarkedTextBox.StateDisabledName, Type = typeof(Storyboard))]
26
[TemplatePart(Name = WatermarkedTextBox.StateDisabledWatermarkedName, Type = typeof(Storyboard))]
27
[TemplatePart(Name = WatermarkedTextBox.StateFocusedName, Type = typeof(Storyboard))]
28
public partial class WatermarkedTextBox : TextBox
31
private const string ElementRootName = "RootElement";
32
private const string ElementContentName = "WatermarkElement";
33
private const string StateNormalName = "Normal State";
34
private const string StateNormalWatermarkedName = "Normal Watermarked State";
35
private const string StateMouseOverName = "MouseOver State";
36
private const string StateMouseOverWatermarkedName = "MouseOver Watermarked State";
37
private const string StateDisabledName = "Disabled State";
38
private const string StateDisabledWatermarkedName = "Disabled Watermarked State";
39
private const string StateFocusedName = "Focused State";
41
private const string TemplateXamlPath = "System.Windows.Controls.WatermarkedTextBox.WatermarkedTextBox.xaml";
48
/// Initializes a new instance of the <see cref="WatermarkedTextBox"/> class.
50
public WatermarkedTextBox()
55
this.MouseEnter += OnMouseEnter;
56
this.MouseLeave += OnMouseLeave;
57
this.Loaded += OnLoaded;
58
this.LostFocus += OnLostFocus;
59
this.GotFocus += OnGotFocus;
60
this.TextChanged += OnTextChanged;
66
internal FrameworkElement elementRoot;
67
internal ContentControl elementContent;
68
internal Storyboard stateNormalWatermarked;
69
internal Storyboard stateNormal;
70
internal Storyboard stateFocused;
71
internal Storyboard stateMouseOver;
72
internal Storyboard stateMouseOverWatermarked;
73
internal Storyboard stateDisabled;
74
internal Storyboard stateDisabledWatermarked;
75
internal Storyboard currentState;
76
internal bool isHovered;
77
internal bool hasFocus;
79
//this method is made 'internal virtual' so the a TestWatermarkedTextBox with custom verification code
80
//that executes in OnLoaded could be created
81
internal virtual void OnLoaded(object sender, RoutedEventArgs e)
87
internal void ToggleState()
91
if (!hasFocus && this.Watermark != null && string.IsNullOrEmpty(Text))
95
TryChangeState(stateMouseOverWatermarked ?? stateNormalWatermarked ?? stateNormal);
99
TryChangeState(stateNormalWatermarked ?? stateNormal);
106
TryChangeState(stateMouseOver ?? stateNormal);
110
TryChangeState(stateFocused ?? stateNormal);
114
TryChangeState(stateNormal);
120
if (this.Watermark != null && string.IsNullOrEmpty(this.Text))
122
TryChangeState(stateDisabledWatermarked ?? stateDisabled ?? stateNormalWatermarked ?? stateNormal);
126
TryChangeState(stateDisabled ?? stateNormal);
135
/// Called when template is applied to the control.
137
public override void OnApplyTemplate()
139
base.OnApplyTemplate();
141
elementRoot = ExtractTemplatePart<FrameworkElement>(ElementRootName);
142
elementContent = ExtractTemplatePart<ContentControl>(ElementContentName);
144
OnWatermarkChanged();
146
if (elementRoot != null)
148
stateNormalWatermarked = ExtractTemplatePartResource<Storyboard>(elementRoot, StateNormalWatermarkedName);
149
stateNormal = ExtractTemplatePartResource<Storyboard>(elementRoot, StateNormalName);
150
stateFocused = ExtractTemplatePartResource<Storyboard>(elementRoot, StateFocusedName);
151
stateMouseOver = ExtractTemplatePartResource<Storyboard>(elementRoot, StateMouseOverName);
152
stateMouseOverWatermarked = ExtractTemplatePartResource<Storyboard>(elementRoot, StateMouseOverWatermarkedName);
153
stateDisabled = ExtractTemplatePartResource<Storyboard>(elementRoot, StateDisabledName);
154
stateDisabledWatermarked = ExtractTemplatePartResource<Storyboard>(elementRoot, StateDisabledWatermarkedName);
170
/// IsEnabled dependency property
172
public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register(
173
"IsEnabled", typeof(bool), typeof(WatermarkedTextBox), new PropertyMetadata(OnIsEnabledPropertyChanged));
177
/// Gets or sets a value indicating whether this element is enabled in the user interface (UI). This is a dependency property.
180
/// <returns>true if the element is enabled; otherwise, false. The default value is true.</returns>
181
public bool IsEnabled
183
get { return (bool)GetValue(IsEnabledProperty); }
184
set { SetValue(IsEnabledProperty, value); }
192
/// Gets or sets the tool-tip object that is displayed for this element
193
/// in the user interface (UI).
195
public object ToolTip
197
get { return ToolTipService.GetToolTip(this); }
198
set { ToolTipService.SetToolTip(this, value); }
205
/// Watermark dependency property
207
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
208
"Watermark", typeof(object), typeof(WatermarkedTextBox), new PropertyMetadata(OnWatermarkPropertyChanged));
211
/// Watermark content
213
/// <value>The watermark.</value>
214
public object Watermark
216
get { return (object)GetValue(WatermarkProperty); }
217
set { SetValue(WatermarkProperty, value); }
226
private static string styleXaml;
228
private static T ExtractTemplatePartResource<T>(FrameworkElement root, string resourceName) where T : DependencyObject
230
DependencyObject obj = (DependencyObject)root.Resources[resourceName];
231
return ExtractTemplatePart<T>(resourceName, obj);
235
private T ExtractTemplatePart<T>(string partName) where T : DependencyObject
237
DependencyObject obj = GetTemplateChild(partName);
238
return ExtractTemplatePart<T>(partName, obj);
242
private static T ExtractTemplatePart<T>(string partName, DependencyObject obj) where T : DependencyObject
244
Debug.Assert(obj == null || typeof(T).IsInstanceOfType(obj),
245
string.Format(CultureInfo.InvariantCulture, Resource.WatermarkedTextBox_TemplatePartIsOfIncorrectType, partName, typeof(T).Name));
251
private void OnGotFocus(object sender, RoutedEventArgs e)
257
if (!string.IsNullOrEmpty(this.Text))
259
Select(0, this.Text.Length);
268
/// Called when is enabled property is changed.
270
/// <param name="sender">The sender.</param>
271
/// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
272
private static void OnIsEnabledPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
274
WatermarkedTextBox watermarkedTextBox = sender as WatermarkedTextBox;
275
Debug.Assert(watermarkedTextBox != null, "The source is not an instance of a WatermarkedTextBox!");
276
bool newValue = (bool)args.NewValue;
278
//MIX-only solution, as IsEnabled is not defined on Control level
279
watermarkedTextBox.IsHitTestVisible = newValue;
280
watermarkedTextBox.IsTabStop = newValue;
281
watermarkedTextBox.IsReadOnly = !newValue;
283
watermarkedTextBox.ToggleState();
287
private void OnLostFocus(object sender, RoutedEventArgs e)
294
private void OnMouseEnter(object sender, MouseEventArgs e)
304
private void OnMouseLeave(object sender, MouseEventArgs e)
315
private void OnTextChanged(object sender, TextChangedEventArgs e)
321
private void OnWatermarkChanged()
323
if (elementContent != null)
325
Control watermarkControl = this.Watermark as Control;
326
if (watermarkControl != null)
328
watermarkControl.IsTabStop = false;
329
watermarkControl.IsHitTestVisible = false;
335
/// Called when watermark property is changed.
337
/// <param name="sender">The sender.</param>
338
/// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
339
private static void OnWatermarkPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
341
WatermarkedTextBox watermarkTextBox = sender as WatermarkedTextBox;
342
Debug.Assert(watermarkTextBox != null, "The source is not an instance of a WatermarkedTextBox!");
343
watermarkTextBox.OnWatermarkChanged();
344
watermarkTextBox.ToggleState();
348
private void SetDefaults()
351
this.Watermark = Resource.WatermarkedTextBox_DefaultWatermarkText;
354
private void SetStyle()
356
if (styleXaml == null)
358
Stream stream = typeof(WatermarkedTextBox).Assembly.GetManifestResourceStream(TemplateXamlPath);
359
Debug.Assert(stream != null, string.Format(CultureInfo.InvariantCulture, "XAML resource '{0}' is not found!", TemplateXamlPath));
360
using (StreamReader reader = new StreamReader(stream))
362
styleXaml = reader.ReadToEnd();
365
Style style = XamlReader.Load(styleXaml) as Style;
369
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
370
Justification="The control with throw Exception if transition occurs while it is not in the tree." )]
371
private void TryChangeState(Storyboard newState)
373
if (currentState == newState)
377
if (newState != null)
383
if (currentState != null)
389
//the control with throw Exception if transition occurs while it is not in the tree
394
currentState = newState;