1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
5 namespace System.Activities.Core.Presentation
8 using System.Collections.ObjectModel;
11 using System.ComponentModel;
13 using System.Diagnostics.CodeAnalysis;
14 using System.Globalization;
15 using System.Activities.Presentation.Model;
17 class CaseKeyBoxViewModel : DependencyObject
19 static readonly string Null = "(null)";
20 static readonly string Empty = "(empty)";
22 public static readonly DependencyProperty ComboBoxIsEditableProperty =
23 DependencyProperty.Register("ComboBoxIsEditable", typeof(bool), typeof(CaseKeyBoxViewModel), new UIPropertyMetadata(false));
25 public static readonly DependencyProperty ComboBoxVisibilityProperty =
26 DependencyProperty.Register("ComboBoxVisibility", typeof(Visibility), typeof(CaseKeyBoxViewModel), new UIPropertyMetadata(Visibility.Collapsed));
28 public static readonly DependencyProperty ComboBoxItemsProperty =
29 DependencyProperty.Register("ComboBoxItems", typeof(ObservableCollection<string>), typeof(CaseKeyBoxViewModel));
31 public static readonly DependencyProperty DataTemplateNameProperty =
32 DependencyProperty.Register("DataTemplateName", typeof(string), typeof(CaseKeyBoxViewModel), new UIPropertyMetadata("Label"));
34 public static readonly DependencyProperty TextProperty =
35 DependencyProperty.Register("Text", typeof(string), typeof(CaseKeyBoxViewModel), new UIPropertyMetadata(String.Empty));
37 public static readonly DependencyProperty TextBoxVisibilityProperty =
38 DependencyProperty.Register("TextBoxVisibility", typeof(Visibility), typeof(CaseKeyBoxViewModel), new UIPropertyMetadata(Visibility.Visible));
40 public const string BoxesTemplate = "Boxes";
41 public const string LabelTemplate = "Label";
43 string oldText = String.Empty;
45 public CaseKeyBoxViewModel(ICaseKeyBoxView view)
50 public bool ComboBoxIsEditable
52 get { return (bool)GetValue(ComboBoxIsEditableProperty); }
53 set { SetValue(ComboBoxIsEditableProperty, value); }
56 public ObservableCollection<string> ComboBoxItems
58 get { return (ObservableCollection<string>)GetValue(ComboBoxItemsProperty); }
59 set { SetValue(ComboBoxItemsProperty, value); }
62 public Visibility ComboBoxVisibility
64 get { return (Visibility)GetValue(ComboBoxVisibilityProperty); }
65 set { SetValue(ComboBoxVisibilityProperty, value); }
68 public string DataTemplateName
70 get { return (string)GetValue(DataTemplateNameProperty); }
71 set { SetValue(DataTemplateNameProperty, value); }
76 get { return (string)GetValue(TextProperty); }
77 set { SetValue(TextProperty, value); }
80 public Visibility TextBoxVisibility
82 get { return (Visibility)GetValue(TextBoxVisibilityProperty); }
83 set { SetValue(TextBoxVisibilityProperty, value); }
92 public bool OnEnterPressed()
94 return this.CommitChanges();
97 public void OnEscapePressed()
102 this.DataTemplateName = CaseKeyBoxViewModel.LabelTemplate;
104 this.View.OnEditCancelled();
107 public void OnLabelGotFocus()
109 this.DataTemplateName = CaseKeyBoxViewModel.BoxesTemplate;
112 public bool OnLostFocus()
114 return CommitChanges();
117 public void OnValueChanged()
119 if (this.Value is ModelItem)
121 // Since Value is a DP, this code will trigger OnValueChanged once more.
122 this.Value = ((ModelItem)this.Value).GetCurrentValue();
126 if (this.DataTemplateName != LabelTemplate && !this.IsBoxOnly)
128 this.DataTemplateName = LabelTemplate;
131 if (this.DisplayHintText)
133 this.Text = string.Empty;
136 if (this.ValueType == null)
140 if (this.ValueType.IsValueType)
142 if (this.Value == null)
144 this.Value = Activator.CreateInstance(this.ValueType);
147 if (this.Value == null)
151 else if ((this.ValueType == typeof(string)) && string.Equals(this.Value, String.Empty))
157 TypeConverter converter = XamlUtilities.GetConverter(this.ValueType);
158 Fx.Assert(converter != null, "TypeConverter is not available");
161 this.Text = converter.ConvertToString(this.Value);
163 catch (ArgumentException)
165 this.Text = this.Value.ToString();
170 public void OnValueTypeChanged()
172 if (this.ValueType == null)
176 bool isBool = this.ValueType == typeof(bool);
177 bool isEnum = this.ValueType.IsEnum;
178 if (isBool || isEnum)
180 this.ComboBoxVisibility = Visibility.Visible;
181 this.TextBoxVisibility = Visibility.Collapsed;
182 this.ComboBoxIsEditable = false;
185 this.ComboBoxItems = new ObservableCollection<string> { "True", "False" };
189 this.ComboBoxItems = new ObservableCollection<string>(Enum.GetNames(this.ValueType).ToList());
192 else if (this.ValueType.IsValueType)
194 this.ComboBoxVisibility = Visibility.Collapsed;
195 this.TextBoxVisibility = Visibility.Visible;
196 this.ComboBoxIsEditable = false;
200 this.ComboBoxVisibility = Visibility.Visible;
201 this.TextBoxVisibility = Visibility.Collapsed;
202 this.ComboBoxIsEditable = true;
203 this.ComboBoxItems = new ObservableCollection<string> { Null };
204 if (this.ValueType == typeof(string))
206 this.ComboBoxItems.Add(Empty);
212 public void SaveOldText()
214 this.oldText = this.Text;
217 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
218 Justification = "If conversion fails, the exception type is System.Exception.So we must catch all types of exceptions here.")]
219 [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
220 Justification = "Catch all exceptions to prevent crash.")]
223 object result = null;
227 result = ResolveInputText();
232 Fx.Assert(false, "Result should have been valid. Preview event handler should have handled the validation.");
237 if (this.DataTemplateName != CaseKeyBoxViewModel.LabelTemplate && !this.IsBoxOnly)
239 // this is for the case when setting this.Value to null. It looks like
240 // OnValueChanged won't get called because NULL is a default value for
241 // the CaseKeyBox instance in SwitchDesigner.
242 this.DataTemplateName = CaseKeyBoxViewModel.LabelTemplate;
244 this.View.OnValueCommitted();
249 object ResolveInputText()
251 object result = null;
252 if (this.ValueType == typeof(string))
254 if (this.Text.Equals(Null))
258 else if (this.Text.Equals(Empty))
260 result = string.Empty;
267 else if (!this.ValueType.IsValueType && this.Text.Equals(Null))
273 TypeConverter converter = XamlUtilities.GetConverter(this.ValueType);
274 Fx.Assert(converter != null, "TypeConverter is not available");
276 if (!converter.CanConvertFrom(typeof(string)) || !converter.CanConvertTo(typeof(string)))
278 throw FxTrace.Exception.AsError(new NotSupportedException(SR.NotSupportedCaseKeyStringConversion));
281 result = converter.ConvertFromString(this.Text);
282 // See if the result can be converted back to a string.
283 // For example, we have a enum Color {Black, White}.
284 // String "3" can be converted to integer 3, but integer 3
285 // cannot be converted back to a valid string for enum Color.
286 // In this case, we disallow string "3".
287 converter.ConvertToString(result);
291 if (this.CaseKeyValidationCallback != null && !this.CaseKeyValidationCallback(result, out reason))
293 throw FxTrace.Exception.AsError(new ArgumentException(reason));
299 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
300 Justification = "If conversion fails, the exception type is System.Exception.So we must catch all types of exceptions here.")]
301 [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
302 Justification = "Catch all exceptions to prevent crash.")]
303 public bool CanResolveInputText(out string reason)
305 reason = string.Empty;
318 public bool TextHasBeenChanged()
320 string normalizedOldText = this.oldText;
321 string normalizedNewText = this.Text;
323 // Tricky: this.DisplayHintText = false => This CaseKeyBox is in CaseDesigner
324 // Here, when changing value of string value type from "(empty)" to "", we must
325 // consider the text hasn't been changed, such that we don't do commit-change.
326 // We normalize the strings for empty-string situation before we do comparison.
327 if (this.ValueType == typeof(string) && !this.DisplayHintText)
329 normalizedOldText = normalizedOldText == Empty ? string.Empty : normalizedOldText;
330 normalizedNewText = normalizedNewText == Empty ? string.Empty : normalizedNewText;
333 return normalizedOldText != normalizedNewText;
336 ICaseKeyBoxView View { get; set; }
340 get { return this.View.DisplayHintText; }
345 get { return this.View.Value; }
346 set { this.View.Value = value; }
351 get { return this.View.ValueType; }
354 CaseKeyValidationCallbackDelegate CaseKeyValidationCallback
356 get { return this.View.CaseKeyValidationCallback; }
359 public void ResetText()
361 this.Text = string.Empty;
362 this.oldText = string.Empty;