92992285fa8eaccfe06c6e3383723f1d7a6f5d44
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / Base / Core / Internal / PropertyEditing / FromExpression / Framework / ValueEditors / ChoiceEditor.cs
1 // -------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 // -------------------------------------------------------------------
4 //From \\authoring\Sparkle\Source\1.0.1083.0\Common\Source\Framework\ValueEditors
5 namespace System.Activities.Presentation.Internal.PropertyEditing.FromExpression.Framework.ValueEditors
6 {
7     using System;
8     using System.Text;
9     using System.Collections;
10     using System.ComponentModel;
11     using System.Diagnostics;
12     using System.Diagnostics.CodeAnalysis;
13     using System.Windows;
14     using System.Windows.Controls;
15     using System.Windows.Data;
16     using System.Windows.Input;
17     using System.Windows.Media;
18     using System.Windows.Controls.Primitives;
19     using System.Activities.Presentation.Internal.PropertyEditing.FromExpression.Framework.Data;
20     using System.Runtime;
21
22     // <summary>
23     // Determines the view type of the choice editor.
24     // Combo - a combo box
25     // Buttons - a set of radio buttons with icons
26     // ToggleButtons - a set of radio buttons with icons that use the ToggleIcon style, which allows separate active and inactive icons.
27     // Toggle - a single toggle, good for values that have only two choices, like Boolean
28     // </summary>
29     internal enum ChoiceEditorViewType
30     {
31         Combo,
32         Buttons,
33         ToggleButtons,
34         Toggle
35     }
36     // <summary>
37     // A ChoiceEditor selects a single item from a list of choices. Think combobox or set of radio buttons.
38     // </summary>
39     internal class ChoiceEditor : Control, INotifyPropertyChanged, IIconProvider
40     {
41         public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(ChoiceEditor.ValueChanged), null, false, UpdateSourceTrigger.Explicit));
42         public static readonly DependencyProperty ValueIndexProperty = DependencyProperty.Register("ValueIndex", typeof(int), typeof(ChoiceEditor), new FrameworkPropertyMetadata(-1, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(ChoiceEditor.ValueIndexChanged)));
43         public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(ChoiceEditor.ItemsSourceChanged)));
44         public static readonly DependencyProperty ConverterProperty = DependencyProperty.Register("Converter", typeof(TypeConverter), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None));
45
46         public static readonly DependencyProperty ViewTypeProperty = DependencyProperty.Register("ViewType", typeof(ChoiceEditorViewType), typeof(ChoiceEditor), new FrameworkPropertyMetadata(ChoiceEditorViewType.Combo, FrameworkPropertyMetadataOptions.AffectsRender));
47         public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register("IsEditable", typeof(bool), typeof(ChoiceEditor), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(ChoiceEditor.IsEditableChanged)));
48         public static readonly DependencyProperty IconResourcePrefixProperty = DependencyProperty.Register("IconResourcePrefix", typeof(string), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null));
49         public static readonly DependencyProperty IconResourceSuffixProperty = DependencyProperty.Register("IconResourceSuffix", typeof(string), typeof(ChoiceEditor), new FrameworkPropertyMetadata("Icon"));
50         public static readonly DependencyProperty IsNinchedProperty = DependencyProperty.Register("IsNinched", typeof(bool), typeof(ChoiceEditor), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(ChoiceEditor.IsNinchedChanged)));
51         public static readonly DependencyProperty ShowFullControlProperty = DependencyProperty.Register("ShowFullControl", typeof(bool), typeof(ChoiceEditor), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender, null, new CoerceValueCallback(ChoiceEditor.CoerceShowFullControl)));
52         public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(ChoiceEditor.ItemTemplateChanged)));
53         public static readonly DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register("ItemTemplateSelector", typeof(DataTemplateSelector), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(ChoiceEditor.ItemTemplateSelectorChanged)));
54         public static readonly DependencyProperty UseItemTemplateForSelectionProperty = DependencyProperty.Register("UseItemTemplateForSelection", typeof(Nullable<bool>), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null, null, new CoerceValueCallback(ChoiceEditor.CoerceUseItemTemplateForSelection)));
55
56         public static readonly DependencyProperty BorderCornerRadiusProperty = DependencyProperty.Register("BorderCornerRadius", typeof(double), typeof(ChoiceEditor), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsRender));
57         public static readonly DependencyProperty DropButtonInsetProperty = DependencyProperty.Register("DropButtonInset", typeof(Thickness), typeof(ChoiceEditor), new FrameworkPropertyMetadata(new Thickness(), FrameworkPropertyMetadataOptions.AffectsRender));
58         public static readonly DependencyProperty TextAreaInsetProperty = DependencyProperty.Register("TextAreaInset", typeof(Thickness), typeof(ChoiceEditor), new FrameworkPropertyMetadata(new Thickness(), FrameworkPropertyMetadataOptions.AffectsRender));
59         public static readonly DependencyProperty DropButtonBrushProperty = DependencyProperty.Register("DropButtonBrush", typeof(Brush), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
60         public static readonly DependencyProperty InnerCornerRadiusProperty = DependencyProperty.Register("InnerCornerRadius", typeof(double), typeof(ChoiceEditor), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsRender));
61         public static readonly DependencyProperty ButtonIconProperty = DependencyProperty.Register("ButtonIcon", typeof(ImageSource), typeof(ChoiceEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
62         public static readonly DependencyProperty IconWidthProperty = DependencyProperty.Register("IconWidth", typeof(double), typeof(ChoiceEditor), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsRender));
63         public static readonly DependencyProperty IconHeightProperty = DependencyProperty.Register("IconHeight", typeof(double), typeof(ChoiceEditor), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsRender));
64
65         public static readonly DependencyProperty BeginCommandProperty = DependencyProperty.Register("BeginCommand", typeof(ICommand), typeof(ChoiceEditor), new PropertyMetadata(null));
66         public static readonly DependencyProperty UpdateCommandProperty = DependencyProperty.Register("UpdateCommand", typeof(ICommand), typeof(ChoiceEditor), new PropertyMetadata(null));
67         public static readonly DependencyProperty CancelCommandProperty = DependencyProperty.Register("CancelCommand", typeof(ICommand), typeof(ChoiceEditor), new PropertyMetadata(null));
68         public static readonly DependencyProperty CommitCommandProperty = DependencyProperty.Register("CommitCommand", typeof(ICommand), typeof(ChoiceEditor), new PropertyMetadata(null));
69         public static readonly DependencyProperty FinishEditingCommandProperty = DependencyProperty.Register("FinishEditingCommand", typeof(ICommand), typeof(ChoiceEditor), new PropertyMetadata(null));
70
71         public static readonly DependencyProperty ComboBoxLoadingCursorProperty = DependencyProperty.Register("ComboBoxLoadingCursor", typeof(Cursor), typeof(ChoiceEditor), new PropertyMetadata(null));
72
73         // WORKAROUND this property is used in combination with a trigger to kick the combobox when it clears its bindings Avalon bug: 1756023
74         public static readonly DependencyProperty ForceBindingProperty = DependencyProperty.Register("ForceBinding", typeof(bool), typeof(ChoiceEditor), new FrameworkPropertyMetadata(false));
75
76
77         // True if the user is editing the text in an editable combo
78         private bool isTextEditing = false;
79         // True if the user is selecting a value (e.g. in a combo when the dropdown is open)
80         private bool isSelectingValue = false;
81
82         // ###################################################
83         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - BEGIN
84         // ###################################################
85
86         // True if the full editor is being shown
87         private bool isShowingFullEditor = false;
88
89         // ###################################################
90         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - END
91         // ###################################################
92
93         // Used to lock out internal changes. Do not change this directly. Use Begin/EndIgnoreInternalChangeBlock
94         private int internalChangeLockCount = 0;
95         // Used to not set commit action = lost focus when cancelling an edit
96         private int internalStringValueChangeLockCount = 0;
97         // True if changes to value should be ignored.
98         private bool ignoreValueChanges = false;
99
100         // Action to take when this control looses focus
101         private LostFocusAction lostFocusAction = LostFocusAction.None;
102         // The selected item of the internal selector. Used to determine Value
103         private object internalValue = null;
104         // The string value of the internal selector if it allows text editing
105         private string internalStringValue = String.Empty;
106
107         // A Collection view over the ItemsSource that we have been passed
108         private CollectionView collectionView = null;
109
110         [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
111         public ChoiceEditor()
112         {
113             this.CoerceValue(ChoiceEditor.UseItemTemplateForSelectionProperty);
114         }
115         public event PropertyChangedEventHandler PropertyChanged;
116  
117         // <summary>
118         // The currently selected choice
119         // </summary>
120         public object Value
121         {
122             get { return this.GetValue(ChoiceEditor.ValueProperty); }
123             set { this.SetValue(ChoiceEditor.ValueProperty, value); }
124         }
125
126         // <summary>
127         // The index of the selected choice. -1 if Value is not in the list.
128         // </summary>
129         public int ValueIndex
130         {
131             get { return (int)this.GetValue(ChoiceEditor.ValueIndexProperty); }
132             set { this.SetValue(ChoiceEditor.ValueIndexProperty, value); }
133         }
134
135         // <summary>
136         // The items source used to populate the choice
137         // </summary>
138         public IEnumerable ItemsSource
139         {
140             get { return (IEnumerable)this.GetValue(ChoiceEditor.ItemsSourceProperty); }
141             set { this.SetValue(ChoiceEditor.ItemsSourceProperty, value); }
142         }
143
144         // <summary>
145         // Converter used to convert text values to object values.
146         // </summary>
147         public TypeConverter Converter
148         {
149             get { return (TypeConverter)this.GetValue(ChoiceEditor.ConverterProperty); }
150             set { this.SetValue(ChoiceEditor.ConverterProperty, value); }
151         }
152
153         // <summary>
154         // Sets the view type of this choice. This will change the behavior of the choice.
155         // </summary>
156         public ChoiceEditorViewType ViewType
157         {
158             get { return (ChoiceEditorViewType)this.GetValue(ChoiceEditor.ViewTypeProperty); }
159             set { this.SetValue(ChoiceEditor.ViewTypeProperty, value); }
160         }
161
162         // <summary>
163         // Set to true if this choice editor should be editable. Currently only works for Combo
164         // </summary>
165         public bool IsEditable
166         {
167             get { return (bool)this.GetValue(ChoiceEditor.IsEditableProperty); }
168             set { this.SetValue(ChoiceEditor.IsEditableProperty, value); }
169         }
170
171         // <summary>
172         // The prefix put on all icon resource references before they are looked up
173         // </summary>
174         public string IconResourcePrefix
175         {
176             get { return (string)this.GetValue(ChoiceEditor.IconResourcePrefixProperty); }
177             set { this.SetValue(ChoiceEditor.IconResourcePrefixProperty, value); }
178         }
179
180         // <summary>
181         // The prefix put on all icon resource references before they are looked up
182         // </summary>
183         public string IconResourceSuffix
184         {
185             get { return (string)this.GetValue(ChoiceEditor.IconResourceSuffixProperty); }
186             set { this.SetValue(ChoiceEditor.IconResourceSuffixProperty, value); }
187         }
188
189         // <summary>
190         // True if this value editor is ninched
191         // </summary>
192         public bool IsNinched
193         {
194             get { return (bool)this.GetValue(ChoiceEditor.IsNinchedProperty); }
195             set { this.SetValue(ChoiceEditor.IsNinchedProperty, value); }
196         }
197
198         // <summary>
199         // True to show the full control instead of the optimized drawing of the control
200         // </summary>
201         public bool ShowFullControl
202         {
203             get { return (bool)this.GetValue(ChoiceEditor.ShowFullControlProperty); }
204             set { this.SetValue(ChoiceEditor.ShowFullControlProperty, value); }
205         }
206
207         public DataTemplate ItemTemplate
208         {
209             get { return (DataTemplate)this.GetValue(ChoiceEditor.ItemTemplateProperty); }
210             set { this.SetValue(ChoiceEditor.ItemTemplateProperty, value); }
211         }
212
213         public DataTemplateSelector ItemTemplateSelector
214         {
215             get { return (DataTemplateSelector)this.GetValue(ChoiceEditor.ItemTemplateSelectorProperty); }
216             set { this.SetValue(ChoiceEditor.ItemTemplateSelectorProperty, value); }
217         }
218
219         public bool UseItemTemplateForSelection
220         {
221             get { return (bool)this.GetValue(ChoiceEditor.UseItemTemplateForSelectionProperty); }
222             set { this.SetValue(ChoiceEditor.UseItemTemplateForSelectionProperty, value); }
223         }
224
225         public double BorderCornerRadius
226         {
227             get { return (double)this.GetValue(ChoiceEditor.BorderCornerRadiusProperty); }
228             set { this.SetValue(ChoiceEditor.BorderCornerRadiusProperty, value); }
229         }
230
231         public Thickness DropButtonInset
232         {
233             get { return (Thickness)this.GetValue(ChoiceEditor.DropButtonInsetProperty); }
234             set { this.SetValue(ChoiceEditor.DropButtonInsetProperty, value); }
235         }
236
237         public Thickness TextAreaInset
238         {
239             get { return (Thickness)this.GetValue(ChoiceEditor.TextAreaInsetProperty); }
240             set { this.SetValue(ChoiceEditor.TextAreaInsetProperty, value); }
241         }
242
243         public Brush DropButtonBrush
244         {
245             get { return (Brush)this.GetValue(ChoiceEditor.DropButtonBrushProperty); }
246             set { this.SetValue(ChoiceEditor.DropButtonBrushProperty, value); }
247         }
248
249         public double InnerCornerRadius
250         {
251             get { return (double)this.GetValue(ChoiceEditor.InnerCornerRadiusProperty); }
252             set { this.SetValue(ChoiceEditor.InnerCornerRadiusProperty, value); }
253         }
254
255         public ImageSource ButtonIcon
256         {
257             get { return (ImageSource)this.GetValue(ChoiceEditor.ButtonIconProperty); }
258             set { this.SetValue(ChoiceEditor.ButtonIconProperty, value); }
259         }
260
261         public double IconWidth
262         {
263             get { return (double)this.GetValue(ChoiceEditor.IconWidthProperty); }
264             set { this.SetValue(ChoiceEditor.IconWidthProperty, value); }
265         }
266
267         public double IconHeight
268         {
269             get { return (double)this.GetValue(ChoiceEditor.IconHeightProperty); }
270             set { this.SetValue(ChoiceEditor.IconHeightProperty, value); }
271         }
272
273         // <summary>
274         // Command fired when editing begins
275         // </summary>
276         public ICommand BeginCommand
277         {
278             get { return (ICommand)this.GetValue(ChoiceEditor.BeginCommandProperty); }
279             set { this.SetValue(ChoiceEditor.BeginCommandProperty, value); }
280         }
281
282         // <summary>
283         // Command fired when an edit value is updated. This command will fire after the
284         // binding has been updated.
285         // </summary>
286         public ICommand UpdateCommand
287         {
288             get { return (ICommand)this.GetValue(ChoiceEditor.UpdateCommandProperty); }
289             set { this.SetValue(ChoiceEditor.UpdateCommandProperty, value); }
290         }
291
292         // <summary>
293         // Command fired when an edit is canceled
294         // </summary>
295         public ICommand CancelCommand
296         {
297             get { return (ICommand)this.GetValue(ChoiceEditor.CancelCommandProperty); }
298             set { this.SetValue(ChoiceEditor.CancelCommandProperty, value); }
299         }
300
301         // <summary>
302         // Command fired when an edit is commited
303         // </summary>
304         public ICommand CommitCommand
305         {
306             get { return (ICommand)this.GetValue(ChoiceEditor.CommitCommandProperty); }
307             set { this.SetValue(ChoiceEditor.CommitCommandProperty, value); }
308         }
309
310         // <summary>
311         // Command fired when the editor is done editing.  At this point the host
312         // may decide to move on to the next property in the list, return focus
313         // to the design surface, or perform any other action it pleases to do.
314         // </summary>
315         public ICommand FinishEditingCommand
316         {
317             get { return (ICommand)this.GetValue(ChoiceEditor.FinishEditingCommandProperty); }
318             set { this.SetValue(ChoiceEditor.FinishEditingCommandProperty, value); }
319         }
320
321         // <summary>
322         // True if cursor should be an hourglass when loading a ComboBox popup
323         // </summary>
324         public Cursor ComboBoxLoadingCursor
325         {
326             get { return (Cursor)this.GetValue(ChoiceEditor.ComboBoxLoadingCursorProperty); }
327             set { this.SetValue(ChoiceEditor.ComboBoxLoadingCursorProperty, value); }
328         }
329
330         // <summary>
331         // Command to rotate the selection of the ChoiceEditor to the next possible item
332         // or cycle to the first if at the end of the current view.
333         // </summary>
334         public ICommand NextValueCommand
335         {
336             get
337             {
338                 return new DelegateCommand(new DelegateCommand.SimpleEventHandler(SelectNextValue));
339             }
340         }
341
342         // <summary>
343         // Command to rotate the selection of the ChoiceEditor the previously selected
344         // item in the view, or to the last item in the view if at the first item in the view.
345         // </summary>
346         public ICommand PreviousValueCommand
347         {
348             get
349             {
350                 return new DelegateCommand(new DelegateCommand.SimpleEventHandler(SelectPreviousValue));
351             }
352         }
353
354         public bool ForceBinding
355         {
356             get { return (bool)this.GetValue(ChoiceEditor.ForceBindingProperty); }
357             set { this.SetValue(ChoiceEditor.ForceBindingProperty, value); }
358         }
359
360         // <summary>
361         // This is the value internal to this control. Controls in the
362         // template of this control should bind to this.
363         // </summary>
364         public object InternalValue
365         {
366             get
367             {
368                 return this.internalValue;
369             }
370             set
371             {
372                 if (this.internalValue != value)
373                 {
374                     this.internalValue = value;
375                     if (this.ShouldCommitInternalValueChanges)
376                     {
377                         if (!this.isTextEditing)
378                         {
379                             this.CommitChange();
380                         }
381                         else
382                         {
383                             this.lostFocusAction = LostFocusAction.Commit;
384                         }
385                     }
386                     this.SendPropertyChanged("InternalValue");
387                 }
388             }
389         }
390
391         public string InternalStringValue
392         {
393             get { return this.internalStringValue; }
394             set
395             {
396                 if (!String.Equals(value, this.internalStringValue))
397                 {
398                     if (this.ShouldCommitInternalStringValueChanges && this.isTextEditing)
399                     {
400                         this.InternalValue = null;
401                         this.lostFocusAction = LostFocusAction.Commit;
402                     }
403                     this.internalStringValue = value;
404                     this.SendPropertyChanged("InternalStringValue");
405                 }
406             }
407         }
408
409         public bool InternalIsSelectingValue
410         {
411             get { return this.isSelectingValue; }
412             set
413             {
414                 if (this.isSelectingValue != value)
415                 {
416                     this.isSelectingValue = value;
417
418                     if (this.isTextEditing && !this.isSelectingValue)
419                     {
420                         //  
421                         //                          * FinishedEditingCommand in Cider does not 
422                         //                          * move focus off of the control (as we do in Sparkle) The fix is to add code to 
423                         //                          * InternalIsSelectingValue when the value goes to false (when the popup is closing) 
424                         //                          * that checks to see if there is a lostFocusAction of Commit and if so calls CommitChange()//                          
425                         LostFocusAction oldAction = this.lostFocusAction;
426                         this.lostFocusAction = LostFocusAction.None;
427                         if (oldAction == LostFocusAction.Commit)
428                         {
429                             this.CommitChange();
430                         }
431                         this.OnFinishEditing();
432                     }
433                     if (this.isSelectingValue && this.CollectionView != null)
434                     {
435                         this.BeginIgnoreExternalValueChangeBlock();
436                         try
437                         {
438                             this.ValueIndex = this.CollectionView.IndexOf(this.Value);
439                         }
440                         finally
441                         {
442                             this.EndIgnoreExternalValueChangeBlock();
443                         }
444                     }
445                     Cursor loadingCursor = this.ComboBoxLoadingCursor;
446                     if (value && this.ViewType == ChoiceEditorViewType.Combo && loadingCursor != null)
447                     {
448                         bool foundPopup = false;
449                         Mouse.OverrideCursor = loadingCursor;
450                         ComboBox comboBox = this.Template.FindName("PART_Combo", this) as ComboBox;
451                         if (comboBox != null)
452                         {
453                             Popup popup = comboBox.Template.FindName("PART_Popup", comboBox) as Popup;
454                             if (popup != null)
455                             {
456                                 foundPopup = true;
457                                 popup.Opened += new EventHandler(OnPopupLoaded);
458                             }
459                         }
460                         if (!foundPopup)
461                         {
462                             // if we couldn't set up the event handler, just return
463                             // the cursor now so they aren't stuck with an hourglass
464                             Mouse.OverrideCursor = null;
465                         }
466                     }
467                 }
468             }
469         }
470
471         // ###################################################
472         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - BEGIN
473         // ###################################################
474
475         private CollectionView CollectionView
476         {
477             get {
478                 if (collectionView == null)
479                 {
480                     IEnumerable newItems = this.ItemsSource;
481                     if (newItems != null)
482                     {
483                         this.collectionView = new CollectionView(this.ItemsSource);
484                     }
485                     else
486                     {
487                         this.collectionView = null;
488                     }
489                 }
490                 return collectionView;
491             }
492         }
493
494         // ###################################################
495         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - END
496         // ###################################################
497
498         private bool ShouldCommitInternalValueChanges
499         {
500             get { return this.internalChangeLockCount == 0; }
501         }
502
503         private bool ShouldCommitInternalStringValueChanges
504         {
505             get { return this.internalStringValueChangeLockCount == 0; }
506         }
507
508         private bool ShouldIgnoreExternalValueChanges
509         {
510             get { return this.ignoreValueChanges; }
511         }
512
513
514         public void SelectNextValue()
515         {
516             int currentIndex = this.ValueIndex;
517
518             Fx.Assert(this.CollectionView != null, "ChoiceEditor CollectionView cannot be null.");
519             if (currentIndex < 0 || currentIndex >= this.CollectionView.Count - 1)
520             {
521                 currentIndex = 0;
522             }
523             else
524             {
525                 currentIndex = currentIndex + 1;
526             }
527             this.ValueIndex = currentIndex;
528         }
529
530         public void SelectPreviousValue()
531         {
532             int currentIndex = this.ValueIndex;
533
534             Fx.Assert(this.CollectionView != null, "ChoiceEditor CollectionView cannot be null.");
535             if (currentIndex <= 0 || currentIndex > this.CollectionView.Count - 1)
536             {
537                 currentIndex = this.CollectionView.Count - 1;
538             }
539             else
540             {
541                 currentIndex = currentIndex - 1;
542             }
543             this.ValueIndex = currentIndex;
544         }
545
546         public ImageSource GetIconAsImageSource(object key, object parameter)
547         {
548             // This is the place to cache icons if these lookups are costing us too much.
549             try
550             {
551                 StringBuilder sb = new StringBuilder();
552                 string prefix = this.IconResourcePrefix;
553                 string suffix = this.IconResourceSuffix;
554                 string parameterString = parameter as string;
555
556                 if (prefix != null)
557                 {
558                     sb.Append(prefix);
559                 }
560                 sb.Append(key.ToString());
561                 if (suffix != null)
562                 {
563                     sb.Append(suffix);
564                 }
565                 if (parameterString != null)
566                 {
567                     sb.Append(parameterString);
568                 }
569
570                 object resource = this.FindResource(sb.ToString());
571                 ImageSource resourceImageSource = resource as ImageSource;
572                 return resourceImageSource;
573             }
574             catch (ResourceReferenceKeyNotFoundException)
575             {
576                 return null;
577             }
578         }
579
580         private void OnPopupLoaded(object sender, EventArgs e)
581         {
582             Popup popup = sender as Popup;
583
584             Mouse.OverrideCursor = null;
585             if (popup != null)
586             {
587                 popup.Opened -= new EventHandler(OnPopupLoaded);
588             }
589         }
590
591         private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
592         {
593             // Make sure the value actually changed
594             if (!object.Equals(e.OldValue, e.NewValue))
595             {
596                 ChoiceEditor choice = d as ChoiceEditor;
597                 if (choice != null && !choice.ShouldIgnoreExternalValueChanges)
598                 {
599                     choice.UpdateInternalValuesFromValue();
600                 }
601             }
602         }
603
604         private static void ValueIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
605         {
606             ChoiceEditor choice = d as ChoiceEditor;
607             if (choice != null && !choice.ShouldIgnoreExternalValueChanges)
608             {
609                 choice.UpdateInternalValuesFromValueIndex();
610                 choice.UpdateValueFromInternalValues();
611             }
612         }
613
614         private static void ItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
615         {
616             ChoiceEditor choice = d as ChoiceEditor;
617             if (choice != null)
618             {
619                 choice.ItemsSourceChanged();
620             }
621         }
622
623         private static void IsEditableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
624         {
625             // Make sure that the internal values are up to date now that we know we are editable or not.
626             ChoiceEditor choice = d as ChoiceEditor;
627             if (choice != null && !choice.ShouldIgnoreExternalValueChanges)
628             {
629                 choice.UpdateInternalValuesFromValue();
630             }
631         }
632
633         private static void IsNinchedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
634         {
635             ChoiceEditor choice = d as ChoiceEditor;
636             if (choice != null && !choice.ShouldIgnoreExternalValueChanges)
637             {
638                 choice.UpdateInternalValuesFromValue();
639             }
640         }
641
642         private static object CoerceShowFullControl(DependencyObject target, object value)
643         {
644             ChoiceEditor choice = target as ChoiceEditor;
645             if (choice != null && value is bool)
646             {
647                 bool boolValue = (bool)value;
648
649                 // ###################################################
650                 // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - BEGIN
651                 // ###################################################
652
653                 choice.isShowingFullEditor = boolValue;
654                 choice.CheckUpdateValueIndex(false);
655
656                 // ###################################################
657                 // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - END
658                 // ###################################################
659
660                 // If we are text editing force the full control to stay showing.
661                 if (!boolValue)
662                 {
663                     return choice.isTextEditing;
664                 }
665             }
666
667             return value;
668         }
669
670         private static void ItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
671         {
672             ChoiceEditor choice = d as ChoiceEditor;
673             if (choice != null)
674             {
675                 choice.CoerceValue(ChoiceEditor.UseItemTemplateForSelectionProperty);
676             }
677         }
678
679         private static void ItemTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
680         {
681             ChoiceEditor choice = d as ChoiceEditor;
682             if (choice != null)
683             {
684                 choice.CoerceValue(ChoiceEditor.UseItemTemplateForSelectionProperty);
685             }
686         }
687
688         private static object CoerceUseItemTemplateForSelection(DependencyObject target, object value)
689         {
690             ChoiceEditor choice = target as ChoiceEditor;
691             if (choice != null)
692             {
693                 if (value == null)
694                 {
695                     return choice.ItemTemplate != null || choice.ItemTemplateSelector != null;
696                 }
697             }
698             return value;
699         }
700
701         private void SendPropertyChanged(string propertyName)
702         {
703             if (this.PropertyChanged != null)
704             {
705                 this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
706             }
707         }
708
709         protected override void OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
710         {
711             base.OnPreviewGotKeyboardFocus(e);
712             FrameworkElement element = e.NewFocus as FrameworkElement;
713             if (element != null && element.Name.Equals("PART_EditableTextBox", StringComparison.Ordinal))
714             {
715                 this.isTextEditing = true;
716             }
717         }
718
719         // ###################################################
720         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - BEGIN
721         // ###################################################
722         // CIDER needs to override the Keydown behavior : 
723         //   
724         //          * The problem here is just a difference in expectation for control behavior 
725         //          * between the two products (CIDER AND BLEND). The fix is entirely in OnPreviewKeyDown 
726         //          * a.    Remove the condition that we handle navigation keys only when the popup is open
727         //          * b.    Add logic that forces a commit when a navigation happens (you could optionally only do the commit when the popup is closed, but I�m not sure what the desired behavior is here). You may or may not want to limit this behavior to editable ChoiceEditors as well.//          
728
729         protected override void OnPreviewKeyDown(KeyEventArgs e)
730         {
731             bool commitChange = false;
732             bool finishEditing = false;
733
734             bool markHandled = ValueEditorUtils.GetHandlesCommitKeys(this);
735
736             if (e.Key == Key.Return || e.Key == Key.Enter)
737             {
738                 e.Handled |= markHandled;
739
740                 commitChange = true;
741
742                 finishEditing = (e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == 0;
743                 //Hide dropdown on excape key
744                 HideDropDown();
745             }
746             else if (e.Key == Key.Escape)
747             {
748                 e.Handled |= markHandled;
749
750                 LostFocusAction savedAction = this.lostFocusAction;
751                 this.lostFocusAction = LostFocusAction.None;
752                 if (savedAction != LostFocusAction.None)
753                 {
754                     this.CancelChange();
755                 }
756
757                 //Hide dropdown on excape key
758                 HideDropDown();
759                 this.OnFinishEditing();
760             }
761             // Only pay attention to navigation keys if we are selecting a value from the popup
762             if (this.CollectionView != null && !this.CollectionView.IsEmpty)
763             {
764                 bool navigated = false;
765                 if (e.Key == Key.Up || (!this.IsEditable && e.Key == Key.Left))
766                 {
767                     this.SelectPreviousValue();
768                     navigated = true;
769                 }
770                 else if (e.Key == Key.Down || (!this.IsEditable && e.Key == Key.Right))
771                 {
772                     this.SelectNextValue();
773                     navigated = true;
774                 }
775                 else if (!this.IsEditable && e.Key == Key.Home)
776                 {
777                     this.ValueIndex = 0;
778                     navigated = true;
779                 }
780                 else if (!this.IsEditable && e.Key == Key.End)
781                 {
782                     this.ValueIndex = this.CollectionView.Count - 1;
783                     navigated = true;
784                 }
785
786                 if (navigated)
787                 {
788                     this.lostFocusAction = LostFocusAction.Commit;
789                     e.Handled = true;
790                     ComboBox comboBox = this.Template.FindName("_comboChoiceEditor", this) as ComboBox;
791                     if (!comboBox.IsDropDownOpen)
792                     {
793                         commitChange = true;
794                     }
795                 }
796             }
797
798             if (commitChange)
799             {
800                 LostFocusAction savedAction = this.lostFocusAction;
801                 this.lostFocusAction = LostFocusAction.None;
802                 if (savedAction == LostFocusAction.Commit)
803                 {
804                     this.CommitChange();
805                 }
806             }
807             if (finishEditing)
808             {
809                 this.OnFinishEditing();
810             }
811             base.OnPreviewKeyDown(e);
812         }
813
814         // ###################################################
815         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - END
816         // ###################################################
817
818         // ###################################################
819         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - BEGIN
820         // ###################################################
821         private void HideDropDown()
822         {
823             ComboBox comboBox = this.Template.FindName("_comboChoiceEditor", this) as ComboBox;
824             if (comboBox != null && comboBox.IsDropDownOpen)
825             {
826                 comboBox.IsDropDownOpen = false;
827             }
828         }
829
830         // When the focus is lost by clicking ouside the choice-editor
831         // we dont get a preview message.
832         // The string edtior has OnLostKeyboardFocus and hence we imitate the 
833         // same behavior.
834         protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
835         {
836             base.OnLostKeyboardFocus(e);
837
838             FrameworkElement element = e.OldFocus as FrameworkElement;
839             if (element != null && element.Name.Equals("PART_EditableTextBox", StringComparison.Ordinal))
840             {
841                 this.HandleLostFocus();
842             }
843         }
844         // #################################################
845         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - END
846         // #################################################
847
848
849         protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
850         {
851             base.OnPreviewLostKeyboardFocus(e);
852             FrameworkElement element = e.OldFocus as FrameworkElement;
853             if (element != null && element.Name.Equals("PART_EditableTextBox", StringComparison.Ordinal))
854             {
855                 this.HandleLostFocus();
856             }
857         }
858
859         private void HandleLostFocus()
860         {
861             if (this.isTextEditing)
862             {
863                 LostFocusAction oldLostFocusAction = this.lostFocusAction;
864                 this.lostFocusAction = LostFocusAction.None;
865                 this.isTextEditing = false;
866
867
868                 if (oldLostFocusAction == LostFocusAction.Commit)
869                 {
870                     this.CommitChange();
871                 }
872                 else if (oldLostFocusAction == LostFocusAction.Cancel)
873                 {
874                     this.CancelChange();
875                 }
876
877                 this.CoerceValue(ChoiceEditor.ShowFullControlProperty);
878             }
879         }
880
881         protected override void OnRender(DrawingContext drawingContext)
882         {
883             base.OnRender(drawingContext);
884             if (this.ViewType == ChoiceEditorViewType.Combo && !this.ShowFullControl)
885             {
886                 double borderCornerRadius = this.BorderCornerRadius;
887                 Thickness dropButtonInset = this.DropButtonInset;
888                 Thickness textAreaInset = this.TextAreaInset;
889                 Brush dropButtonBrush = this.DropButtonBrush;
890                 double innerCornerRadius = this.InnerCornerRadius;
891                 ImageSource buttonIcon = this.ButtonIcon;
892                 double iconWidth = this.IconWidth;
893                 double iconHeight = this.IconHeight;
894
895                 // Draw something that looks like an Expression combo
896                 Rect fullRect = new Rect(0d, 0d, this.ActualWidth, this.ActualHeight);
897
898                 if (RenderUtils.DrawInscribedRoundedRect(drawingContext, this.BorderBrush, null, fullRect, borderCornerRadius))
899                 {
900                     Rect innerRect = RenderUtils.CalculateInnerRect(fullRect, 0);
901                     double dropButtonLeft = (innerRect.Right > textAreaInset.Right ? innerRect.Right - textAreaInset.Right : 0d) + dropButtonInset.Left;
902                     double dropButtonTop = innerRect.Top + dropButtonInset.Top;
903                     double dropButtonRight = innerRect.Right - dropButtonInset.Right;
904                     double dropButtonBottom = innerRect.Bottom - dropButtonInset.Bottom;
905
906                     RenderUtils.DrawInscribedRoundedRect(drawingContext, dropButtonBrush, null, new Rect(new Point(dropButtonLeft, dropButtonTop), new Point(dropButtonRight, dropButtonBottom)), innerCornerRadius);
907                     if (buttonIcon != null)
908                     {
909                         double buttonCenterX = dropButtonLeft + (dropButtonRight - dropButtonLeft) / 2d;
910                         double buttonCenterY = dropButtonTop + (dropButtonBottom - dropButtonTop) / 2d;
911                         drawingContext.DrawImage(buttonIcon, new Rect(new Point(buttonCenterX - iconWidth / 2d, buttonCenterY - iconHeight / 2d), new Point(buttonCenterX + iconWidth / 2d, buttonCenterY + iconHeight / 2d)));
912                     }
913
914                     double textAreaLeft = innerRect.Left + textAreaInset.Left;
915                     double textAreaTop = innerRect.Top + textAreaInset.Top;
916                     double textAreaRight = innerRect.Right > textAreaInset.Right ? innerRect.Right - textAreaInset.Right : textAreaLeft;
917                     double textAreaBottom = innerRect.Bottom - textAreaInset.Bottom;
918
919                     RenderUtils.DrawInscribedRoundedRect(drawingContext, this.Background, null, new Rect(new Point(textAreaLeft, textAreaTop), new Point(textAreaRight, textAreaBottom)), innerCornerRadius);
920                 }
921             }
922         }
923
924         protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
925         {
926             this.BeginNoCommitInternalValueChangeBlock();
927             // WORKAROUND Turn off bindings on the internal combo while the template is udpating. This works around Avalon bug: 1756023
928             this.ForceBinding = false;
929             base.OnTemplateChanged(oldTemplate, newTemplate);
930         }
931
932         public override void OnApplyTemplate()
933         {
934             base.OnApplyTemplate();
935             // WORKAROUND Force the bindings on our internal combo (if there is one) to update. This works around Avalon bug: 1756023
936             this.ForceBinding = true;
937
938             this.EndNoCommitInternalValueChangeBlock();
939
940             this.HandleLostFocus();
941         }
942
943         private void CommitChange()
944         {
945             ValueEditorUtils.ExecuteCommand(this.BeginCommand, this, null);
946
947             if (this.UpdateValueFromInternalValues())
948             {
949                 // We need to update both the binding on the value property and the valueindex property
950                 // so that the value does not bounce around when we commit.
951                 ValueEditorUtils.UpdateBinding(this, ChoiceEditor.ValueProperty, UpdateBindingType.Source);
952                 ValueEditorUtils.UpdateBinding(this, ChoiceEditor.ValueIndexProperty, UpdateBindingType.Source);
953                 ValueEditorUtils.ExecuteCommand(this.CommitCommand, this, null);
954                 ValueEditorUtils.UpdateBinding(this, ChoiceEditor.ValueProperty, UpdateBindingType.Target);
955                 ValueEditorUtils.UpdateBinding(this, ChoiceEditor.ValueIndexProperty, UpdateBindingType.Target);
956             }
957             else
958             {
959                 this.CancelStartedChange();
960             }
961
962             this.lostFocusAction = LostFocusAction.None;
963         }
964
965         private void CancelChange()
966         {
967             ValueEditorUtils.ExecuteCommand(this.BeginCommand, this, null);
968             this.CancelStartedChange();
969         }
970
971         private void CancelStartedChange()
972         {
973             // Revert External values
974             ValueEditorUtils.UpdateBinding(this, ChoiceEditor.ValueProperty, UpdateBindingType.Target);
975             ValueEditorUtils.UpdateBinding(this, ChoiceEditor.ValueIndexProperty, UpdateBindingType.Target);
976             this.UpdateInternalValuesFromValue();
977             ValueEditorUtils.ExecuteCommand(this.CancelCommand, this, null);
978         }
979
980         private void OnFinishEditing()
981         {
982             ICommand finishedEditingCommand = this.FinishEditingCommand;
983             if (finishedEditingCommand != null)
984             {
985                 ValueEditorUtils.ExecuteCommand(finishedEditingCommand, this, null);
986             }
987             else
988             {
989                 Keyboard.Focus(null);
990             }
991         }
992
993         private void ItemsSourceChanged()
994         {
995             // The collection just changed, so we need to make sure that things are in [....]
996
997             // ###################################################
998             // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - BEGIN
999             // ###################################################
1000             this.collectionView = null;
1001             // ###################################################
1002             // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - end
1003             // ###################################################
1004
1005             this.UpdateInternalValuesFromValue();
1006             this.UpdateValueFromInternalValues();
1007         }
1008
1009         private int IndexOf(object item)
1010         {
1011             if (this.CollectionView != null)
1012             {
1013                 return this.CollectionView.IndexOf(item);
1014             }
1015             else
1016             {
1017                 return -1;
1018             }
1019         }
1020
1021         private object GetItemAt(int index)
1022         {
1023             if (this.CollectionView != null)
1024             {
1025                 return this.CollectionView.GetItemAt(index);
1026             }
1027             else
1028             {
1029                 return null;
1030             }
1031         }
1032
1033         protected void UpdateInternalValuesFromValue()
1034         {
1035             this.BeginNoCommitInternalValueChangeBlock();
1036             this.BeginNoCommitInternalStringValueChangeBlock();
1037             try
1038             {
1039                 if (!this.IsNinched)
1040                 {
1041                     this.InternalValue = this.Value;
1042                 }
1043                 else
1044                 {
1045                     this.InternalValue = null;
1046                 }
1047
1048                 if (this.IsEditable)
1049                 {
1050                     string newStringValue = String.Empty;
1051                     if (this.InternalValue != null && !this.IsNinched)
1052                     {
1053                         TypeConverter converter = this.Converter;
1054                         if (converter != null && converter.CanConvertFrom(this.InternalValue.GetType()))
1055                         {
1056                             newStringValue = converter.ConvertToString(this.InternalValue);
1057                         }
1058                         else
1059                         {
1060                             newStringValue = this.InternalValue.ToString();
1061                         }
1062                     }
1063
1064                     this.InternalStringValue = newStringValue;
1065                 }
1066             }
1067             finally
1068             {
1069                 this.EndNoCommitInternalStringValueChangeBlock();
1070                 this.EndNoCommitInternalValueChangeBlock();
1071             }
1072         }
1073
1074         public void UpdateInternalValuesFromValueIndex()
1075         {
1076             this.BeginNoCommitInternalValueChangeBlock();
1077             this.BeginNoCommitInternalStringValueChangeBlock();
1078             try
1079             {
1080                 this.InternalValue = this.GetItemAt(this.ValueIndex);
1081             }
1082             finally
1083             {
1084                 this.EndNoCommitInternalStringValueChangeBlock();
1085                 this.EndNoCommitInternalValueChangeBlock();
1086             }
1087         }
1088
1089         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Propagating the error might cause VS to crash")]
1090         [SuppressMessage("Reliability", "Reliability108", Justification = "Propagating the error might cause VS to crash")]
1091         protected bool UpdateValueFromInternalValues()
1092         {
1093             this.BeginIgnoreExternalValueChangeBlock();
1094             try
1095             {
1096                 if (!this.IsEditable)
1097                 {
1098                     this.Value = this.InternalValue;
1099                 }
1100                 else
1101                 {
1102                     if (this.InternalValue != null)
1103                     {
1104                         this.Value = this.InternalValue;
1105                     }
1106                     else
1107                     {
1108                         string stringValue = this.InternalStringValue;
1109                         // Try to parse a new value from the string value
1110                         if (stringValue != null)
1111                         {
1112                             TypeConverter converter = this.Converter;
1113                             object newValue = null;
1114                             if (converter != null)
1115                             {
1116                                 try
1117                                 {
1118                                     newValue = converter.ConvertFromString(stringValue);
1119                                 }
1120                                 catch (Exception)
1121                                 {
1122                                     // Have to catch Exception here because Various of these converters (e.g. DoubleConverter) will throw it.
1123                                     // Do nothing since newValue should still be null;
1124                                     return false;
1125                                 }
1126                             }
1127                             else
1128                             {
1129                                 newValue = stringValue;
1130                             }
1131
1132                             this.Value = newValue;
1133
1134                             // At this point it is possible that the value that we just set is out of [....] with the internal value
1135                             if (newValue != this.InternalValue)
1136                             {
1137                                 this.UpdateInternalValuesFromValue();
1138                             }
1139                         }
1140                     }
1141
1142                 }
1143             }
1144             finally
1145             {
1146                 this.EndIgnoreExternalValueChangeBlock();
1147             }
1148
1149             CheckUpdateValueIndex(true);
1150             return true;
1151         }
1152
1153         protected void BeginNoCommitInternalValueChangeBlock()
1154         {
1155             this.internalChangeLockCount++;
1156         }
1157
1158         // ###################################################
1159         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - BEGIN
1160         // ###################################################
1161
1162         // <summary>
1163         // Updates the value index for the current value, but
1164         // only if necessary.
1165         // </summary>
1166         private void CheckUpdateValueIndex(bool sourceChanged)
1167         {
1168
1169             BeginIgnoreExternalValueChangeBlock();
1170             try
1171             {
1172                 // Check if we need to update the value index.
1173                 // We don't need to if we're a combo box and
1174                 // we're not showing the drop-down.
1175
1176                 if (ViewType != ChoiceEditorViewType.Combo || this.isShowingFullEditor)
1177                 {
1178                     if (sourceChanged || ReadLocalValue(ValueIndexProperty) == DependencyProperty.UnsetValue)
1179                     {
1180                         ValueIndex = IndexOf(Value);
1181                     }
1182                 }
1183                 else
1184                 {
1185                     ClearValue(ValueIndexProperty);
1186                 }
1187             }
1188             finally
1189             {
1190                 EndIgnoreExternalValueChangeBlock();
1191             }
1192         }
1193
1194         // ###################################################
1195         // CIDER-SPECIFIC CHANGE IN NEED OF PORTING - END
1196         // ###################################################
1197
1198         protected void EndNoCommitInternalValueChangeBlock()
1199         {
1200             this.internalChangeLockCount--;
1201             Fx.Assert(this.internalChangeLockCount >= 0, "internalChangeLockCount should be positive");
1202         }
1203
1204         protected void BeginNoCommitInternalStringValueChangeBlock()
1205         {
1206             this.internalStringValueChangeLockCount++;
1207         }
1208
1209         protected void EndNoCommitInternalStringValueChangeBlock()
1210         {
1211             this.internalStringValueChangeLockCount--;
1212             Fx.Assert(this.internalStringValueChangeLockCount >= 0, "internalStringValueChangeLockCount should be positive");
1213         }
1214
1215         protected void BeginIgnoreExternalValueChangeBlock()
1216         {
1217             Fx.Assert(this.ignoreValueChanges == false, "ignoreValueChanges should be false");
1218             this.ignoreValueChanges = true;
1219         }
1220
1221         protected void EndIgnoreExternalValueChangeBlock()
1222         {
1223             Fx.Assert(this.ignoreValueChanges == true, "ignoreValueChanges should be false");
1224             this.ignoreValueChanges = false;
1225         }
1226
1227
1228         enum LostFocusAction
1229         {
1230             None,
1231             Commit,
1232             Cancel
1233         }
1234
1235     }
1236 }