~ubuntu-branches/ubuntu/karmic/moon/karmic

« back to all changes in this revision

Viewing changes to class/Microsoft.SilverlightControls/Controls/Extended/Src/WatermarkedTextBox/WatermarkedTextBox.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-14 12:01:08 UTC
  • Revision ID: james.westby@ubuntu.com-20090214120108-06539vb25vhbd8bn
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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. 
 
5
 
 
6
namespace System.Windows.Controls
 
7
 
8
    using System.Diagnostics; 
 
9
    using System.Globalization;
 
10
    using System.IO; 
 
11
    using System.Windows;
 
12
    using System.Windows.Input;
 
13
    using System.Windows.Markup; 
 
14
    using System.Windows.Media.Animation;
 
15
 
 
16
    /// <summary> 
 
17
    /// WatermarkedTextBox is a specialized form of TextBox which displays custom visuals when its contents are empty 
 
18
    /// </summary>
 
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 
 
29
    {
 
30
        #region Constants
 
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";
 
40
 
 
41
        private const string TemplateXamlPath = "System.Windows.Controls.WatermarkedTextBox.WatermarkedTextBox.xaml";
 
42
 
 
43
 
 
44
        #endregion 
 
45
 
 
46
        #region Constructor 
 
47
        /// <summary>
 
48
        /// Initializes a new instance of the <see cref="WatermarkedTextBox"/> class.
 
49
        /// </summary> 
 
50
        public WatermarkedTextBox()
 
51
        {
 
52
            SetStyle(); 
 
53
            SetDefaults(); 
 
54
 
 
55
            this.MouseEnter += OnMouseEnter; 
 
56
            this.MouseLeave += OnMouseLeave;
 
57
            this.Loaded += OnLoaded;
 
58
            this.LostFocus += OnLostFocus; 
 
59
            this.GotFocus += OnGotFocus;
 
60
            this.TextChanged += OnTextChanged;
 
61
        } 
 
62
        #endregion 
 
63
 
 
64
        #region Internal 
 
65
 
 
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;
 
78
 
 
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)
 
82
        { 
 
83
            ApplyTemplate();
 
84
            ToggleState();
 
85
        } 
 
86
 
 
87
        internal void ToggleState()
 
88
        { 
 
89
            if (IsEnabled) 
 
90
            {
 
91
                if (!hasFocus && this.Watermark != null && string.IsNullOrEmpty(Text)) 
 
92
                {
 
93
                    if (isHovered)
 
94
                    { 
 
95
                        TryChangeState(stateMouseOverWatermarked ?? stateNormalWatermarked ?? stateNormal);
 
96
                    }
 
97
                    else 
 
98
                    { 
 
99
                        TryChangeState(stateNormalWatermarked ?? stateNormal);
 
100
                    } 
 
101
                }
 
102
                else
 
103
                { 
 
104
                    if (isHovered)
 
105
                    {
 
106
                        TryChangeState(stateMouseOver ?? stateNormal); 
 
107
                    } 
 
108
                    else if (hasFocus)
 
109
                    { 
 
110
                        TryChangeState(stateFocused ?? stateNormal);
 
111
                    }
 
112
                    else 
 
113
                    {
 
114
                        TryChangeState(stateNormal);
 
115
                    } 
 
116
                } 
 
117
            }
 
118
            else 
 
119
            {
 
120
                if (this.Watermark != null && string.IsNullOrEmpty(this.Text))
 
121
                { 
 
122
                    TryChangeState(stateDisabledWatermarked ?? stateDisabled ?? stateNormalWatermarked ?? stateNormal);
 
123
                }
 
124
                else 
 
125
                { 
 
126
                    TryChangeState(stateDisabled ?? stateNormal);
 
127
                } 
 
128
            }
 
129
        }
 
130
        #endregion 
 
131
 
 
132
        #region Protected
 
133
 
 
134
        /// <summary> 
 
135
        /// Called when template is applied to the control.
 
136
        /// </summary> 
 
137
        public override void OnApplyTemplate()
 
