[corlib] Avoid unnecessary ephemeron array resizes
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / View / ArgumentDesigner.xaml.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.Activities.Presentation.View
6 {
7     using System;
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;
21     using System.Linq;
22     using System.Reflection;
23     using System.Runtime;
24     using System.Windows;
25     using System.Windows.Controls;
26     using System.Windows.Controls.Primitives;
27     using System.Windows.Input;
28     using System.Windows.Threading;
29     using System.Xaml;
30
31     partial class ArgumentDesigner
32     {
33         public static readonly DependencyProperty ContextProperty = DependencyProperty.Register(
34             "Context",
35             typeof(EditingContext),
36             typeof(ArgumentDesigner),
37             new FrameworkPropertyMetadata(null, OnContextChanged));
38
39         public static readonly DependencyProperty ActivitySchemaProperty = DependencyProperty.Register(
40             "ActivitySchema",
41             typeof(ModelItem),
42             typeof(ArgumentDesigner),
43             new FrameworkPropertyMetadata(OnActivitySchemaChanged));
44
45         public static readonly RoutedEvent ArgumentCollectionChangedEvent = EventManager.RegisterRoutedEvent(
46             "ArgumentCollectionChanged",
47             RoutingStrategy.Bubble,
48             typeof(RoutedEventHandler),
49             typeof(ArgumentDesigner));
50
51         static readonly string DefaultArgumentName = "argument";
52         static readonly string Members = "Properties";
53         static readonly string ArgumentNamePropertyName = "Name";
54
55         ObservableCollection<DesignTimeArgument> argumentWrapperCollection = new ObservableCollection<DesignTimeArgument>();
56
57         bool isCollectionLoaded = false;
58         bool isDataGridPopulating = false;
59         ModelItem lastSelection;
60         bool isSelectionChangeInternal = false;
61         ArgumentToExpressionConverter argumentToExpressionConverter;
62         DataGridHelper dgHelper;
63
64         public ArgumentDesigner()
65         {
66             InitializeComponent();
67
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;
75
76             this.argumentsDataGrid.SelectionChanged += OnDataGridArgumentSelected;
77             this.argumentsDataGrid.GotFocus += OnDataGridArgumentSelected;
78
79             this.argumentWrapperCollection.CollectionChanged += OnArgumentWrapperCollectionChanged;
80             this.argumentsDataGrid.ItemsSource = this.argumentWrapperCollection;
81
82             this.argumentsDataGrid.LayoutUpdated += OnArgumentDataGridLayoutUpdated;
83         }
84
85         public event RoutedEventHandler ArgumentCollectionChanged
86         {
87             add
88             {
89                 AddHandler(ArgumentCollectionChangedEvent, value);
90             }
91             remove
92             {
93                 RemoveHandler(ArgumentCollectionChangedEvent, value);
94             }
95         }
96
97
98         public ModelItem ActivitySchema
99         {
100             get { return (ModelItem)GetValue(ActivitySchemaProperty); }
101             set { SetValue(ActivitySchemaProperty, value); }
102         }
103
104         public EditingContext Context
105         {
106             get { return (EditingContext)GetValue(ContextProperty); }
107             set { SetValue(ContextProperty, value); }
108         }
109
110         internal ArgumentToExpressionConverter ArgumentToExpressionConverter
111         {
112             get
113             {
114                 if (null == this.argumentToExpressionConverter)
115                 {
116                     this.argumentToExpressionConverter = new ArgumentToExpressionConverter();
117                 }
118                 return this.argumentToExpressionConverter;
119             }
120         }
121
122         public bool CreateNewArgumentWrapper()
123         {
124             bool result = false;
125
126             if (null != this.ActivitySchema)
127             {
128                 DynamicActivityProperty property = new DynamicActivityProperty()
129                 {
130                     Name = this.GetDefaultName(),
131                     Type = this.GetDefaultType(),
132                 };
133                 DesignTimeArgument wrapper = null;
134                 using (ModelEditingScope scope = this.ActivitySchema.BeginEdit((string)this.FindResource("addNewArgumentDescription")))
135                 {
136                     ModelItem argument = this.GetArgumentCollection().Add(property);
137                     wrapper = new DesignTimeArgument(argument, this);
138                     this.argumentWrapperCollection.Add(wrapper);
139                     scope.Complete();
140                     result = true;
141                 }
142                 this.dgHelper.BeginRowEdit(wrapper);
143             }
144             return result;
145         }
146
147         ModelItemCollection GetArgumentCollection()
148         {
149             if (this.ActivitySchema != null)
150             {
151                 Fx.Assert(this.ActivitySchema.Properties[Members] != null, "Members collection not found!");
152                 return this.ActivitySchema.Properties[Members].Collection;
153             }
154             return null;
155         }
156
157
158         string GetDefaultName()
159         {
160             ModelItemCollection argumentCollection = this.GetArgumentCollection();
161             return argumentCollection.GetUniqueName(ArgumentDesigner.DefaultArgumentName, (arg) => ((string)arg.Properties["Name"].ComputedValue));
162         }
163
164         Type GetDefaultType()
165         {
166             return typeof(InArgument<string>);
167         }
168
169         void Populate()
170         {
171             if (!this.isCollectionLoaded)
172             {
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)
178                 {
179                     foreach (ModelItem argument in arguments)
180                     {
181                         this.argumentWrapperCollection.Add(new DesignTimeArgument(argument, this));
182                     }
183                 }
184                 this.argumentsDataGrid.ItemsSource = this.argumentWrapperCollection;
185                 this.isCollectionLoaded = true;
186             }
187         }
188
189         void StoreLastSelection()
190         {
191             if (!this.isSelectionChangeInternal)
192             {
193                 ModelItem current = this.Context.Items.GetValue<Selection>().PrimarySelection;
194                 if (null == current || !typeof(DesignTimeArgument).IsAssignableFrom(current.ItemType))
195                 {
196                     this.lastSelection = current;
197                 }
198             }
199         }
200
201         void OnArgumentTypeTypePresenterLoaded(object sender, RoutedEventArgs args)
202         {
203             TypePresenter argumentTypeTypePresenter = ((TypePresenter)sender);
204             argumentTypeTypePresenter.Filter = ((DesignTimeArgument)argumentTypeTypePresenter.DataContext).Filter;
205             DataGridHelper.OnEditingControlLoaded(sender, args);
206         }
207
208         void OnArgumentTypeTypePresenterUnloaded(object sender, RoutedEventArgs args)
209         {
210             DataGridHelper.OnEditingControlUnloaded(sender, args);
211         }
212
213         internal void SelectArgument(ModelItem argument)
214         {
215             this.Dispatcher.BeginInvoke(new Action(() =>
216             {
217                 foreach (object item in this.argumentsDataGrid.Items)
218                 {
219                     if (item is DesignTimeArgument)
220                     {
221                         if (object.ReferenceEquals(((DesignTimeArgument)item).ReflectedObject, argument))
222                         {
223                             this.argumentsDataGrid.SelectedItem = item;
224                             this.argumentsDataGrid.ScrollIntoView(item, null);
225                         }
226                     }
227                 }
228             }), DispatcherPriority.ApplicationIdle);
229         }
230
231         void OnDataGridArgumentSelected(object sender, RoutedEventArgs e)
232         {
233             if (null != this.Context && !this.isSelectionChangeInternal)
234             {
235                 this.isSelectionChangeInternal = true;
236                 DesignTimeArgument argument = this.dgHelper.SelectedItem<DesignTimeArgument>();
237                 if (null != argument)
238                 {
239                     this.Context.Items.SetValue(new Selection(argument.Content));
240                 }
241                 else
242                 {
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)
247                     {
248                         foreach (ModelItem item in oldSelection.SelectedObjects)
249                         {
250                             if (item.ItemType != typeof(DesignTimeArgument))
251                             {
252                                 newSelection.Add(item);
253                             }
254                         }
255                     }
256                     this.Context.Items.SetValue(new Selection(newSelection));
257                 }
258                 this.isSelectionChangeInternal = false;
259             }
260         }
261
262         void OnArgumentDataGridLayoutUpdated(object sender, EventArgs e)
263         {
264             if (this.isDataGridPopulating)
265             {
266                 this.isDataGridPopulating = false;
267                 Mouse.OverrideCursor = null;
268             }
269         }
270
271         void OnActivitySchemaChanged(ModelItem newSchemaItem)
272         {
273             this.isCollectionLoaded = false;
274
275             if (null != newSchemaItem && null != newSchemaItem.Properties[Members])
276             {
277                 //lazy initialization, wait till it is visible
278                 if (this.Visibility == Visibility.Visible)
279                 {
280                     this.Populate();
281                 }
282             }
283         }
284
285         void OnContextChanged()
286         {
287             if (null != this.Context)
288             {
289                 this.Context.Items.Subscribe<Selection>(new SubscribeContextCallback<Selection>(OnItemSelected));
290             }
291             this.dgHelper.Context = this.Context;
292         }
293
294         void OnItemSelected(Selection selection)
295         {
296             if (!this.isSelectionChangeInternal)
297             {
298                 this.StoreLastSelection();
299
300                 bool selectedArgumentIsInSelection = false;
301
302                 DesignTimeArgument selectedArgument = this.argumentsDataGrid.SelectedItem as DesignTimeArgument;
303                 if (selectedArgument != null)
304                 {
305                     foreach (ModelItem item in selection.SelectedObjects)
306                     {
307                         if (object.ReferenceEquals(selectedArgument, item.GetCurrentValue()))
308                         {
309                             selectedArgumentIsInSelection = true;
310                         }
311                     }
312                 }
313
314                 if (!selectedArgumentIsInSelection)
315                 {
316                     this.argumentsDataGrid.SelectedItem = null;
317                 }
318             }
319         }
320
321         void OnVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
322         {
323             if (this.Dispatcher.HasShutdownStarted)
324             {
325                 return;
326             }
327
328             if ((Boolean)e.NewValue == true)
329             {
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;
333
334                 this.StoreLastSelection();
335                 this.Populate();
336             }
337             else
338             {
339                 if (this.argumentsDataGrid.SelectedItem != null)
340                 {
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;
347                 }
348             }
349         }
350
351         void OnArgumentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
352         {
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)
357             {
358                 switch (e.Action)
359                 {
360                     case NotifyCollectionChangedAction.Add:
361                         foreach (ModelItem argument in e.NewItems)
362                         {
363                             var wrapper = this.argumentWrapperCollection
364                                 .FirstOrDefault(p => (ModelItem.Equals(p.ReflectedObject, argument)));
365
366                             if (wrapper == null)
367                             {
368                                 wrapper = new DesignTimeArgument(argument, this);
369                                 this.argumentWrapperCollection.Add(wrapper);
370                             }
371                         }
372                         break;
373
374                     case NotifyCollectionChangedAction.Remove:
375                         foreach (ModelItem argument in e.OldItems)
376                         {
377                             var wrapper = this.argumentWrapperCollection.FirstOrDefault(p => ModelItem.Equals(p.ReflectedObject, argument));
378                             if (null != wrapper)
379                             {
380                                 this.argumentWrapperCollection.Remove(wrapper);
381                             }
382                         }
383                         break;
384                 }
385             }
386         }
387         void OnArgumentWrapperCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
388         {
389             bool isUndoRedoInProgress = this.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress;
390             switch (e.Action)
391             {
392                 case NotifyCollectionChangedAction.Remove:
393                     foreach (DesignTimeArgument arg in e.OldItems)
394                     {
395                         this.ClearCaseInsensitiveDuplicates(arg.GetArgumentName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue);
396                         if (!isUndoRedoInProgress)
397                         {
398                             ModelItemCollection collection = (ModelItemCollection)arg.ReflectedObject.Parent;
399                             collection.Remove(arg.ReflectedObject);
400                         }
401                         arg.Dispose();
402                     }
403                     break;
404                 case NotifyCollectionChangedAction.Add:
405                     foreach (DesignTimeArgument arg in e.NewItems)
406                     {
407                         this.CheckCaseInsensitiveDuplicates(arg.GetArgumentName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue);
408                     }
409                     break;
410             }
411         }
412
413         bool OnResolveDynamicContentTemplate(ResolveTemplateParams resolveParams)
414         {
415             var argument = (DesignTimeArgument)resolveParams.Cell.DataContext;
416
417             //get editor associated with variable's value
418             var editorType = argument.GetDynamicPropertyValueEditorType(DesignTimeArgument.ArgumentDefaultValueProperty);
419
420             //if yes there is a custom one - use it
421             if (!typeof(DesignTimeArgument.DefaultValueEditor).IsAssignableFrom(editorType))
422             {
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;
426             }
427             else
428             {
429                 //no custom editor - depending on grid state display either editable or readonly expression template
430                 string key = string.Empty;
431                 switch (argument.GetArgumentDirection())
432                 {
433                     case PropertyKind.Property:
434                         key = resolveParams.Cell.IsEditing ? "argumentPropertyEditableTemplate" : "argumentPropertyReadOnlyTemplate";
435                         break;
436
437                     case PropertyKind.InArgument:
438                         key = resolveParams.Cell.IsEditing ? "argumentExpressionEditableTemplate" : "argumentExpressionReadOnlyTemplate";
439                         break;
440
441                     case PropertyKind.OutArgument:
442                     case PropertyKind.InOutArgument:
443                         key = "argumentOutputValueTemplate";
444                         break;
445                 }
446                 resolveParams.Template = (DataTemplate)this.FindResource(key);
447                 resolveParams.IsDefaultTemplate = true;
448             }
449             return true;
450         }
451
452         DialogPropertyValueEditor OnLoadExtendedValueEditor(DataGridCell cell, object instance)
453         {
454             var argument = (DesignObjectWrapper)cell.DataContext;
455             return argument.GetDynamicPropertyValueEditor(DesignTimeArgument.ArgumentDefaultValueProperty) as DialogPropertyValueEditor;
456         }
457
458         ModelProperty OnShowExtendedValueEditor(DataGridCell cell, object instance)
459         {
460             var argument = (DesignObjectWrapper)cell.DataContext;
461             return argument.Content.Properties[DesignTimeArgument.ArgumentDefaultValueProperty];
462         }
463
464         internal void UpdateTypeDesigner(DesignTimeArgument argument)
465         {
466             this.dgHelper.UpdateDynamicContentColumns(argument);
467         }
468
469         //Check case-insensitive duplicates, which are not allowed in VB expressions 
470         internal void CheckCaseInsensitiveDuplicates(VBIdentifierName identifierName, string newName)
471         {
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)
475             {
476                 identifierName.IsValid = false;
477                 identifierName.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateIdentifier, newName);
478                 VBIdentifierName duplicateIdentifier = duplicate.GetArgumentName();
479                 if (duplicateIdentifier.IsValid)
480                 {
481                     duplicateIdentifier.IsValid = false;
482                     duplicateIdentifier.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateIdentifier, duplicateIdentifier.IdentifierName);
483                 }
484             };
485         }
486
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)
490         {
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)
494             {
495                 DesignTimeArgument wrapper = oldDuplicates.First<DesignTimeArgument>();
496                 VBIdentifierName oldDuplicate = wrapper.GetArgumentName();
497                 oldDuplicate.IsValid = true;
498                 oldDuplicate.ErrorMessage = string.Empty;
499             }
500         }
501
502         internal void ValidateArgumentName(VBIdentifierName identifierName, string newName, string oldName)
503         {
504             //Check whether there're any variables' name conflict with the old name which can be cleaned up now
505             this.ClearCaseInsensitiveDuplicates(identifierName, oldName);
506
507             //Check whether there're any duplicates with new name                
508             this.CheckCaseInsensitiveDuplicates(identifierName, newName);
509         }
510
511         static void OnActivitySchemaChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
512         {
513             ModelItem oldItem = e.OldValue as ModelItem;
514             ModelItem newItem = e.NewValue as ModelItem;
515             ArgumentDesigner designer = (ArgumentDesigner)dependencyObject;
516
517             if (null != oldItem && null != oldItem.Properties[Members])
518             {
519                 oldItem.Properties[Members].Collection.CollectionChanged -= designer.OnArgumentCollectionChanged;
520             }
521             if (null != newItem && null != newItem.Properties[Members])
522             {
523                 newItem.Properties[Members].Collection.CollectionChanged += designer.OnArgumentCollectionChanged;
524             }
525             designer.OnActivitySchemaChanged(newItem);
526         }
527
528         static void OnContextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
529         {
530             ((ArgumentDesigner)dependencyObject).OnContextChanged();
531         }
532
533         internal void UpdateArgumentName(DesignTimeArgument argumentWrapper, string newName, string oldName)
534         {
535             ModelItemCollection argumentsCollection = this.GetArgumentCollection();
536
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);
544
545             //Update default value editor in Argument designer
546             this.UpdateTypeDesigner(argumentWrapper);
547         }
548
549         void OnEditingControlLoaded(object sender, RoutedEventArgs args)
550         {
551             DataGridHelper.OnEditingControlLoaded(sender, args);
552         }
553
554         void OnEditingControlUnloaded(object sender, RoutedEventArgs args)
555         {
556             DataGridHelper.OnEditingControlUnloaded(sender, args);
557         }
558
559         // This is to workaround a bug that updating ModelItem from outside of ArgumentDesigner will not update ArgumentDesigner.
560         internal void NotifyAnnotationTextChanged()
561         {
562             foreach (object item in this.argumentsDataGrid.Items)
563             {
564                 DesignTimeArgument designTimeArgument = item as DesignTimeArgument;
565                 if (designTimeArgument != null)
566                 {
567                     designTimeArgument.NotifyPropertyChanged(DesignTimeArgument.AnnotationTextProperty);
568                 }
569             }
570         }
571
572         protected override void OnContextMenuOpening(ContextMenuEventArgs e)
573         {
574             base.OnContextMenuOpening(e);
575
576             DesignerConfigurationService configurationService = this.Context.Services.GetService<DesignerConfigurationService>();
577             Fx.Assert(configurationService != null, "DesignerConfigurationService should not be null");
578             if (configurationService.WorkflowDesignerHostId == WorkflowDesignerHostId.Dev10)
579             {
580                 return;
581             }
582
583             e.Handled = true;
584
585             bool openedByKeyboard = e.CursorLeft < 0 && e.CursorTop < 0;
586
587             if (openedByKeyboard)
588             {
589                 this.ContextMenu.Placement = PlacementMode.Center;
590             }
591             else
592             {
593                 this.ContextMenu.Placement = PlacementMode.MousePoint;
594             }
595             this.ContextMenu.PlacementTarget = this;
596             this.ContextMenu.IsOpen = true;
597         }
598
599         private void OnDeleteCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
600         {
601             ContextMenuUtilities.OnDeleteCommandCanExecute(e, this.argumentsDataGrid);
602         }
603
604         private void OnDeleteCommandExecuted(object sender, ExecutedRoutedEventArgs e)
605         {
606             if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count > 0)
607             {
608                 List<ModelItem> list = new List<ModelItem>();
609                 foreach (object item in this.argumentsDataGrid.SelectedItems)
610                 {
611                     DesignTimeArgument designTimeArgument = item as DesignTimeArgument;
612                     if (designTimeArgument != null)
613                     {
614                         list.Add(designTimeArgument.ReflectedObject);
615                     }
616                 }
617
618                 foreach (ModelItem modelItem in list)
619                 {
620                     foreach (DesignTimeArgument designTimeArgument in this.argumentWrapperCollection)
621                     {
622                         if (designTimeArgument.ReflectedObject == modelItem)
623                         {
624                             this.argumentWrapperCollection.Remove(designTimeArgument);
625                             break;
626                         }
627                     }
628                 }
629             }
630
631             e.Handled = true;
632         }
633
634         private void OnAnnotationSeparatorLoaded(object sender, RoutedEventArgs e)
635         {
636             ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
637         }
638
639         private void OnAddAnnotationMenuLoaded(object sender, RoutedEventArgs e)
640         {
641             ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
642         }
643
644         private void OnAddAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
645         {
646             ContextMenuUtilities.OnAddAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
647         }
648
649         private void OnAddAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
650         {
651             if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
652             {
653                 AnnotationDialog dialog = new AnnotationDialog();
654                 dialog.Context = Context;
655                 dialog.Title = SR.AddAnnotationTitle;
656
657                 WindowHelperService service = this.Context.Services.GetService<WindowHelperService>();
658                 if (null != service)
659                 {
660                     service.TrySetWindowOwner(this, dialog);
661                 }
662                 dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
663
664                 if (dialog.ShowDialog() == true)
665                 {
666                     string annotationText = dialog.AnnotationText;
667
668                     DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
669                     variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].SetValue(annotationText);
670                 }
671             }
672
673             e.Handled = true;
674         }
675
676         private void OnEditAnnotationMenuLoaded(object sender, RoutedEventArgs e)
677         {
678             ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
679         }
680
681         private void OnEditAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
682         {
683             // call the same method as delete annotation command
684             ContextMenuUtilities.OnDeleteAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
685         }
686
687         private void OnEditAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
688         {
689             if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
690             {
691                 DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
692
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;
697
698                 WindowHelperService service = this.Context.Services.GetService<WindowHelperService>();
699                 if (null != service)
700                 {
701                     service.TrySetWindowOwner(this, dialog);
702                 }
703                 dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
704
705                 if (dialog.ShowDialog() == true)
706                 {
707                     string annotationText = dialog.AnnotationText;
708
709                     variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].SetValue(annotationText);
710                 }
711             }
712         }
713
714         private void OnDeleteAnnotationMenuLoaded(object sender, RoutedEventArgs e)
715         {
716             ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
717         }
718
719         private void OnDeleteAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
720         {
721             ContextMenuUtilities.OnDeleteAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
722         }
723
724         private void OnDeleteAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
725         {
726             if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
727             {
728                 DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
729                 variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].ClearValue();
730             }
731
732             e.Handled = true;
733         }
734     }
735
736     sealed class DesignTimeArgument : DesignObjectWrapper
737     {
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";
746
747         static readonly string[] Properties =
748             new string[] { ArgumentNameProperty, ArgumentTypeProperty, ArgumentDirectionProperty, ArgumentDefaultValueProperty, IsOutputArgument, OwnerSchemaProperty, IsRequiredProperty };
749
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;
758
759         public DesignTimeArgument()
760         {
761             throw FxTrace.Exception.AsError(new NotSupportedException(SR.InvalidConstructorCall));
762         }
763
764         internal DesignTimeArgument(ModelItem argument, ArgumentDesigner editor)
765             : base(argument)
766         {
767             this.Editor = editor;
768             this.ReflectedObject.Properties["Attributes"].Collection.CollectionChanged += new NotifyCollectionChangedEventHandler(OnAttributesChanged);
769             this.identifierName = new VBIdentifierName(true)
770             {
771                 IdentifierName = (string)argument.Properties[ArgumentNameProperty].ComputedValue
772             };
773         }
774
775         void OnAttributesChanged(object sender, NotifyCollectionChangedEventArgs e)
776         {
777             this.RaisePropertyChangedEvent(IsRequiredProperty);
778         }
779
780         public override void Dispose()
781         {
782             this.ReflectedObject.Properties["Attributes"].Collection.CollectionChanged -= new NotifyCollectionChangedEventHandler(OnAttributesChanged);
783             base.Dispose();
784         }
785
786         #region Initialize type properties code
787         public static PropertyDescriptorData[] InitializeTypeProperties()
788         {
789             return new PropertyDescriptorData[]
790             {
791                 new PropertyDescriptorData()
792                 {
793                     PropertyName = ArgumentNameProperty,
794                     PropertyType = typeof(VBIdentifierName),
795                     PropertyAttributes = TypeDescriptor.GetAttributes(typeof(VBIdentifierName)).OfType<Attribute>().ToArray(),
796                     PropertySetter = (instance, newValue) =>
797                         {
798                             ((DesignTimeArgument)instance).SetArgumentName((VBIdentifierName)newValue);
799                         },
800                     PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentName()),
801                     PropertyValidator  = (instance, value, errors) => (((DesignTimeArgument)instance).ValidateArgumentName(value, errors))
802                 },
803                 new PropertyDescriptorData()
804                 {
805                     PropertyName = ArgumentTypeProperty,
806                     PropertyType = typeof(Type),
807                     PropertyAttributes = TypeDescriptor.GetAttributes(typeof(Type)).OfType<Attribute>().ToArray(),
808                     PropertySetter = (instance, newValue) =>
809                         {
810                             ((DesignTimeArgument)instance).SetArgumentType((Type)newValue);
811                         },
812                     PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentType()),
813                     PropertyValidator = null
814                 },
815                 new PropertyDescriptorData()
816                 {
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) =>
821                         {
822                             ((DesignTimeArgument)instance).SetArgumentDirection((PropertyKind)newValue);
823                         },
824                     PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentDirection()),
825                     PropertyValidator  = null
826                 },
827                 new PropertyDescriptorData()
828                 {
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) =>
833                         {
834                             ((DesignTimeArgument)instance).SetArgumentValue(newValue);
835                         },
836                     PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentValue()),
837                     PropertyValidator  = (instance, value, errors) => (((DesignTimeArgument)instance).ValidateArgumentValue(value, errors)),
838                 },
839                 new PropertyDescriptorData()
840                 {
841                     PropertyName = IsOutputArgument,
842                     PropertyType = typeof(bool),
843                     PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
844                     PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetIsOutputArgument()), 
845                     PropertyValidator = null,
846                 },
847                 new PropertyDescriptorData()
848                 {
849                     PropertyName = OwnerSchemaProperty,
850                     PropertyType = typeof(ModelItem),
851                     PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
852                     PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetOwnerSchemaProperty()),
853                 },
854                 new PropertyDescriptorData()
855                 {
856                     PropertyName = IsRequiredProperty,
857                     PropertyType = typeof(bool),
858                     PropertyAttributes = TypeDescriptor.GetAttributes(typeof(bool)).OfType<Attribute>().Union(
859                         new Attribute[] 
860                         { 
861                             new EditorAttribute(typeof(IsRequiredPropertyEditor), typeof(PropertyValueEditor)), 
862                             new EditorReuseAttribute(false) 
863                         }
864                     ).ToArray(),
865                     PropertySetter = (instance, newValue) =>
866                     {
867                         ((DesignTimeArgument)instance).SetIsRequired(newValue);
868                     },
869                     PropertyValidator = null,
870                     PropertyGetter = (instance) =>
871                     {
872                         return ((DesignTimeArgument)instance).GetIsRequired();
873                     }
874                 },
875                 new PropertyDescriptorData()
876                 {
877                     PropertyName = AnnotationTextProperty,
878                     PropertyType = typeof(string),
879                     PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
880                     PropertySetter = (instance, newValue) =>
881                         {
882                             ((DesignTimeArgument)instance).SetAnnotationText(newValue);
883                         },
884                     PropertyValidator = null,
885                     PropertyGetter = (instance) =>
886                         {
887                             return ((DesignTimeArgument)instance).GetAnnotationText();
888                         }
889                 },
890             };
891         }
892         #endregion
893
894         internal ArgumentDesigner Editor { get; private set; }
895
896         protected override string AutomationId
897         {
898             get
899             {
900                 return this.GetArgumentNameString();
901             }
902         }
903
904         internal VBIdentifierName GetArgumentName()
905         {
906             return this.identifierName;
907         }
908
909         string GetArgumentNameString()
910         {
911             return (string)this.ReflectedObject.Properties[ArgumentNameProperty].ComputedValue;
912         }
913
914         // For screen reader to read the DataGrid row.
915         public override string ToString()
916         {
917             string name = this.GetArgumentNameString();
918             if (!string.IsNullOrEmpty(name))
919             {
920                 return name;
921             }
922             return "Argument";
923         }
924
925         object GetAnnotationText()
926         {
927             ModelProperty property = this.ReflectedObject.Properties.Find(Annotation.AnnotationTextPropertyName);
928
929             if (property != null)
930             {
931                 return property.ComputedValue;
932             }
933             else
934             {
935                 return null;
936             }
937         }
938
939         void SetAnnotationText(object annotationText)
940         {
941             ModelProperty property = this.ReflectedObject.Properties.Find(Annotation.AnnotationTextPropertyName);
942
943             if (property != null)
944             {
945                 property.SetValue(annotationText);
946             }
947         }
948
949         void SetArgumentName(VBIdentifierName identifierName)
950         {
951             using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentNameDescription")))
952             {
953                 this.identifierName = identifierName;
954                 string name = identifierName.IdentifierName;
955                 this.Editor.UpdateArgumentName(this, name, (string)this.ReflectedObject.Properties[ArgumentNameProperty].ComputedValue);
956
957                 scope.Complete();
958             }
959         }
960
961         internal Type GetArgumentType()
962         {
963             Type result = (Type)this.ReflectedObject.Properties["Type"].ComputedValue;
964             if (this.GetArgumentDirection() != PropertyKind.Property)
965             {
966                 result = result.GetGenericArguments()[0];
967             }
968             return result;
969         }
970
971         void SetArgumentType(Type type)
972         {
973             using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentTypeDescription")))
974             {
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);
980                 scope.Complete();
981             }
982         }
983
984         internal PropertyKind GetArgumentDirection()
985         {
986             PropertyKind result = PropertyKind.Property;
987             Type argumentType = (Type)this.ReflectedObject.Properties["Type"].ComputedValue;
988             if (inArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
989             {
990                 result = PropertyKind.InArgument;
991             }
992             else if (outArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
993             {
994                 result = PropertyKind.OutArgument;
995             }
996             else if (inOutArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
997             {
998                 result = PropertyKind.InOutArgument;
999             }
1000             return result;
1001         }
1002
1003         void SetArgumentDirection(PropertyKind direction)
1004         {
1005             using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentDirectionDescription")))
1006             {
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)
1012                 {
1013                     this.SetIsRequired(false);
1014                 }
1015                 scope.Complete();
1016             }
1017         }
1018
1019         Type GetTypeReference(PropertyKind direction, Type type)
1020         {
1021             Type targetType = null;
1022             switch (direction)
1023             {
1024                 case PropertyKind.InArgument:
1025                     targetType = typeof(InArgument<>).MakeGenericType(type);
1026                     break;
1027
1028                 case PropertyKind.OutArgument:
1029                     targetType = typeof(OutArgument<>).MakeGenericType(type);
1030                     break;
1031
1032                 case PropertyKind.InOutArgument:
1033                     targetType = typeof(InOutArgument<>).MakeGenericType(type);
1034                     break;
1035
1036                 case PropertyKind.Property:
1037                     targetType = type;
1038                     break;
1039
1040                 default:
1041                     throw FxTrace.Exception.AsError(new NotSupportedException(direction.ToString()));
1042             }
1043             return targetType;
1044         }
1045
1046         void SetArgumentValue(object value)
1047         {
1048             this.argumentExpressionChanged = true;
1049             if (PropertyKind.Property == this.GetArgumentDirection())
1050             {
1051                 //handle empty string - reset the value
1052                 if (this.GetArgumentType() != typeof(string) && value is string && string.IsNullOrEmpty((string)value))
1053                 {
1054                     value = null;
1055                 }
1056                 //handle conversion if needed
1057                 else if (null != value && !this.GetArgumentType().IsAssignableFrom(value.GetType()))
1058                 {
1059                     TypeConverter converter = TypeDescriptor.GetConverter(this.GetArgumentType());
1060                     if (converter.CanConvertFrom(value.GetType()))
1061                     {
1062                         value = converter.ConvertFrom(value);
1063                     }
1064                     else
1065                     {
1066                         value = null;
1067                     }
1068                 }
1069                 //else: leave value as is
1070             }
1071             else
1072             {
1073                 if (null != value)
1074                 {
1075                     string direction = null;
1076                     switch (this.GetArgumentDirection())
1077                     {
1078                         case PropertyKind.InArgument:
1079                             direction = ArgumentDirection.In.ToString();
1080                             break;
1081
1082                         case PropertyKind.OutArgument:
1083                             direction = ArgumentDirection.Out.ToString();
1084                             break;
1085
1086                         case PropertyKind.InOutArgument:
1087                             direction = ArgumentDirection.InOut.ToString();
1088                             break;
1089
1090                         default:
1091                             throw FxTrace.Exception.AsError(new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "{0} argument direction is not supported", this.GetArgumentDirection())));
1092                     }
1093                     value = this.Editor.ArgumentToExpressionConverter.ConvertBack(value, typeof(Argument), direction, CultureInfo.CurrentCulture);
1094                 }
1095             }
1096             this.ReflectedObject.Properties[DesignTimeArgument.ArgumentDefaultValueProperty].SetValue(value);
1097         }
1098
1099         internal object GetArgumentValue()
1100         {
1101             ModelItem value = this.ReflectedObject.Properties[DesignTimeArgument.ArgumentDefaultValueProperty].Value;
1102             object result = null;
1103             if (PropertyKind.Property == this.GetArgumentDirection())
1104             {
1105                 if (null != value)
1106                 {
1107                     result = value.GetCurrentValue();
1108                 }
1109             }
1110             else
1111             {
1112                 result = this.Editor.ArgumentToExpressionConverter.Convert(value, typeof(object), null, CultureInfo.CurrentCulture);
1113                 ModelItem expression = result as ModelItem;
1114                 if (null != expression)
1115                 {
1116                     result = expression.GetCurrentValue();
1117                 }
1118             }
1119             return result;
1120         }
1121
1122         bool GetIsOutputArgument()
1123         {
1124             PropertyKind direction = this.GetArgumentDirection();
1125             return (direction == PropertyKind.OutArgument || direction == PropertyKind.InOutArgument);
1126         }
1127
1128         bool IsRequired(IList attributes)
1129         {
1130             if (attributes == null)
1131             {
1132                 return false;
1133             }
1134             foreach (ModelItem item in attributes)
1135             {
1136                 if (typeof(RequiredArgumentAttribute).IsAssignableFrom(item.ItemType))
1137                 {
1138                     return true;
1139                 }
1140             }
1141             return false;
1142         }
1143
1144         bool GetIsRequired()
1145         {
1146             ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
1147             return IsRequired(attributes);
1148         }
1149
1150         void AddIsRequiredAttribute()
1151         {
1152             ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
1153             using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentIsRequiredDescription")))
1154             {
1155                 attributes.Add(new RequiredArgumentAttribute());
1156                 scope.Complete();
1157             }
1158         }
1159
1160         void RemoveIsRequiredAttribute()
1161         {
1162             ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
1163             using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentIsRequiredDescription")))
1164             {
1165                 foreach (ModelItem toRemove in attributes.Where<ModelItem>(p => typeof(RequiredArgumentAttribute).IsAssignableFrom(p.ItemType)))
1166                 {
1167                     attributes.Remove(toRemove);
1168                 }
1169                 scope.Complete();
1170             }
1171         }
1172
1173         void SetIsRequired(object isRequired)
1174         {
1175             bool required = isRequired is ModelItem ? (bool)(((ModelItem)isRequired).GetCurrentValue()) : (bool)isRequired;
1176
1177             if (required && !this.GetIsRequired())
1178             {
1179                 this.AddIsRequiredAttribute();
1180             }
1181             else if (!required && this.GetIsRequired())
1182             {
1183                 this.RemoveIsRequiredAttribute();
1184             }
1185         }
1186
1187         internal bool Filter(Type type)
1188         {
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);
1191         }
1192
1193         internal ModelItem GetOwnerSchemaProperty()
1194         {
1195             return this.ReflectedObject.Parent.Parent;
1196         }
1197
1198         protected override Type OnGetDynamicPropertyValueEditorType(string propertyName)
1199         {
1200             var type = this.GetArgumentType();
1201             var direction = this.GetArgumentDirection();
1202
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))
1206             {
1207                 return typeof(InvalidXamlMemberValueEditor);
1208             }
1209
1210             //in case of arguments which contain handles - display HandleValueEditor
1211             if (typeof(Handle).IsAssignableFrom(type))
1212             {
1213                 return typeof(HandleValueEditor);
1214             }
1215
1216
1217             //check if there are custom editors on the variable's type
1218             Type argumentType = null;
1219             switch (direction)
1220             {
1221                 case PropertyKind.InArgument:
1222                     argumentType = typeof(InArgument<>).MakeGenericType(type);
1223                     break;
1224
1225                 case PropertyKind.InOutArgument:
1226                     argumentType = typeof(InOutArgument<>).MakeGenericType(type);
1227                     break;
1228
1229                 case PropertyKind.OutArgument:
1230                     argumentType = typeof(OutArgument<>).MakeGenericType(type);
1231                     break;
1232
1233                 default:
1234                     argumentType = type;
1235                     break;
1236             }
1237
1238             var referenceType = typeof(PropertyValueEditor);
1239             var expressionEditorType = typeof(ExpressionValueEditor);
1240
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>()
1249                 .Where(p =>
1250                     {
1251                         Type currentType = Type.GetType(p.EditorTypeName);
1252                         return (expressionEditorType != currentType && referenceType.IsAssignableFrom(currentType));
1253                     })
1254                 .Select(p => Type.GetType(p.EditorTypeName))
1255                 .FirstOrDefault();
1256
1257             //if yes - check if there is at least one editor assigner and it derives from PropertyValueEditor 
1258             if (null != customEditorType)
1259             {
1260                 return customEditorType;
1261             }
1262
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)
1266             {
1267                 return typeof(ValueNotSupportedEditor);
1268             }
1269
1270             //otherwise - return default expression value editor
1271             return typeof(DefaultValueEditor);
1272         }
1273
1274         internal bool ValidateArgumentName(object value, List<string> errors)
1275         {
1276             VBIdentifierName identifier = value as VBIdentifierName;
1277             string name = identifier.IdentifierName;
1278
1279             if (string.IsNullOrEmpty(name))
1280             {
1281                 errors.Add(SR.EmptyArgumentName);
1282             }
1283             else
1284             {
1285                 if (!VBIdentifierName.IsValidXamlName(name))
1286                 {
1287                     errors.Add(string.Format(CultureInfo.CurrentUICulture, SR.InvalidXamlMemberName, name));
1288                 }
1289                 else
1290                 {
1291                     ModelItemCollection argumentCollection = (ModelItemCollection)this.ReflectedObject.Parent;
1292
1293                     bool duplicates =
1294                         argumentCollection.Any<ModelItem>(p => string.Equals(p.Properties["Name"].ComputedValue, name) && !ModelItem.Equals(p, this.ReflectedObject));
1295
1296                     if (duplicates)
1297                     {
1298                         errors.Add(string.Format(CultureInfo.CurrentUICulture, SR.DuplicateArgumentName, name));
1299                     }
1300                 }
1301             }
1302             return 0 == errors.Count;
1303         }
1304
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)
1310         {
1311             if (PropertyKind.Property == this.GetArgumentDirection())
1312             {
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))
1315                 {
1316                     return true;
1317                 }
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()))
1320                 {
1321                     try
1322                     {
1323                         TypeConverter converter = TypeDescriptor.GetConverter(this.GetArgumentType());
1324                         converter.ConvertFrom(value);
1325                     }
1326                     catch (Exception err)
1327                     {
1328                         errors.Add(err.Message);
1329                     }
1330                 }
1331             }
1332             return 0 == errors.Count;
1333         }
1334
1335         string GetArgumentValueExpressionText()
1336         {
1337             string currentExpressionText = null;
1338             object currentValue = this.GetArgumentValue();
1339             if (null != currentValue)
1340             {
1341                 if (this.GetArgumentDirection() == PropertyKind.Property)
1342                 {
1343                     TypeConverter oldConverter = TypeDescriptor.GetConverter(this.GetArgumentType());
1344
1345                     if (oldConverter.CanConvertTo(typeof(string)))
1346                     {
1347                         currentExpressionText = (string)oldConverter.ConvertTo(currentValue, typeof(string));
1348                     }
1349                 }
1350                 else
1351                 {
1352                     ModelItem expression = null;
1353                     if (this.ReflectedObject.TryGetPropertyValue(out expression, ArgumentDefaultValueProperty, "Expression") && null != expression)
1354                     {
1355                         var activity = expression.GetCurrentValue() as ActivityWithResult;
1356                         if (null != activity)
1357                         {
1358                             currentExpressionText = ExpressionHelper.GetExpressionString(activity);
1359                         }
1360                     }
1361                 }
1362             }
1363             return currentExpressionText;
1364         }
1365
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)
1371         {
1372             if (newDirection == PropertyKind.Property)
1373             {
1374                 string currentExpressionText = this.GetArgumentValueExpressionText();
1375                 if (null != currentExpressionText)
1376                 {
1377                     TypeConverter converter = TypeDescriptor.GetConverter(newType);
1378                     if (converter.CanConvertFrom(typeof(string)))
1379                     {
1380                         try
1381                         {
1382                             object value = converter.ConvertFrom(currentExpressionText);
1383                             this.ReflectedObject.Properties[ArgumentDefaultValueProperty].SetValue(value);
1384                         }
1385                         catch (Exception err)
1386                         {
1387                             System.Diagnostics.Debug.WriteLine(err.ToString());
1388                             this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1389                         }
1390                     }
1391                     else
1392                     {
1393                         this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1394                     }
1395                 }
1396                 else
1397                 {
1398                     this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1399                 }
1400             }
1401             else if (newDirection == PropertyKind.InArgument)
1402             {
1403                 Argument currentArgument = this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ComputedValue as Argument;
1404                 ActivityWithResult newExpression = null;
1405                 bool succeeded = false;
1406                 if (currentArgument != null)
1407                 {
1408                     succeeded = ExpressionHelper.TryMorphExpression(currentArgument.Expression, false, newType, this.Context, out newExpression);
1409                 }                                 
1410                 else
1411                 {
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))
1415                     {                        
1416                         string rootEditorSetting = ExpressionHelper.GetRootEditorSetting(this.ModelTreeManager, WorkflowDesigner.GetTargetFramework(this.Context));
1417                         if (!string.IsNullOrEmpty(rootEditorSetting))
1418                         {
1419                             succeeded = ExpressionTextBox.TryConvertFromString(rootEditorSetting, currentExpressionText, false, newType, out newExpression);
1420                         }
1421                     }
1422                 }
1423
1424                 if (succeeded)
1425                 {
1426                     Argument newArgument = Argument.Create(newType, ArgumentDirection.In);
1427                     newArgument.Expression = newExpression;
1428                     this.ReflectedObject.Properties[ArgumentDefaultValueProperty].SetValue(newArgument);
1429                 }
1430                 else
1431                 {
1432                     //currently if the value cannot be morphed, it's cleared.
1433                     this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1434                 }
1435             }
1436             else
1437             {
1438                 this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
1439             }
1440         }
1441
1442         protected override void OnReflectedObjectPropertyChanged(string propertyName)
1443         {
1444             if (string.Equals(propertyName, "Type"))
1445             {
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);
1451             }
1452             else if (propertyName == ArgumentNameProperty)
1453             {
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();
1457
1458                 //This is invoked in undo stack
1459                 if (oldValue != newValue)
1460                 {
1461                     this.identifierName = new VBIdentifierName(true)
1462                     {
1463                         IdentifierName = newValue
1464                     };
1465                     Editor.ValidateArgumentName(this.identifierName, newValue, oldValue);
1466                 }
1467             }
1468             else if (propertyName == ArgumentDefaultValueProperty)
1469             {
1470                 this.argumentExpressionChanged = true;
1471             }
1472             else if (propertyName == Annotation.AnnotationTextPropertyName)
1473             {
1474                 RaisePropertyChangedEvent(AnnotationTextProperty);
1475             }
1476         }
1477
1478         protected override void OnPropertyChanged(string propertyName)
1479         {
1480             if (string.Equals(propertyName, ArgumentNameProperty))
1481             {
1482                 this.RaisePropertyChangedEvent(AutomationIdProperty);
1483             }
1484             else if (string.Equals(propertyName, TimestampProperty))
1485             {
1486                 if ((!this.argumentExpressionChanged) && (this.Editor != null))
1487                 {
1488                     this.CustomValueEditors.Clear();
1489                     this.Editor.UpdateTypeDesigner(this);
1490                 }
1491                 else
1492                 {
1493                     this.argumentExpressionChanged = false;
1494                 }
1495             }
1496             else if (string.Equals(propertyName, ArgumentDirectionProperty) || (string.Equals(propertyName, ArgumentTypeProperty)))
1497             {
1498                 this.RaisePropertyChangedEvent(ArgumentDefaultValueProperty);
1499             }
1500             base.OnPropertyChanged(propertyName);
1501         }
1502
1503         internal sealed class DirectionPropertyEditor : PropertyValueEditor
1504         {
1505             public DirectionPropertyEditor()
1506             {
1507                 this.InlineEditorTemplate = EditorResources.GetResources()["DirectionEditor_InlineEditorTemplate"] as DataTemplate;
1508             }
1509         }
1510
1511         internal sealed class DefaultValueEditor : ExpressionValueEditor
1512         {
1513             public DefaultValueEditor()
1514             {
1515                 this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument"] as DataTemplate;
1516             }
1517         }
1518
1519         internal sealed class IsRequiredPropertyEditor : PropertyValueEditor
1520         {
1521             public IsRequiredPropertyEditor()
1522             {
1523                 this.InlineEditorTemplate = EditorResources.GetResources()["IsRequiredPropertyEditor_InlineEditorTemplate"] as DataTemplate;
1524             }
1525         }
1526
1527         internal sealed class ValueNotSupportedEditor : PropertyValueEditor
1528         {
1529             public ValueNotSupportedEditor()
1530             {
1531                 this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument_ValueNotSupported"] as DataTemplate;
1532             }
1533         }
1534
1535         internal sealed class InvalidXamlMemberValueEditor : PropertyValueEditor
1536         {
1537             public InvalidXamlMemberValueEditor()
1538             {
1539                 this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument_InvalidXamlMember"] as DataTemplate;
1540             }
1541         }
1542     }
1543
1544     sealed class PropertyValueTextBox : TextBox
1545     {
1546         protected override void OnInitialized(EventArgs e)
1547         {
1548             base.OnInitialized(e);
1549             this.Loaded += (s, args) =>
1550                 {
1551                     //get the binding expression, and hook up exception filter
1552                     var expr = this.GetBindingExpression(PropertyValueTextBox.TextProperty);
1553                     if (null != expr && null != expr.ParentBinding)
1554                     {
1555                         expr.ParentBinding.UpdateSourceExceptionFilter = this.OnUpdateBindingException;
1556                     }
1557                 };
1558         }
1559
1560         object OnUpdateBindingException(object sender, Exception err)
1561         {
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)
1564             {
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();
1569             }
1570             return null;
1571         }
1572     }
1573
1574     public enum PropertyKind
1575     {
1576         InArgument,
1577         InOutArgument,
1578         OutArgument,
1579         Property
1580     }
1581 }