1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.Activities.Presentation.View
8 using System.Activities.Presentation.Annotations;
9 using System.Activities.Presentation.Converters;
10 using System.Activities.Presentation.Expressions;
11 using System.Activities.Presentation.Hosting;
12 using System.Activities.Presentation.Model;
13 using System.Activities.Presentation.PropertyEditing;
14 using System.Collections;
15 using System.Collections.Generic;
16 using System.Collections.ObjectModel;
17 using System.Collections.Specialized;
18 using System.ComponentModel;
19 using System.Diagnostics.CodeAnalysis;
20 using System.Globalization;
22 using System.Reflection;
25 using System.Windows.Controls;
26 using System.Windows.Controls.Primitives;
27 using System.Windows.Input;
28 using System.Windows.Threading;
31 partial class ArgumentDesigner
33 public static readonly DependencyProperty ContextProperty = DependencyProperty.Register(
35 typeof(EditingContext),
36 typeof(ArgumentDesigner),
37 new FrameworkPropertyMetadata(null, OnContextChanged));
39 public static readonly DependencyProperty ActivitySchemaProperty = DependencyProperty.Register(
42 typeof(ArgumentDesigner),
43 new FrameworkPropertyMetadata(OnActivitySchemaChanged));
45 public static readonly RoutedEvent ArgumentCollectionChangedEvent = EventManager.RegisterRoutedEvent(
46 "ArgumentCollectionChanged",
47 RoutingStrategy.Bubble,
48 typeof(RoutedEventHandler),
49 typeof(ArgumentDesigner));
51 static readonly string DefaultArgumentName = "argument";
52 static readonly string Members = "Properties";
53 static readonly string ArgumentNamePropertyName = "Name";
55 ObservableCollection<DesignTimeArgument> argumentWrapperCollection = new ObservableCollection<DesignTimeArgument>();
57 bool isCollectionLoaded = false;
58 bool isDataGridPopulating = false;
59 ModelItem lastSelection;
60 bool isSelectionChangeInternal = false;
61 ArgumentToExpressionConverter argumentToExpressionConverter;
62 DataGridHelper dgHelper;
64 public ArgumentDesigner()
66 InitializeComponent();
68 this.dgHelper = new DataGridHelper(this.argumentsDataGrid, this);
69 this.dgHelper.Context = this.Context;
70 this.dgHelper.AddNewRowContent = (string)this.FindResource("addNewArgumentTitle");
71 this.dgHelper.AddNewRowCommand = DesignerView.CreateArgumentCommand;
72 this.dgHelper.ResolveDynamicTemplateCallback = this.OnResolveDynamicContentTemplate;
73 this.dgHelper.LoadDynamicContentDataCallback = this.OnShowExtendedValueEditor;
74 this.dgHelper.LoadCustomPropertyValueEditorCallback = this.OnLoadExtendedValueEditor;
76 this.argumentsDataGrid.SelectionChanged += OnDataGridArgumentSelected;
77 this.argumentsDataGrid.GotFocus += OnDataGridArgumentSelected;
79 this.argumentWrapperCollection.CollectionChanged += OnArgumentWrapperCollectionChanged;
80 this.argumentsDataGrid.ItemsSource = this.argumentWrapperCollection;
82 this.argumentsDataGrid.LayoutUpdated += OnArgumentDataGridLayoutUpdated;
85 public event RoutedEventHandler ArgumentCollectionChanged
89 AddHandler(ArgumentCollectionChangedEvent, value);
93 RemoveHandler(ArgumentCollectionChangedEvent, value);
98 public ModelItem ActivitySchema
100 get { return (ModelItem)GetValue(ActivitySchemaProperty); }
101 set { SetValue(ActivitySchemaProperty, value); }
104 public EditingContext Context
106 get { return (EditingContext)GetValue(ContextProperty); }
107 set { SetValue(ContextProperty, value); }
110 internal ArgumentToExpressionConverter ArgumentToExpressionConverter
114 if (null == this.argumentToExpressionConverter)
116 this.argumentToExpressionConverter = new ArgumentToExpressionConverter();
118 return this.argumentToExpressionConverter;
122 public bool CreateNewArgumentWrapper()
126 if (null != this.ActivitySchema)
128 DynamicActivityProperty property = new DynamicActivityProperty()
130 Name = this.GetDefaultName(),
131 Type = this.GetDefaultType(),
133 DesignTimeArgument wrapper = null;
134 using (ModelEditingScope scope = this.ActivitySchema.BeginEdit((string)this.FindResource("addNewArgumentDescription")))
136 ModelItem argument = this.GetArgumentCollection().Add(property);
137 wrapper = new DesignTimeArgument(argument, this);
138 this.argumentWrapperCollection.Add(wrapper);
142 this.dgHelper.BeginRowEdit(wrapper);
147 ModelItemCollection GetArgumentCollection()
149 if (this.ActivitySchema != null)
151 Fx.Assert(this.ActivitySchema.Properties[Members] != null, "Members collection not found!");
152 return this.ActivitySchema.Properties[Members].Collection;
158 string GetDefaultName()
160 ModelItemCollection argumentCollection = this.GetArgumentCollection();
161 return argumentCollection.GetUniqueName(ArgumentDesigner.DefaultArgumentName, (arg) => ((string)arg.Properties["Name"].ComputedValue));
164 Type GetDefaultType()
166 return typeof(InArgument<string>);
171 if (!this.isCollectionLoaded)
173 this.argumentsDataGrid.ItemsSource = null;
174 this.argumentWrapperCollection.All(p => { p.Dispose(); return true; });
175 this.argumentWrapperCollection.Clear();
176 ModelItemCollection arguments = this.GetArgumentCollection();
177 if (null != arguments)
179 foreach (ModelItem argument in arguments)
181 this.argumentWrapperCollection.Add(new DesignTimeArgument(argument, this));
184 this.argumentsDataGrid.ItemsSource = this.argumentWrapperCollection;
185 this.isCollectionLoaded = true;
189 void StoreLastSelection()
191 if (!this.isSelectionChangeInternal)
193 ModelItem current = this.Context.Items.GetValue<Selection>().PrimarySelection;
194 if (null == current || !typeof(DesignTimeArgument).IsAssignableFrom(current.ItemType))
196 this.lastSelection = current;
201 void OnArgumentTypeTypePresenterLoaded(object sender, RoutedEventArgs args)
203 TypePresenter argumentTypeTypePresenter = ((TypePresenter)sender);
204 argumentTypeTypePresenter.Filter = ((DesignTimeArgument)argumentTypeTypePresenter.DataContext).Filter;
205 DataGridHelper.OnEditingControlLoaded(sender, args);
208 void OnArgumentTypeTypePresenterUnloaded(object sender, RoutedEventArgs args)
210 DataGridHelper.OnEditingControlUnloaded(sender, args);
213 internal void SelectArgument(ModelItem argument)
215 this.Dispatcher.BeginInvoke(new Action(() =>
217 foreach (object item in this.argumentsDataGrid.Items)
219 if (item is DesignTimeArgument)
221 if (object.ReferenceEquals(((DesignTimeArgument)item).ReflectedObject, argument))
223 this.argumentsDataGrid.SelectedItem = item;
224 this.argumentsDataGrid.ScrollIntoView(item, null);
228 }), DispatcherPriority.ApplicationIdle);
231 void OnDataGridArgumentSelected(object sender, RoutedEventArgs e)
233 if (null != this.Context && !this.isSelectionChangeInternal)
235 this.isSelectionChangeInternal = true;
236 DesignTimeArgument argument = this.dgHelper.SelectedItem<DesignTimeArgument>();
237 if (null != argument)
239 this.Context.Items.SetValue(new Selection(argument.Content));
243 // clear arguments in selection
244 Selection oldSelection = this.Context.Items.GetValue<Selection>();
245 List<ModelItem> newSelection = new List<ModelItem>();
246 if (oldSelection != null && oldSelection.SelectionCount > 0)
248 foreach (ModelItem item in oldSelection.SelectedObjects)
250 if (item.ItemType != typeof(DesignTimeArgument))
252 newSelection.Add(item);
256 this.Context.Items.SetValue(new Selection(newSelection));
258 this.isSelectionChangeInternal = false;
262 void OnArgumentDataGridLayoutUpdated(object sender, EventArgs e)
264 if (this.isDataGridPopulating)
266 this.isDataGridPopulating = false;
267 Mouse.OverrideCursor = null;
271 void OnActivitySchemaChanged(ModelItem newSchemaItem)
273 this.isCollectionLoaded = false;
275 if (null != newSchemaItem && null != newSchemaItem.Properties[Members])
277 //lazy initialization, wait till it is visible
278 if (this.Visibility == Visibility.Visible)
285 void OnContextChanged()
287 if (null != this.Context)
289 this.Context.Items.Subscribe<Selection>(new SubscribeContextCallback<Selection>(OnItemSelected));
291 this.dgHelper.Context = this.Context;
294 void OnItemSelected(Selection selection)
296 if (!this.isSelectionChangeInternal)
298 this.StoreLastSelection();
300 bool selectedArgumentIsInSelection = false;
302 DesignTimeArgument selectedArgument = this.argumentsDataGrid.SelectedItem as DesignTimeArgument;
303 if (selectedArgument != null)
305 foreach (ModelItem item in selection.SelectedObjects)
307 if (object.ReferenceEquals(selectedArgument, item.GetCurrentValue()))
309 selectedArgumentIsInSelection = true;
314 if (!selectedArgumentIsInSelection)
316 this.argumentsDataGrid.SelectedItem = null;
321 void OnVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
323 if (this.Dispatcher.HasShutdownStarted)
328 if ((Boolean)e.NewValue == true)
330 // Changing cursor as Populate() might take long to run. Cursor will be restored when DataGrid.LayoutUpdated fires.
331 this.isDataGridPopulating = true;
332 Mouse.OverrideCursor = Cursors.Wait;
334 this.StoreLastSelection();
339 if (this.argumentsDataGrid.SelectedItem != null)
341 // Clear argument selection, if possible, restore last selection.
342 Selection restoredSelection = null == this.lastSelection ? new Selection() : new Selection(this.lastSelection);
343 this.isSelectionChangeInternal = true;
344 this.Context.Items.SetValue(restoredSelection);
345 this.argumentsDataGrid.SelectedItem = null;
346 this.isSelectionChangeInternal = false;
351 void OnArgumentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
353 //we need to track argument collection changes caused by undo/redo stack -
354 //in such case, we have to add/remove corresponding items from wrapper collection
355 bool isUndoRedoInProgress = this.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress;
356 if (isUndoRedoInProgress)
360 case NotifyCollectionChangedAction.Add:
361 foreach (ModelItem argument in e.NewItems)
363 var wrapper = this.argumentWrapperCollection
364 .FirstOrDefault(p => (ModelItem.Equals(p.ReflectedObject, argument)));
368 wrapper = new DesignTimeArgument(argument, this);
369 this.argumentWrapperCollection.Add(wrapper);
374 case NotifyCollectionChangedAction.Remove:
375 foreach (ModelItem argument in e.OldItems)
377 var wrapper = this.argumentWrapperCollection.FirstOrDefault(p => ModelItem.Equals(p.ReflectedObject, argument));
380 this.argumentWrapperCollection.Remove(wrapper);
387 void OnArgumentWrapperCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
389 bool isUndoRedoInProgress = this.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress;
392 case NotifyCollectionChangedAction.Remove:
393 foreach (DesignTimeArgument arg in e.OldItems)
395 this.ClearCaseInsensitiveDuplicates(arg.GetArgumentName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue);
396 if (!isUndoRedoInProgress)
398 ModelItemCollection collection = (ModelItemCollection)arg.ReflectedObject.Parent;
399 collection.Remove(arg.ReflectedObject);
404 case NotifyCollectionChangedAction.Add:
405 foreach (DesignTimeArgument arg in e.NewItems)
407 this.CheckCaseInsensitiveDuplicates(arg.GetArgumentName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue);
413 bool OnResolveDynamicContentTemplate(ResolveTemplateParams resolveParams)
415 var argument = (DesignTimeArgument)resolveParams.Cell.DataContext;
417 //get editor associated with variable's value
418 var editorType = argument.GetDynamicPropertyValueEditorType(DesignTimeArgument.ArgumentDefaultValueProperty);
420 //if yes there is a custom one - use it
421 if (!typeof(DesignTimeArgument.DefaultValueEditor).IsAssignableFrom(editorType))
423 //get inline editor template - it will be used for both templates - view and editing;
424 resolveParams.Template = argument.GetDynamicPropertyValueEditor(DesignTimeArgument.ArgumentDefaultValueProperty).InlineEditorTemplate;
425 resolveParams.IsDefaultTemplate = false;
429 //no custom editor - depending on grid state display either editable or readonly expression template
430 string key = string.Empty;
431 switch (argument.GetArgumentDirection())
433 case PropertyKind.Property:
434 key = resolveParams.Cell.IsEditing ? "argumentPropertyEditableTemplate" : "argumentPropertyReadOnlyTemplate";
437 case PropertyKind.InArgument:
438 key = resolveParams.Cell.IsEditing ? "argumentExpressionEditableTemplate" : "argumentExpressionReadOnlyTemplate";
441 case PropertyKind.OutArgument:
442 case PropertyKind.InOutArgument:
443 key = "argumentOutputValueTemplate";
446 resolveParams.Template = (DataTemplate)this.FindResource(key);
447 resolveParams.IsDefaultTemplate = true;
452 DialogPropertyValueEditor OnLoadExtendedValueEditor(DataGridCell cell, object instance)
454 var argument = (DesignObjectWrapper)cell.DataContext;
455 return argument.GetDynamicPropertyValueEditor(DesignTimeArgument.ArgumentDefaultValueProperty) as DialogPropertyValueEditor;
458 ModelProperty OnShowExtendedValueEditor(DataGridCell cell, object instance)
460 var argument = (DesignObjectWrapper)cell.DataContext;
461 return argument.Content.Properties[DesignTimeArgument.ArgumentDefaultValueProperty];
464 internal void UpdateTypeDesigner(DesignTimeArgument argument)
466 this.dgHelper.UpdateDynamicContentColumns(argument);
469 //Check case-insensitive duplicates, which are not allowed in VB expressions
470 internal void CheckCaseInsensitiveDuplicates(VBIdentifierName identifierName, string newName)
472 Func<DesignTimeArgument, bool> checkForDuplicates = new Func<DesignTimeArgument, bool>(p => string.Equals((string)p.ReflectedObject.Properties["Name"].ComputedValue, newName, StringComparison.OrdinalIgnoreCase) && !object.Equals(p.GetArgumentName(), identifierName));
473 DesignTimeArgument duplicate = this.argumentWrapperCollection.FirstOrDefault<DesignTimeArgument>(checkForDuplicates);
474 if (duplicate != null)
476 identifierName.IsValid = false;
477 identifierName.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateIdentifier, newName);
478 VBIdentifierName duplicateIdentifier = duplicate.GetArgumentName();
479 if (duplicateIdentifier.IsValid)
481 duplicateIdentifier.IsValid = false;
482 duplicateIdentifier.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateIdentifier, duplicateIdentifier.IdentifierName);
487 //Check duplicates with old value. When there's only one variable duplicate with the old value,
488 //the only one variable should be valid now after the change
489 void ClearCaseInsensitiveDuplicates(VBIdentifierName identifier, string oldName)
491 Func<DesignTimeArgument, bool> checkForOldNameDuplicates = new Func<DesignTimeArgument, bool>(p => string.Equals((string)p.ReflectedObject.Properties["Name"].ComputedValue, oldName, StringComparison.OrdinalIgnoreCase) && !object.Equals(p.GetArgumentName(), identifier));
492 IEnumerable<DesignTimeArgument> oldDuplicates = this.argumentWrapperCollection.Where<DesignTimeArgument>(checkForOldNameDuplicates);
493 if (oldDuplicates.Count<DesignTimeArgument>() == 1)
495 DesignTimeArgument wrapper = oldDuplicates.First<DesignTimeArgument>();
496 VBIdentifierName oldDuplicate = wrapper.GetArgumentName();
497 oldDuplicate.IsValid = true;
498 oldDuplicate.ErrorMessage = string.Empty;
502 internal void ValidateArgumentName(VBIdentifierName identifierName, string newName, string oldName)
504 //Check whether there're any variables' name conflict with the old name which can be cleaned up now
505 this.ClearCaseInsensitiveDuplicates(identifierName, oldName);
507 //Check whether there're any duplicates with new name
508 this.CheckCaseInsensitiveDuplicates(identifierName, newName);
511 static void OnActivitySchemaChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
513 ModelItem oldItem = e.OldValue as ModelItem;
514 ModelItem newItem = e.NewValue as ModelItem;
515 ArgumentDesigner designer = (ArgumentDesigner)dependencyObject;
517 if (null != oldItem && null != oldItem.Properties[Members])
519 oldItem.Properties[Members].Collection.CollectionChanged -= designer.OnArgumentCollectionChanged;
521 if (null != newItem && null != newItem.Properties[Members])
523 newItem.Properties[Members].Collection.CollectionChanged += designer.OnArgumentCollectionChanged;
525 designer.OnActivitySchemaChanged(newItem);
528 static void OnContextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
530 ((ArgumentDesigner)dependencyObject).OnContextChanged();
533 internal void UpdateArgumentName(DesignTimeArgument argumentWrapper, string newName, string oldName)
535 ModelItemCollection argumentsCollection = this.GetArgumentCollection();
537 //Since underlying object is an KeyedCollection, if we only update the property value, it won't update the key
538 //Need to remove the object and add it again to update the key
539 ModelItem argument = argumentWrapper.ReflectedObject;
540 argumentsCollection.Remove(argument);
541 argument.Properties[ArgumentNamePropertyName].SetValue(newName);
542 argumentsCollection.Add(argument);
543 this.ValidateArgumentName(argumentWrapper.GetArgumentName(), newName, oldName);
545 //Update default value editor in Argument designer
546 this.UpdateTypeDesigner(argumentWrapper);
549 void OnEditingControlLoaded(object sender, RoutedEventArgs args)
551 DataGridHelper.OnEditingControlLoaded(sender, args);
554 void OnEditingControlUnloaded(object sender, RoutedEventArgs args)
556 DataGridHelper.OnEditingControlUnloaded(sender, args);
559 // This is to workaround a bug that updating ModelItem from outside of ArgumentDesigner will not update ArgumentDesigner.
560 internal void NotifyAnnotationTextChanged()
562 foreach (object item in this.argumentsDataGrid.Items)
564 DesignTimeArgument designTimeArgument = item as DesignTimeArgument;
565 if (designTimeArgument != null)
567 designTimeArgument.NotifyPropertyChanged(DesignTimeArgument.AnnotationTextProperty);
572 protected override void OnContextMenuOpening(ContextMenuEventArgs e)
574 base.OnContextMenuOpening(e);
576 DesignerConfigurationService configurationService = this.Context.Services.GetService<DesignerConfigurationService>();
577 Fx.Assert(configurationService != null, "DesignerConfigurationService should not be null");
578 if (configurationService.WorkflowDesignerHostId == WorkflowDesignerHostId.Dev10)
585 bool openedByKeyboard = e.CursorLeft < 0 && e.CursorTop < 0;
587 if (openedByKeyboard)
589 this.ContextMenu.Placement = PlacementMode.Center;
593 this.ContextMenu.Placement = PlacementMode.MousePoint;
595 this.ContextMenu.PlacementTarget = this;
596 this.ContextMenu.IsOpen = true;
599 private void OnDeleteCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
601 ContextMenuUtilities.OnDeleteCommandCanExecute(e, this.argumentsDataGrid);
604 private void OnDeleteCommandExecuted(object sender, ExecutedRoutedEventArgs e)
606 if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count > 0)
608 List<ModelItem> list = new List<ModelItem>();
609 foreach (object item in this.argumentsDataGrid.SelectedItems)
611 DesignTimeArgument designTimeArgument = item as DesignTimeArgument;
612 if (designTimeArgument != null)
614 list.Add(designTimeArgument.ReflectedObject);
618 foreach (ModelItem modelItem in list)
620 foreach (DesignTimeArgument designTimeArgument in this.argumentWrapperCollection)
622 if (designTimeArgument.ReflectedObject == modelItem)
624 this.argumentWrapperCollection.Remove(designTimeArgument);
634 private void OnAnnotationSeparatorLoaded(object sender, RoutedEventArgs e)
636 ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
639 private void OnAddAnnotationMenuLoaded(object sender, RoutedEventArgs e)
641 ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
644 private void OnAddAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
646 ContextMenuUtilities.OnAddAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
649 private void OnAddAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
651 if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
653 AnnotationDialog dialog = new AnnotationDialog();
654 dialog.Context = Context;
655 dialog.Title = SR.AddAnnotationTitle;
657 WindowHelperService service = this.Context.Services.GetService<WindowHelperService>();
660 service.TrySetWindowOwner(this, dialog);
662 dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
664 if (dialog.ShowDialog() == true)
666 string annotationText = dialog.AnnotationText;
668 DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
669 variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].SetValue(annotationText);
676 private void OnEditAnnotationMenuLoaded(object sender, RoutedEventArgs e)
678 ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
681 private void OnEditAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
683 // call the same method as delete annotation command
684 ContextMenuUtilities.OnDeleteAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
687 private void OnEditAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
689 if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
691 DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
693 AnnotationDialog dialog = new AnnotationDialog();
694 dialog.Context = Context;
695 dialog.Title = SR.EditAnnotationTitle;
696 dialog.AnnotationText = variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].ComputedValue as string;
698 WindowHelperService service = this.Context.Services.GetService<WindowHelperService>();
701 service.TrySetWindowOwner(this, dialog);
703 dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
705 if (dialog.ShowDialog() == true)
707 string annotationText = dialog.AnnotationText;
709 variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].SetValue(annotationText);
714 private void OnDeleteAnnotationMenuLoaded(object sender, RoutedEventArgs e)
716 ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
719 private void OnDeleteAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
721 ContextMenuUtilities.OnDeleteAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
724 private void OnDeleteAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
726 if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
728 DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
729 variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].ClearValue();
736 sealed class DesignTimeArgument : DesignObjectWrapper
738 internal static readonly string ArgumentNameProperty = "Name";
739 internal static readonly string ArgumentTypeProperty = "ArgumentType";
740 internal static readonly string ArgumentDirectionProperty = "Direction";
741 internal static readonly string ArgumentDefaultValueProperty = "Value";
742 internal static readonly string IsOutputArgument = "IsOutputArgument";
743 internal static readonly string OwnerSchemaProperty = "OwnerActivitySchemaType";
744 internal static readonly string IsRequiredProperty = "IsRequired";
745 internal static readonly string AnnotationTextProperty = "DesignTimeArgumentAnnotationText";
747 static readonly string[] Properties =
748 new string[] { ArgumentNameProperty, ArgumentTypeProperty, ArgumentDirectionProperty, ArgumentDefaultValueProperty, IsOutputArgument, OwnerSchemaProperty, IsRequiredProperty };
750 static readonly Type inArgumentTypeReference = typeof(InArgument);
751 static readonly Type outArgumentTypeReference = typeof(OutArgument);
752 static readonly Type inOutArgumentTypeReference = typeof(InOutArgument);
753 static readonly Type stringTypeReference = typeof(string);
754 static readonly XamlSchemaContext xamlContext = new XamlSchemaContext();
755 static readonly XamlType xamlType = new XamlType(typeof(string), xamlContext);
756 bool argumentExpressionChanged = false;
757 VBIdentifierName identifierName;
759 public DesignTimeArgument()
761 throw FxTrace.Exception.AsError(new NotSupportedException(SR.InvalidConstructorCall));
764 internal DesignTimeArgument(ModelItem argument, ArgumentDesigner editor)
767 this.Editor = editor;
768 this.ReflectedObject.Properties["Attributes"].Collection.CollectionChanged += new NotifyCollectionChangedEventHandler(OnAttributesChanged);
769 this.identifierName = new VBIdentifierName(true)
771 IdentifierName = (string)argument.Properties[ArgumentNameProperty].ComputedValue
775 void OnAttributesChanged(object sender, NotifyCollectionChangedEventArgs e)
777 this.RaisePropertyChangedEvent(IsRequiredProperty);
780 public override void Dispose()
782 this.ReflectedObject.Properties["Attributes"].Collection.CollectionChanged -= new NotifyCollectionChangedEventHandler(OnAttributesChanged);
786 #region Initialize type properties code
787 public static PropertyDescriptorData[] InitializeTypeProperties()
789 return new PropertyDescriptorData[]
791 new PropertyDescriptorData()
793 PropertyName = ArgumentNameProperty,
794 PropertyType = typeof(VBIdentifierName),
795 PropertyAttributes = TypeDescriptor.GetAttributes(typeof(VBIdentifierName)).OfType<Attribute>().ToArray(),
796 PropertySetter = (instance, newValue) =>
798 ((DesignTimeArgument)instance).SetArgumentName((VBIdentifierName)newValue);
800 PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentName()),
801 PropertyValidator = (instance, value, errors) => (((DesignTimeArgument)instance).ValidateArgumentName(value, errors))
803 new PropertyDescriptorData()
805 PropertyName = ArgumentTypeProperty,
806 PropertyType = typeof(Type),
807 PropertyAttributes = TypeDescriptor.GetAttributes(typeof(Type)).OfType<Attribute>().ToArray(),
808 PropertySetter = (instance, newValue) =>
810 ((DesignTimeArgument)instance).SetArgumentType((Type)newValue);
812 PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentType()),
813 PropertyValidator = null
815 new PropertyDescriptorData()
817 PropertyName = ArgumentDirectionProperty,
818 PropertyType = typeof(PropertyKind),
819 PropertyAttributes = TypeDescriptor.GetAttributes(typeof(PropertyKind)).OfType<Attribute>().Union( new Attribute[] { new EditorAttribute(typeof(DirectionPropertyEditor), typeof(PropertyValueEditor)) }).ToArray(),
820 PropertySetter = (instance, newValue) =>
822 ((DesignTimeArgument)instance).SetArgumentDirection((PropertyKind)newValue);
824 PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentDirection()),
825 PropertyValidator = null
827 new PropertyDescriptorData()
829 PropertyName = ArgumentDefaultValueProperty,
830 PropertyType = typeof(object),
831 PropertyAttributes = TypeDescriptor.GetAttributes(typeof(Activity)).OfType<Attribute>().Union(new Attribute[] { new EditorAttribute(typeof(DesignObjectWrapperDynamicPropertyEditor), typeof(PropertyValueEditor)), new EditorReuseAttribute(false) }).ToArray(),
832 PropertySetter = (instance, newValue) =>
834 ((DesignTimeArgument)instance).SetArgumentValue(newValue);
836 PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentValue()),
837 PropertyValidator = (instance, value, errors) => (((DesignTimeArgument)instance).ValidateArgumentValue(value, errors)),
839 new PropertyDescriptorData()
841 PropertyName = IsOutputArgument,
842 PropertyType = typeof(bool),
843 PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
844 PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetIsOutputArgument()),
845 PropertyValidator = null,
847 new PropertyDescriptorData()
849 PropertyName = OwnerSchemaProperty,
850 PropertyType = typeof(ModelItem),
851 PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
852 PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetOwnerSchemaProperty()),
854 new PropertyDescriptorData()
856 PropertyName = IsRequiredProperty,
857 PropertyType = typeof(bool),
858 PropertyAttributes = TypeDescriptor.GetAttributes(typeof(bool)).OfType<Attribute>().Union(
861 new EditorAttribute(typeof(IsRequiredPropertyEditor), typeof(PropertyValueEditor)),
862 new EditorReuseAttribute(false)
865 PropertySetter = (instance, newValue) =>
867 ((DesignTimeArgument)instance).SetIsRequired(newValue);
869 PropertyValidator = null,
870 PropertyGetter = (instance) =>
872 return ((DesignTimeArgument)instance).GetIsRequired();
875 new PropertyDescriptorData()
877 PropertyName = AnnotationTextProperty,
878 PropertyType = typeof(string),
879 PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
880 PropertySetter = (instance, newValue) =>
882 ((DesignTimeArgument)instance).SetAnnotationText(newValue);
884 PropertyValidator = null,
885 PropertyGetter = (instance) =>
887 return ((DesignTimeArgument)instance).GetAnnotationText();
894 internal ArgumentDesigner Editor { get; private set; }
896 protected override string AutomationId
900 return this.GetArgumentNameString();
904 internal VBIdentifierName GetArgumentName()
906 return this.identifierName;
909 string GetArgumentNameString()
911 return (string)this.ReflectedObject.Properties[ArgumentNameProperty].ComputedValue;
914 // For screen reader to read the DataGrid row.
915 public override string ToString()
917 string name = this.GetArgumentNameString();
918 if (!string.IsNullOrEmpty(name))
925 object GetAnnotationText()
927 ModelProperty property = this.ReflectedObject.Properties.Find(Annotation.AnnotationTextPropertyName);
929 if (property != null)
931 return property.ComputedValue;
939 void SetAnnotationText(object annotationText)
941 ModelProperty property = this.ReflectedObject.Properties.Find(Annotation.AnnotationTextPropertyName);
943 if (property != null)
945 property.SetValue(annotationText);
949 void SetArgumentName(VBIdentifierName identifierName)
951 using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentNameDescription")))
953 this.identifierName = identifierName;
954 string name = identifierName.IdentifierName;
955 this.Editor.UpdateArgumentName(this, name, (string)this.ReflectedObject.Properties[ArgumentNameProperty].ComputedValue);
961 internal Type GetArgumentType()
963 Type result = (Type)this.ReflectedObject.Properties["Type"].ComputedValue;
964 if (this.GetArgumentDirection() != PropertyKind.Property)
966 result = result.GetGenericArguments()[0];
971 void SetArgumentType(Type type)
973 using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentTypeDescription")))
975 PropertyKind currentDirection = this.GetArgumentDirection();
976 Type propertyType = GetTypeReference(currentDirection, type);
977 this.ReflectedObject.Properties["Type"].SetValue(propertyType);
978 this.TryUpdateArgumentType(type, currentDirection);
979 ImportDesigner.AddImport(type.Namespace, this.Context);
984 internal PropertyKind GetArgumentDirection()
986 PropertyKind result = PropertyKind.Property;
987 Type argumentType = (Type)this.ReflectedObject.Properties["Type"].ComputedValue;
988 if (inArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
990 result = PropertyKind.InArgument;
992 else if (outArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
994 result = PropertyKind.OutArgument;
996 else if (inOutArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
998 result = PropertyKind.InOutArgument;
1003 void SetArgumentDirection(PropertyKind direction)
1005 using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentDirectionDescription")))
1007 Type currentType = this.GetArgumentType();
1008 Type propertyType = GetTypeReference(direction, currentType);
1009 this.ReflectedObject.Properties["Type"].SetValue(propertyType);
1010 this.TryUpdateArgumentType(currentType, direction);
1011 if (direction == PropertyKind.Property)
1013 this.SetIsRequired(false);
1019 Type GetTypeReference(PropertyKind direction, Type type)
1021 Type targetType = null;
1024 case PropertyKind.InArgument:
1025 targetType = typeof(InArgument<>).MakeGenericType(type);
1028 case PropertyKind.OutArgument:
1029 targetType = typeof(OutArgument<>).MakeGenericType(type);
1032 case PropertyKind.InOutArgument:
1033 targetType = typeof(InOutArgument<>).MakeGenericType(type);
1036 case PropertyKind.Property:
1041 throw FxTrace.Exception.AsError(new NotSupportedException(direction.ToString()));
1046 void SetArgumentValue(object value)
1048 this.argumentExpressionChanged = true;
1049 if (PropertyKind.Property == this.GetArgumentDirection())
1051 //handle empty string - reset the value
1052 if (this.GetArgumentType() != typeof(string) && value is string && string.IsNullOrEmpty((string)value))
1056 //handle conversion if needed
1057 else if (null != value && !this.GetArgumentType().IsAssignableFrom(value.GetType()))
1059 TypeConverter converter = TypeDescriptor.GetConverter(this.GetArgumentType());
1060 if (converter.CanConvertFrom(value.GetType()))
1062 value = converter.ConvertFrom(value);
1069 //else: leave value as is
1075 string direction = null;
1076 switch (this.GetArgumentDirection())
1078 case PropertyKind.InArgument:
1079 direction = ArgumentDirection.In.ToString();
1082 case PropertyKind.OutArgument:
1083 direction = ArgumentDirection.Out.ToString();
1086 case PropertyKind.InOutArgument:
1087 direction = ArgumentDirection.InOut.ToString();
1091 throw FxTrace.Exception.AsError(new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "{0} argument direction is not supported", this.GetArgumentDirection())));
1093 value = this.Editor.ArgumentToExpressionConverter.ConvertBack(value, typeof(Argument), direction, CultureInfo.CurrentCulture);
1096 this.ReflectedObject.Properties[DesignTimeArgument.ArgumentDefaultValueProperty].SetValue(value);
1099 internal object GetArgumentValue()
1101 ModelItem value = this.ReflectedObject.Properties[DesignTimeArgument.ArgumentDefaultValueProperty].Value;
1102 object result = null;
1103 if (PropertyKind.Property == this.GetArgumentDirection())
1107 result = value.GetCurrentValue();
1112 result = this.Editor.ArgumentToExpressionConverter.Convert(value, typeof(object), null, CultureInfo.CurrentCulture);
1113 ModelItem expression = result as ModelItem;
1114 if (null != expression)
1116 result = expression.GetCurrentValue();
1122 bool GetIsOutputArgument()
1124 PropertyKind direction = this.GetArgumentDirection();
1125 return (direction == PropertyKind.OutArgument || direction == PropertyKind.InOutArgument);
1128 bool IsRequired(IList attributes)
1130 if (attributes == null)
1134 foreach (ModelItem item in attributes)
1136 if (typeof(RequiredArgumentAttribute).IsAssignableFrom(item.ItemType))
1144 bool GetIsRequired()
1146 ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
1147 return IsRequired(attributes);
1150 void AddIsRequiredAttribute()
1152 ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
1153 using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentIsRequiredDescription")))
1155 attributes.Add(new RequiredArgumentAttribute());
1160 void RemoveIsRequiredAttribute()
1162 ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
1163 using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentIsRequiredDescription")))
1165 foreach (ModelItem toRemove in attributes.Where<ModelItem>(p => typeof(RequiredArgumentAttribute).IsAssignableFrom(p.ItemType)))
1167 attributes.Remove(toRemove);
1173 void SetIsRequired(object isRequired)
1175 bool required = isRequired is ModelItem ? (bool)(((ModelItem)isRequired).GetCurrentValue()) : (bool)isRequired;
1177 if (required && !this.GetIsRequired())
1179 this.AddIsRequiredAttribute();
1181 else if (!required && this.GetIsRequired())
1183 this.RemoveIsRequiredAttribute();
1187 internal bool Filter(Type type)
1189 // We disallow user to pick any Argument<T> type as a property since this is the same as choosing the right direction in the first place.
1190 return this.GetArgumentDirection() != PropertyKind.Property || !type.IsGenericType || !typeof(Argument).IsAssignableFrom(type);
1193 internal ModelItem GetOwnerSchemaProperty()
1195 return this.ReflectedObject.Parent.Parent;
1198 protected override Type OnGetDynamicPropertyValueEditorType(string propertyName)
1200 var type = this.GetArgumentType();
1201 var direction = this.GetArgumentDirection();
1203 //if argument name is not valid XAML member name, default value editing is disabled.
1204 //Since it cannot be saved.
1205 if (!VBIdentifierName.IsValidXamlName(this.GetArgumentName().IdentifierName))
1207 return typeof(InvalidXamlMemberValueEditor);
1210 //in case of arguments which contain handles - display HandleValueEditor
1211 if (typeof(Handle).IsAssignableFrom(type))
1213 return typeof(HandleValueEditor);
1217 //check if there are custom editors on the variable's type
1218 Type argumentType = null;
1221 case PropertyKind.InArgument:
1222 argumentType = typeof(InArgument<>).MakeGenericType(type);
1225 case PropertyKind.InOutArgument:
1226 argumentType = typeof(InOutArgument<>).MakeGenericType(type);
1229 case PropertyKind.OutArgument:
1230 argumentType = typeof(OutArgument<>).MakeGenericType(type);
1234 argumentType = type;
1238 var referenceType = typeof(PropertyValueEditor);
1239 var expressionEditorType = typeof(ExpressionValueEditor);
1241 //check if there are custom type editors associated with given type -
1242 //first look for type editor defined for In/Out/InOut/Argument<T> (if argument is of proper direction)
1243 //then, look for type editor defined for type itself (i.e. T) -
1244 //in search, skip ExpressionValueEditor instance - it will be returned by default for property grid, but for
1245 //dataGrid nothing should be used - we use default dg template
1246 var customEditorType = TypeDescriptor
1247 .GetAttributes(argumentType)
1248 .OfType<EditorAttribute>()
1251 Type currentType = Type.GetType(p.EditorTypeName);
1252 return (expressionEditorType != currentType && referenceType.IsAssignableFrom(currentType));
1254 .Select(p => Type.GetType(p.EditorTypeName))
1257 //if yes - check if there is at least one editor assigner and it derives from PropertyValueEditor
1258 if (null != customEditorType)
1260 return customEditorType;
1263 TypeConverter converter = TypeDescriptor.GetConverter(type);
1264 if (((type != stringTypeReference && (converter == null || !converter.CanConvertFrom(stringTypeReference))) && direction == PropertyKind.Property)
1265 || direction == PropertyKind.OutArgument || direction == PropertyKind.InOutArgument)
1267 return typeof(ValueNotSupportedEditor);
1270 //otherwise - return default expression value editor
1271 return typeof(DefaultValueEditor);
1274 internal bool ValidateArgumentName(object value, List<string> errors)
1276 VBIdentifierName identifier = value as VBIdentifierName;
1277 string name = identifier.IdentifierName;
1279 if (string.IsNullOrEmpty(name))
1281 errors.Add(SR.EmptyArgumentName);
1285 if (!VBIdentifierName.IsValidXamlName(name))
1287 errors.Add(string.Format(CultureInfo.CurrentUICulture, SR.InvalidXamlMemberName, name));
1291 ModelItemCollection argumentCollection = (ModelItemCollection)this.ReflectedObject.Parent;
1294 argumentCollection.Any<ModelItem>(p => string.Equals(p.Properties["Name"].ComputedValue, name) && !ModelItem.Equals(p, this.ReflectedObject));
1298 errors.Add(string.Format(CultureInfo.CurrentUICulture, SR.DuplicateArgumentName, name));
1302 return 0 == errors.Count;
1305 [SuppressMessage(FxCop.Category.Design, FxCop.Rule.DoNotCatchGeneralExceptionTypes,
1306 Justification = "Exception content is displayed as error message. Propagating exceptions might lead to VS crash.")]
1307 [SuppressMessage("Reliability", "Reliability108",
1308 Justification = "Exception content is displayed as error message. Propagating exceptions might lead to VS crash.")]
1309 bool ValidateArgumentValue(object value, List<string> errors)
1311 if (PropertyKind.Property == this.GetArgumentDirection())
1313 //the value is a string and is empty - assume user wants to clear the property value
1314 if (value is string && string.IsNullOrEmpty((string)value))
1318 //validate the value for PropertyType - check if converter usage is required - if value type is the same as argument type - skip conversion
1319 if (null != value && !this.GetArgumentType().IsAssignableFrom(value.GetType()))
1323 TypeConverter converter = TypeDescriptor.GetConverter(this.GetArgumentType());
1324 converter.ConvertFrom(value);
1326 catch (Exception err)
1328 errors.Add(err.Message);
1332 return 0 == errors.Count;
1335 string GetArgumentValueExpressionText()
1337 string currentExpressionText = null;
1338 object currentValue = this.GetArgumentValue();
1339 if (null != currentValue)
1341 if (this.GetArgumentDirection() == PropertyKind.Property)
1343 TypeConverter oldConverter = TypeDescriptor.GetConverter(this.GetArgumentType());
1345 if (oldConverter.CanConvertTo(typeof(string)))
1347 currentExpressionText = (string)oldConverter.ConvertTo(currentValue, typeof(string));
1352 ModelItem expression = null;
1353 if (this.ReflectedObject.TryGetPropertyValue(out expression, ArgumentDefaultValueProperty, "Expression") && null != expression)
1355 var activity = expression.GetCurrentValue() as ActivityWithResult;
1356 if (null != activity)
1358 currentExpressionText = ExpressionHelper.GetExpressionString(activity);
1363 return currentExpressionText;
1366 [SuppressMessage(FxCop.Category.Design, FxCop.Rule.DoNotCatchGeneralExceptionTypes,
1367 Justification = "Conversion of value when type changes might fail - argument will get null value by default. Propagating exceptions might lead to VS crash.")]
1368 [SuppressMessage("Reliability", "Reliability108",
1369 Justification = "Conversion of value when type changes might fail - argument will get null value by default. Propagating exceptions might lead to VS crash.")]
1370 void TryUpdateArgumentType(Type newType, PropertyKind newDirection)
1372 if (newDirection == PropertyKind.Property)
1374 string currentExpressionText = this.GetArgumentValueExpressionText();
1375 if (null != currentExpressionText)
1377 TypeConverter converter = TypeDescriptor.GetConverter(newType);
1378 if (converter.CanConvertFrom(typeof(string)))
1382 object value = converter.ConvertFrom(currentExpressionText);
1383 this.ReflectedObject.Properties[ArgumentDefaultValueProperty].SetValue(value);
1385 catch (Exception err)
1387 System.Diagnostics.Debug.WriteLine(err.ToString());
1388 this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1393 this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1398 this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1401 else if (newDirection == PropertyKind.InArgument)
1403 Argument currentArgument = this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ComputedValue as Argument;
1404 ActivityWithResult newExpression = null;
1405 bool succeeded = false;
1406 if (currentArgument != null)
1408 succeeded = ExpressionHelper.TryMorphExpression(currentArgument.Expression, false, newType, this.Context, out newExpression);
1412 ////If the old direction is property, we'll try to convert the default value object to the expression object specified by global editor setting
1413 string currentExpressionText = this.GetArgumentValueExpressionText();
1414 if (!string.IsNullOrEmpty(currentExpressionText))
1416 string rootEditorSetting = ExpressionHelper.GetRootEditorSetting(this.ModelTreeManager, WorkflowDesigner.GetTargetFramework(this.Context));
1417 if (!string.IsNullOrEmpty(rootEditorSetting))
1419 succeeded = ExpressionTextBox.TryConvertFromString(rootEditorSetting, currentExpressionText, false, newType, out newExpression);
1426 Argument newArgument = Argument.Create(newType, ArgumentDirection.In);
1427 newArgument.Expression = newExpression;
1428 this.ReflectedObject.Properties[ArgumentDefaultValueProperty].SetValue(newArgument);
1432 //currently if the value cannot be morphed, it's cleared.
1433 this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1438 this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1442 protected override void OnReflectedObjectPropertyChanged(string propertyName)
1444 if (string.Equals(propertyName, "Type"))
1446 //type has changed - most likely custom value editors collection would be obsolete
1447 this.RaisePropertyChangedEvent(ArgumentTypeProperty);
1448 this.RaisePropertyChangedEvent(ArgumentDirectionProperty);
1449 this.RaisePropertyChangedEvent(IsOutputArgument);
1450 this.RaisePropertyChangedEvent(ArgumentDefaultValueProperty);
1452 else if (propertyName == ArgumentNameProperty)
1454 //Change name may need to update the defaul value editor as well, so clean the cache
1455 string oldValue = this.identifierName.IdentifierName;
1456 string newValue = GetArgumentNameString();
1458 //This is invoked in undo stack
1459 if (oldValue != newValue)
1461 this.identifierName = new VBIdentifierName(true)
1463 IdentifierName = newValue
1465 Editor.ValidateArgumentName(this.identifierName, newValue, oldValue);
1468 else if (propertyName == ArgumentDefaultValueProperty)
1470 this.argumentExpressionChanged = true;
1472 else if (propertyName == Annotation.AnnotationTextPropertyName)
1474 RaisePropertyChangedEvent(AnnotationTextProperty);
1478 protected override void OnPropertyChanged(string propertyName)
1480 if (string.Equals(propertyName, ArgumentNameProperty))
1482 this.RaisePropertyChangedEvent(AutomationIdProperty);
1484 else if (string.Equals(propertyName, TimestampProperty))
1486 if ((!this.argumentExpressionChanged) && (this.Editor != null))
1488 this.CustomValueEditors.Clear();
1489 this.Editor.UpdateTypeDesigner(this);
1493 this.argumentExpressionChanged = false;
1496 else if (string.Equals(propertyName, ArgumentDirectionProperty) || (string.Equals(propertyName, ArgumentTypeProperty)))
1498 this.RaisePropertyChangedEvent(ArgumentDefaultValueProperty);
1500 base.OnPropertyChanged(propertyName);
1503 internal sealed class DirectionPropertyEditor : PropertyValueEditor
1505 public DirectionPropertyEditor()
1507 this.InlineEditorTemplate = EditorResources.GetResources()["DirectionEditor_InlineEditorTemplate"] as DataTemplate;
1511 internal sealed class DefaultValueEditor : ExpressionValueEditor
1513 public DefaultValueEditor()
1515 this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument"] as DataTemplate;
1519 internal sealed class IsRequiredPropertyEditor : PropertyValueEditor
1521 public IsRequiredPropertyEditor()
1523 this.InlineEditorTemplate = EditorResources.GetResources()["IsRequiredPropertyEditor_InlineEditorTemplate"] as DataTemplate;
1527 internal sealed class ValueNotSupportedEditor : PropertyValueEditor
1529 public ValueNotSupportedEditor()
1531 this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument_ValueNotSupported"] as DataTemplate;
1535 internal sealed class InvalidXamlMemberValueEditor : PropertyValueEditor
1537 public InvalidXamlMemberValueEditor()
1539 this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument_InvalidXamlMember"] as DataTemplate;
1544 sealed class PropertyValueTextBox : TextBox
1546 protected override void OnInitialized(EventArgs e)
1548 base.OnInitialized(e);
1549 this.Loaded += (s, args) =>
1551 //get the binding expression, and hook up exception filter
1552 var expr = this.GetBindingExpression(PropertyValueTextBox.TextProperty);
1553 if (null != expr && null != expr.ParentBinding)
1555 expr.ParentBinding.UpdateSourceExceptionFilter = this.OnUpdateBindingException;
1560 object OnUpdateBindingException(object sender, Exception err)
1562 //if exception occured, the property value is invalid (conversion to target type failed)
1563 if (err is TargetInvocationException && err.InnerException is ValidationException || err is ValidationException)
1565 //show error message
1566 ErrorReporting.ShowErrorMessage((err.InnerException ?? err).Message);
1567 //and revert textbox to last valid value
1568 this.GetBindingExpression(PropertyValueTextBox.TextProperty).UpdateTarget();
1574 public enum PropertyKind