138
        {
 
139
            base.OnApplyTemplate(); 
 
140
 
 
141
            elementRoot = ExtractTemplatePart<FrameworkElement>(ElementRootName);
 
142
            elementContent = ExtractTemplatePart<ContentControl>(ElementContentName); 
 
143
 
 
144
            OnWatermarkChanged();
 
145
 
 
146
            if (elementRoot != null)
 
147
            {
 
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); 
 
155
            }
 
156
 
 
157
 
 
158
 
 
159
            ToggleState();
 
160
        } 
 
161
 
 
162
        #endregion
 
163
 
 
164
        #region Public
 
165
 
 
166
        #region IsEnabled 
 
167
 
 
168
 
 
169
        /// <summary> 
 
170
        /// IsEnabled dependency property 
 
171
        /// </summary>
 
172
        public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register( 
 
173
            "IsEnabled", typeof(bool), typeof(WatermarkedTextBox), new PropertyMetadata(OnIsEnabledPropertyChanged));
 
174
 
 
175
 
 
176
        /// <summary>
 
177
        /// Gets or sets a value indicating whether this element is enabled in the user interface (UI).  This is a dependency property.
 
178
        /// </summary> 
 
179
        /// <value></value> 
 
180
        /// <returns>true if the element is enabled; otherwise, false. The default value is true.</returns>
 
181
        public bool IsEnabled 
 
182
        {
 
183
            get { return (bool)GetValue(IsEnabledProperty); }
 
184
            set { SetValue(IsEnabledProperty, value); } 
 
185
        }
 
186
 
 
187
        #endregion 
 
188
 
 
189
        #region ToolTip
 
190
 
 
191
        /// <summary>
 
192
        /// Gets or sets the tool-tip object that is displayed for this element
 
193
        /// in the user interface (UI). 
 
194
        /// </summary>
 
195
        public object ToolTip
 
196
        { 
 
197
            get { return ToolTipService.GetToolTip(this); } 
 
198
            set { ToolTipService.SetToolTip(this, value); }
 
199
        } 
 
200
 
 
201
        #endregion ToolTip
 
202
 
 
203
        #region Watermark
 
204
        /// <summary>
 
205
        /// Watermark dependency property 
 
206
        /// </summary> 
 
207
        public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
 
208
            "Watermark", typeof(object), typeof(WatermarkedTextBox), new PropertyMetadata(OnWatermarkPropertyChanged)); 
 
209
 
 
210
        /// <summary>
 
211
        /// Watermark content 
 
212
        /// </summary>
 
213
        /// <value>The watermark.</value>
 
214
        public object Watermark 
 
215
        { 
 
216
            get { return (object)GetValue(WatermarkProperty); }
 
217
            set { SetValue(WatermarkProperty, value); } 
 
218
        }
 
219
 
 
220
        #endregion 
 
221
 
 
222
        #endregion
 
223
 
 
224
        #region Private 
 
225
 
 
226
        private static string styleXaml; 
 
227
 
 
228
        private static T ExtractTemplatePartResource<T>(FrameworkElement root, string resourceName) where T : DependencyObject
 
229
        { 
 
230
            DependencyObject obj = (DependencyObject)root.Resources[resourceName];
 
231
            return ExtractTemplatePart<T>(resourceName, obj);
 
232
        } 
 
233
 
 
234
 
 
235
        private T ExtractTemplatePart<T>(string partName) where T : DependencyObject 
 
236
        {
 
237
            DependencyObject obj = GetTemplateChild(partName);
 
238
            return ExtractTemplatePart<T>(partName, obj); 
 
239
        }
 
240
 
 
241
 
 
242
        private static T ExtractTemplatePart<T>(string partName, DependencyObject obj) where T : DependencyObject 
 
243
        {
 
244
            Debug.Assert(obj == null || typeof(T).IsInstanceOfType(obj), 
 
245
             string.Format(CultureInfo.InvariantCulture, Resource.WatermarkedTextBox_TemplatePartIsOfIncorrectType, partName, typeof(T).Name));
 
246
            return obj as T;
 
247
        } 
 
248
 
 
249
 
 
250
 
 
251
        private void OnGotFocus(object sender, RoutedEventArgs e) 
 
