1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.Activities.Core.Presentation
8 using System.Activities.Presentation;
9 using System.Activities.Presentation.Model;
10 using System.Activities.Presentation.View;
11 using System.Activities.Statements;
12 using System.ComponentModel;
14 using System.Windows.Data;
16 abstract class FlowSwitchLink<T> : DependencyObject, IFlowSwitchLink
18 static DependencyProperty caseProperty = DependencyProperty.Register("Case", typeof(T), typeof(FlowSwitchLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchLink<T>.OnCasePropertyChanged)));
19 static DependencyProperty isDefaultCaseProperty = DependencyProperty.Register("IsDefault", typeof(bool), typeof(FlowSwitchLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchLink<T>.OnIsDefaultCasePropertyChanged)));
21 private FlowSwitch<T> parentFlowSwitch;
22 protected bool internalChange = false;
23 protected ModelItem flowSwitchModelItem;
24 const string DefaultConnectorViewStateKey = "Default";
25 const string CaseViewStateKeyAppendString = "Connector";
26 bool internalDefaultCaseChange = false;
28 public FlowSwitchLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
30 this.flowSwitchModelItem = flowSwitchMI;
31 object flowSwitch = this.flowSwitchModelItem.GetCurrentValue();
32 this.parentFlowSwitch = (FlowSwitch<T>)this.flowSwitchModelItem.GetCurrentValue();
33 this.internalChange = true;
34 this.internalDefaultCaseChange = true;
37 this.CaseObject = caseValue;
39 this.IsDefaultCase = isDefault;
40 this.internalDefaultCaseChange = false;
41 this.internalChange = false;
44 [BrowsableAttribute(false)]
45 public ModelItem ModelItem
48 public CaseKeyValidationCallbackDelegate ValidateCaseKey
52 return (object obj, out string reason) =>
54 return GenericFlowSwitchHelper.ValidateCaseKey(obj,
55 this.flowSwitchModelItem.Properties["Cases"],
62 [BrowsableAttribute(false)]
63 public FlowNode ParentFlowSwitch
67 return this.parentFlowSwitch;
71 this.parentFlowSwitch = value as FlowSwitch<T>;
75 public bool IsDefaultCase
79 return (bool)GetValue(FlowSwitchLink<T>.isDefaultCaseProperty);
83 SetValue(FlowSwitchLink<T>.isDefaultCaseProperty, value);
88 public string CaseName
92 object value = GetValue(FlowSwitchLink<T>.caseProperty);
93 return GenericFlowSwitchHelper.GetString((T)value, typeof(T));
98 public object CaseObject
102 return GetValue(FlowSwitchLink<T>.caseProperty);
106 SetValue(FlowSwitchLink<T>.caseProperty, value);
110 [BrowsableAttribute(false)]
115 return (T)GetValue(FlowSwitchLink<T>.caseProperty);
119 SetValue(FlowSwitchLink<T>.caseProperty, value);
123 DependencyProperty CaseProperty
131 DependencyProperty IsDefaultCaseProperty
135 return isDefaultCaseProperty;
140 public Type GenericType
148 bool ContainsKey(object key)
150 return this.parentFlowSwitch.Cases.ContainsKey((T)key);
153 void OnIsDefaultPropertyChanged(DependencyPropertyChangedEventArgs e)
155 bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
157 if (!this.internalDefaultCaseChange && !isUndoRedoInProgress)
159 bool value = (bool)e.NewValue;
160 bool oldValue = (bool)e.OldValue;
164 if (object.Equals(this.flowSwitchModelItem.Properties["Default"].Value, null))
166 using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
168 ModelItem flowNodeMI = GenericFlowSwitchHelper.GetCaseModelItem(this.flowSwitchModelItem.Properties["Cases"], this.CaseObject);
169 GenericFlowSwitchHelper.RemoveCase(this.flowSwitchModelItem.Properties["Cases"], this.CaseObject);
170 this.flowSwitchModelItem.Properties["Default"].SetValue(flowNodeMI);
171 this.UpdateViewState(this.CaseName + CaseViewStateKeyAppendString, DefaultConnectorViewStateKey);
172 this.internalChange = true;
178 this.internalDefaultCaseChange = true;
179 this.IsDefaultCase = oldValue;
180 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.DefaultCaseExists));
187 using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
189 ModelItem defaultCase = this.flowSwitchModelItem.Properties["Default"].Value;
190 object uniqueCase = null;
191 string errorMessage = string.Empty;
192 Type typeArgument = typeof(T);
193 if (GenericFlowSwitchHelper.CanBeGeneratedUniquely(typeArgument))
195 string caseName = GenericFlowSwitchHelper.GetCaseName(this.flowSwitchModelItem.Properties["Cases"], typeArgument, out errorMessage);
196 if (!string.IsNullOrEmpty(errorMessage))
198 this.internalDefaultCaseChange = true;
199 this.IsDefaultCase = oldValue;
200 throw FxTrace.Exception.AsError(new InvalidOperationException(errorMessage));
202 uniqueCase = GenericFlowSwitchHelper.GetObject(caseName, typeArgument);
207 FlowSwitchCaseEditorDialog editor = new FlowSwitchCaseEditorDialog(this.flowSwitchModelItem, ((WorkflowViewElement)this.flowSwitchModelItem.View).Context, this.flowSwitchModelItem.View, SR.ChangeCaseValue, this.flowSwitchModelItem.ItemType.GetGenericArguments()[0]);
208 editor.WindowSizeToContent = SizeToContent.WidthAndHeight;
210 if (!editor.ShowOkCancel())
212 this.internalDefaultCaseChange = true;
213 this.IsDefaultCase = oldValue;
216 uniqueCase = editor.Case;
217 if (GenericFlowSwitchHelper.ContainsCaseKey(this.flowSwitchModelItem.Properties["Cases"], uniqueCase))
219 this.internalDefaultCaseChange = true;
220 this.IsDefaultCase = oldValue;
221 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidFlowSwitchCaseMessage));
225 this.flowSwitchModelItem.Properties["Default"].SetValue(null);
226 this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(FlowSwitchLabelFeature.DefaultCaseDisplayNameDefaultValue);
228 this.internalChange = true;
229 if (typeof(string) != typeof(T))
231 this.ModelItem.Properties["Case"].SetValue(uniqueCase);
232 GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], uniqueCase, defaultCase.GetCurrentValue());
236 this.ModelItem.Properties["Case"].SetValue(uniqueCase);
237 GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], uniqueCase, defaultCase.GetCurrentValue());
239 this.UpdateViewState(DefaultConnectorViewStateKey, GenericFlowSwitchHelper.GetString(uniqueCase, typeof(T)) + CaseViewStateKeyAppendString);
241 this.internalChange = false;
243 this.internalDefaultCaseChange = false;
247 this.internalDefaultCaseChange = false;
250 protected bool IsUndoRedoInProgress()
252 bool isUndoRedoInProgress;
253 WorkflowViewElement designer = (WorkflowViewElement)this.flowSwitchModelItem.View;
254 if (designer == null)
256 isUndoRedoInProgress = false;
260 isUndoRedoInProgress = designer.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress;
262 return isUndoRedoInProgress;
265 void OnCasePropertyChanged(DependencyPropertyChangedEventArgs e)
267 bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
269 if (!this.internalChange && !isUndoRedoInProgress)
271 T oldValue = (T)e.OldValue;
272 T newValue = (T)e.NewValue;
274 if (newValue is string && newValue != null)
276 newValue = (T)((object)((string)((object)newValue)).Trim());
279 string oldViewStateKey = string.Empty;
280 if (!this.ContainsKey(newValue))
282 using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
284 ModelItem flowElementMI = null;
286 flowElementMI = GenericFlowSwitchHelper.GetCaseModelItem(this.flowSwitchModelItem.Properties["Cases"], oldValue);
287 GenericFlowSwitchHelper.RemoveCase(this.flowSwitchModelItem.Properties["Cases"], oldValue);
288 oldViewStateKey = GenericFlowSwitchHelper.GetString(oldValue, typeof(T)) + CaseViewStateKeyAppendString;
290 GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], newValue, flowElementMI.GetCurrentValue());
291 //Update the viewstate for the flowswitch.
292 this.UpdateViewState(oldViewStateKey, GenericFlowSwitchHelper.GetString(newValue, typeof(T)) + CaseViewStateKeyAppendString);
293 //Making sure the value for Case is always trimmed.
294 this.internalChange = true;
295 this.ModelItem.Properties["Case"].SetValue(newValue);
301 this.internalChange = true;
302 this.CaseObject = oldValue;
303 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidFlowSwitchCaseMessage));
306 this.internalChange = false;
309 void UpdateViewState(string oldValue, string newValue)
311 EditingContext context = this.flowSwitchModelItem.GetEditingContext();
312 ViewStateService viewStateService = (ViewStateService)context.Services.GetService(typeof(ViewStateService));
313 if (viewStateService != null)
315 object viewState = viewStateService.RetrieveViewState(this.flowSwitchModelItem, oldValue);
316 if (viewState != null)
318 viewStateService.StoreViewStateWithUndo(this.flowSwitchModelItem, oldValue, null);
319 viewStateService.StoreViewStateWithUndo(this.flowSwitchModelItem, newValue, viewState);
324 static void OnCasePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
326 FlowSwitchLink<T> link = (FlowSwitchLink<T>)dependencyObject;
327 link.OnCasePropertyChanged(e);
330 static void OnIsDefaultCasePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
332 FlowSwitchLink<T> link = (FlowSwitchLink<T>)dependencyObject;
333 link.OnIsDefaultPropertyChanged(e);
336 public virtual MultiBinding CreateConnectorLabelTextBinding()
338 return new MultiBinding
340 Converter = new FlowSwitchLinkMultiValueConverter(),
341 ConverterParameter = this.CaseProperty.PropertyType,
344 new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.CaseProperty) },
345 new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.IsDefaultCaseProperty) },
351 class FlowSwitchDefaultLink<T> : FlowSwitchLink<T>, IFlowSwitchDefaultLink
353 static DependencyProperty defaultCaseDisplayNameProperty = DependencyProperty.Register(FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName, typeof(string), typeof(FlowSwitchDefaultLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchDefaultLink<T>.OnDefaultCaseDisplayNamePropertyChanged)));
355 public FlowSwitchDefaultLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
356 : base(flowSwitchMI, caseValue, isDefault)
358 this.internalChange = true;
359 this.DefaultCaseDisplayName = (string)this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].Value.GetCurrentValue();
360 this.internalChange = false;
363 public string DefaultCaseDisplayName
367 return (string)GetValue(FlowSwitchDefaultLink<T>.defaultCaseDisplayNameProperty);
371 SetValue(FlowSwitchDefaultLink<T>.defaultCaseDisplayNameProperty, value);
375 DependencyProperty DefaultCaseDisplayNameProperty
379 return defaultCaseDisplayNameProperty;
383 void OnDefaultCaseDisplayNamePropertyChanged(DependencyPropertyChangedEventArgs e)
385 bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
386 if (!this.internalChange && !isUndoRedoInProgress)
388 string newValue = (string)e.NewValue;
389 this.internalChange = true;
390 using (ModelEditingScope scope = this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchDefaultCaseDisplayNameEditingScopeDesc))
392 this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(newValue);
395 this.internalChange = false;
399 static void OnDefaultCaseDisplayNamePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
401 FlowSwitchDefaultLink<T> link = (FlowSwitchDefaultLink<T>)dependencyObject;
402 link.OnDefaultCaseDisplayNamePropertyChanged(e);
405 public override MultiBinding CreateConnectorLabelTextBinding()
407 MultiBinding result = base.CreateConnectorLabelTextBinding();
408 result.Bindings.Add(new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.DefaultCaseDisplayNameProperty) });
413 class FlowSwitchCaseLink<T> : FlowSwitchLink<T>
415 public FlowSwitchCaseLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
416 : base(flowSwitchMI, caseValue, isDefault)
420 [BrowsableAttribute(true)]
423 get { return base.Case; }
424 set { base.Case = value; }