252
        {
 
253
            if (IsEnabled) 
 
254
            {
 
255
                hasFocus = true;
 
256
 
 
257
                if (!string.IsNullOrEmpty(this.Text))
 
258
                {
 
259
                    Select(0, this.Text.Length); 
 
260
                } 
 
261
 
 
262
                ToggleState(); 
 
263
            }
 
264
        }
 
265
 
 
266
 
 
267
        /// <summary>
 
268
        /// Called when is enabled property is changed. 
 
269
        /// </summary> 
 
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)
 
273
        {
 
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;
 
277
 
 
278
            //MIX-only solution, as IsEnabled is not defined on Control level 
 
279
            watermarkedTextBox.IsHitTestVisible = newValue;
 
280
            watermarkedTextBox.IsTabStop = newValue; 
 
281
            watermarkedTextBox.IsReadOnly = !newValue;
 
282
 
 
283
            watermarkedTextBox.ToggleState(); 
 
284
        }
 
285
 
 
286
 
 
287
        private void OnLostFocus(object sender, RoutedEventArgs e) 
 
288
        {
 
289
            hasFocus = false; 
 
290
            ToggleState();
 
291
        }
 
292
 
 
293
 
 
294
        private void OnMouseEnter(object sender, MouseEventArgs e)
 
295
        { 
 
296
            isHovered = true; 
 
297
 
 
298
            if (!hasFocus) 
 
299
            {
 
300
                ToggleState();
 
301
            } 
 
302
        }
 
303
 
 
304
        private void OnMouseLeave(object sender, MouseEventArgs e) 
 
305
        { 
 
306
            isHovered = false;
 
307
 
 
308
            if (!hasFocus)
 
309
            {
 
310
                ToggleState(); 
 
311
            }
 
312
        }
 
313
 
 
314
 
 
315
        private void OnTextChanged(object sender, TextChangedEventArgs e)
 
316
        { 
 
317
            ToggleState();
 
318
        }
 
319
 
 
320
 
 
321
        private void OnWatermarkChanged()
 
322
        { 
 
323
            if (elementContent != null) 
 
324
            {
 
325
                Control watermarkControl = this.Watermark as Control; 
 
326
                if (watermarkControl != null)
 
327
                {
 
328
                    watermarkControl.IsTabStop = false; 
 
329
                    watermarkControl.IsHitTestVisible = false;
 
330
                }
 
331
            } 
 
332
        } 
 
333
 
 
334
        /// <summary> 
 
335
        /// Called when watermark property is changed.
 
336
        /// </summary>
 
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)
 
340
        { 
 
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();
 
345
 
 
346
        } 
 
347
 
 
348
        private void SetDefaults()
 
349
        { 
 
350
            IsEnabled = true; 
 
351
            this.Watermark = Resource.WatermarkedTextBox_DefaultWatermarkText;
 
352
        } 
 
353
 
 
354
        private void SetStyle()
 
355
        { 
 
356
            if (styleXaml == null)
 
357
            {
 
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))
 
361
                { 
 
362
                    styleXaml = reader.ReadToEnd();
 
363
                }
 
364
            } 
 
365
            Style style = XamlReader.Load(styleXaml) as Style;
 
366
            this.Style = style;
 
367
        } 
 
368
 
 
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)
 
372
        {
 
373
            if (currentState == newState) 
 
374
            {
 
375
                return;
 
376
            } 
 
377
            if (newState != null) 
 
378
            {
 
379
                if (Parent != null) 
 
380
                {
 
381
                    try
 
382
                    { 
 
383
                        if (currentState != null)
 
384
                        {
 
385
                            currentState.Stop(); 
 
386
                        } 
 
387
                        newState.Begin();
 
388
                    } 
 
389
                    //the control with throw Exception if transition occurs while it is not in the tree
 
390
                    catch
 
391
                    { 
 
392
                    }
 
393
                }
 
394
                currentState = newState; 
 
395
            } 
 
396
        }
 
397
 
 
398
        #endregion
 
399
    }
 
400
 
401