File: cdf\src\NetFx40\Tools\System.Activities.Presentation\System\Activities\Presentation\View\ArgumentDesigner.xaml.cs
Project: ndp\System.Data.csproj (System.Data)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.Activities.Presentation.View
{
    using System;
    using System.Activities.Presentation.Annotations;
    using System.Activities.Presentation.Converters;
    using System.Activities.Presentation.Expressions;
    using System.Activities.Presentation.Hosting;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.PropertyEditing;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Runtime;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;
    using System.Windows.Threading;
    using System.Xaml;
 
    partial class ArgumentDesigner
    {
        public static readonly DependencyProperty ContextProperty = DependencyProperty.Register(
            "Context",
            typeof(EditingContext),
            typeof(ArgumentDesigner),
            new FrameworkPropertyMetadata(null, OnContextChanged));
 
        public static readonly DependencyProperty ActivitySchemaProperty = DependencyProperty.Register(
            "ActivitySchema",
            typeof(ModelItem),
            typeof(ArgumentDesigner),
            new FrameworkPropertyMetadata(OnActivitySchemaChanged));
 
        public static readonly RoutedEvent ArgumentCollectionChangedEvent = EventManager.RegisterRoutedEvent(
            "ArgumentCollectionChanged",
            RoutingStrategy.Bubble,
            typeof(RoutedEventHandler),
            typeof(ArgumentDesigner));
 
        static readonly string DefaultArgumentName = "argument";
        static readonly string Members = "Properties";
        static readonly string ArgumentNamePropertyName = "Name";
 
        ObservableCollection<DesignTimeArgument> argumentWrapperCollection = new ObservableCollection<DesignTimeArgument>();
 
        bool isCollectionLoaded = false;
        bool isDataGridPopulating = false;
        ModelItem lastSelection;
        bool isSelectionChangeInternal = false;
        ArgumentToExpressionConverter argumentToExpressionConverter;
        DataGridHelper dgHelper;
 
        public ArgumentDesigner()
        {
            InitializeComponent();
 
            this.dgHelper = new DataGridHelper(this.argumentsDataGrid, this);
            this.dgHelper.Context = this.Context;
            this.dgHelper.AddNewRowContent = (string)this.FindResource("addNewArgumentTitle");
            this.dgHelper.AddNewRowCommand = DesignerView.CreateArgumentCommand;
            this.dgHelper.ResolveDynamicTemplateCallback = this.OnResolveDynamicContentTemplate;
            this.dgHelper.LoadDynamicContentDataCallback = this.OnShowExtendedValueEditor;
            this.dgHelper.LoadCustomPropertyValueEditorCallback = this.OnLoadExtendedValueEditor;
 
            this.argumentsDataGrid.SelectionChanged += OnDataGridArgumentSelected;
            this.argumentsDataGrid.GotFocus += OnDataGridArgumentSelected;
 
            this.argumentWrapperCollection.CollectionChanged += OnArgumentWrapperCollectionChanged;
            this.argumentsDataGrid.ItemsSource = this.argumentWrapperCollection;
 
            this.argumentsDataGrid.LayoutUpdated += OnArgumentDataGridLayoutUpdated;
        }
 
        public event RoutedEventHandler ArgumentCollectionChanged
        {
            add
            {
                AddHandler(ArgumentCollectionChangedEvent, value);
            }
            remove
            {
                RemoveHandler(ArgumentCollectionChangedEvent, value);
            }
        }
 
 
        public ModelItem ActivitySchema
        {
            get { return (ModelItem)GetValue(ActivitySchemaProperty); }
            set { SetValue(ActivitySchemaProperty, value); }
        }
 
        public EditingContext Context
        {
            get { return (EditingContext)GetValue(ContextProperty); }
            set { SetValue(ContextProperty, value); }
        }
 
        internal ArgumentToExpressionConverter ArgumentToExpressionConverter
        {
            get
            {
                if (null == this.argumentToExpressionConverter)
                {
                    this.argumentToExpressionConverter = new ArgumentToExpressionConverter();
                }
                return this.argumentToExpressionConverter;
            }
        }
 
        public bool CreateNewArgumentWrapper()
        {
            bool result = false;
 
            if (null != this.ActivitySchema)
            {
                DynamicActivityProperty property = new DynamicActivityProperty()
                {
                    Name = this.GetDefaultName(),
                    Type = this.GetDefaultType(),
                };
                DesignTimeArgument wrapper = null;
                using (ModelEditingScope scope = this.ActivitySchema.BeginEdit((string)this.FindResource("addNewArgumentDescription")))
                {
                    ModelItem argument = this.GetArgumentCollection().Add(property);
                    wrapper = new DesignTimeArgument(argument, this);
                    this.argumentWrapperCollection.Add(wrapper);
                    scope.Complete();
                    result = true;
                }
                this.dgHelper.BeginRowEdit(wrapper);
            }
            return result;
        }
 
        ModelItemCollection GetArgumentCollection()
        {
            if (this.ActivitySchema != null)
            {
                Fx.Assert(this.ActivitySchema.Properties[Members] != null, "Members collection not found!");
                return this.ActivitySchema.Properties[Members].Collection;
            }
            return null;
        }
 
 
        string GetDefaultName()
        {
            ModelItemCollection argumentCollection = this.GetArgumentCollection();
            return argumentCollection.GetUniqueName(ArgumentDesigner.DefaultArgumentName, (arg) => ((string)arg.Properties["Name"].ComputedValue));
        }
 
        Type GetDefaultType()
        {
            return typeof(InArgument<string>);
        }
 
        void Populate()
        {
            if (!this.isCollectionLoaded)
            {
                this.argumentsDataGrid.ItemsSource = null;
                this.argumentWrapperCollection.All(p => { p.Dispose(); return true; });
                this.argumentWrapperCollection.Clear();
                ModelItemCollection arguments = this.GetArgumentCollection();
                if (null != arguments)
                {
                    foreach (ModelItem argument in arguments)
                    {
                        this.argumentWrapperCollection.Add(new DesignTimeArgument(argument, this));
                    }
                }
                this.argumentsDataGrid.ItemsSource = this.argumentWrapperCollection;
                this.isCollectionLoaded = true;
            }
        }
 
        void StoreLastSelection()
        {
            if (!this.isSelectionChangeInternal)
            {
                ModelItem current = this.Context.Items.GetValue<Selection>().PrimarySelection;
                if (null == current || !typeof(DesignTimeArgument).IsAssignableFrom(current.ItemType))
                {
                    this.lastSelection = current;
                }
            }
        }
 
        void OnArgumentTypeTypePresenterLoaded(object sender, RoutedEventArgs args)
        {
            TypePresenter argumentTypeTypePresenter = ((TypePresenter)sender);
            argumentTypeTypePresenter.Filter = ((DesignTimeArgument)argumentTypeTypePresenter.DataContext).Filter;
            DataGridHelper.OnEditingControlLoaded(sender, args);
        }
 
        void OnArgumentTypeTypePresenterUnloaded(object sender, RoutedEventArgs args)
        {
            DataGridHelper.OnEditingControlUnloaded(sender, args);
        }
 
        internal void SelectArgument(ModelItem argument)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                foreach (object item in this.argumentsDataGrid.Items)
                {
                    if (item is DesignTimeArgument)
                    {
                        if (object.ReferenceEquals(((DesignTimeArgument)item).ReflectedObject, argument))
                        {
                            this.argumentsDataGrid.SelectedItem = item;
                            this.argumentsDataGrid.ScrollIntoView(item, null);
                        }
                    }
                }
            }), DispatcherPriority.ApplicationIdle);
        }
 
        void OnDataGridArgumentSelected(object sender, RoutedEventArgs e)
        {
            if (null != this.Context && !this.isSelectionChangeInternal)
            {
                this.isSelectionChangeInternal = true;
                DesignTimeArgument argument = this.dgHelper.SelectedItem<DesignTimeArgument>();
                if (null != argument)
                {
                    this.Context.Items.SetValue(new Selection(argument.Content));
                }
                else
                {
                    // clear arguments in selection
                    Selection oldSelection = this.Context.Items.GetValue<Selection>();
                    List<ModelItem> newSelection = new List<ModelItem>();
                    if (oldSelection != null && oldSelection.SelectionCount > 0)
                    {
                        foreach (ModelItem item in oldSelection.SelectedObjects)
                        {
                            if (item.ItemType != typeof(DesignTimeArgument))
                            {
                                newSelection.Add(item);
                            }
                        }
                    }
                    this.Context.Items.SetValue(new Selection(newSelection));
                }
                this.isSelectionChangeInternal = false;
            }
        }
 
        void OnArgumentDataGridLayoutUpdated(object sender, EventArgs e)
        {
            if (this.isDataGridPopulating)
            {
                this.isDataGridPopulating = false;
                Mouse.OverrideCursor = null;
            }
        }
 
        void OnActivitySchemaChanged(ModelItem newSchemaItem)
        {
            this.isCollectionLoaded = false;
 
            if (null != newSchemaItem && null != newSchemaItem.Properties[Members])
            {
                //lazy initialization, wait till it is visible
                if (this.Visibility == Visibility.Visible)
                {
                    this.Populate();
                }
            }
        }
 
        void OnContextChanged()
        {
            if (null != this.Context)
            {
                this.Context.Items.Subscribe<Selection>(new SubscribeContextCallback<Selection>(OnItemSelected));
            }
            this.dgHelper.Context = this.Context;
        }
 
        void OnItemSelected(Selection selection)
        {
            if (!this.isSelectionChangeInternal)
            {
                this.StoreLastSelection();
 
                bool selectedArgumentIsInSelection = false;
 
                DesignTimeArgument selectedArgument = this.argumentsDataGrid.SelectedItem as DesignTimeArgument;
                if (selectedArgument != null)
                {
                    foreach (ModelItem item in selection.SelectedObjects)
                    {
                        if (object.ReferenceEquals(selectedArgument, item.GetCurrentValue()))
                        {
                            selectedArgumentIsInSelection = true;
                        }
                    }
                }
 
                if (!selectedArgumentIsInSelection)
                {
                    this.argumentsDataGrid.SelectedItem = null;
                }
            }
        }
 
        void OnVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (this.Dispatcher.HasShutdownStarted)
            {
                return;
            }
 
            if ((Boolean)e.NewValue == true)
            {
                // Changing cursor as Populate() might take long to run. Cursor will be restored when DataGrid.LayoutUpdated fires.
                this.isDataGridPopulating = true;
                Mouse.OverrideCursor = Cursors.Wait;
 
                this.StoreLastSelection();
                this.Populate();
            }
            else
            {
                if (this.argumentsDataGrid.SelectedItem != null)
                {
                    // Clear argument selection, if possible, restore last selection.
                    Selection restoredSelection = null == this.lastSelection ? new Selection() : new Selection(this.lastSelection);
                    this.isSelectionChangeInternal = true;
                    this.Context.Items.SetValue(restoredSelection);
                    this.argumentsDataGrid.SelectedItem = null;
                    this.isSelectionChangeInternal = false;
                }
            }
        }
 
        void OnArgumentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            //we need to track argument collection changes caused by undo/redo stack - 
            //in such case, we have to add/remove corresponding items from wrapper collection
            bool isUndoRedoInProgress = this.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress;
            if (isUndoRedoInProgress)
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                        foreach (ModelItem argument in e.NewItems)
                        {
                            var wrapper = this.argumentWrapperCollection
                                .FirstOrDefault(p => (ModelItem.Equals(p.ReflectedObject, argument)));
 
                            if (wrapper == null)
                            {
                                wrapper = new DesignTimeArgument(argument, this);
                                this.argumentWrapperCollection.Add(wrapper);
                            }
                        }
                        break;
 
                    case NotifyCollectionChangedAction.Remove:
                        foreach (ModelItem argument in e.OldItems)
                        {
                            var wrapper = this.argumentWrapperCollection.FirstOrDefault(p => ModelItem.Equals(p.ReflectedObject, argument));
                            if (null != wrapper)
                            {
                                this.argumentWrapperCollection.Remove(wrapper);
                            }
                        }
                        break;
                }
            }
        }
        void OnArgumentWrapperCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            bool isUndoRedoInProgress = this.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress;
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Remove:
                    foreach (DesignTimeArgument arg in e.OldItems)
                    {
                        this.ClearCaseInsensitiveDuplicates(arg.GetArgumentName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue);
                        if (!isUndoRedoInProgress)
                        {
                            ModelItemCollection collection = (ModelItemCollection)arg.ReflectedObject.Parent;
                            collection.Remove(arg.ReflectedObject);
                        }
                        arg.Dispose();
                    }
                    break;
                case NotifyCollectionChangedAction.Add:
                    foreach (DesignTimeArgument arg in e.NewItems)
                    {
                        this.CheckCaseInsensitiveDuplicates(arg.GetArgumentName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue);
                    }
                    break;
            }
        }
 
        bool OnResolveDynamicContentTemplate(ResolveTemplateParams resolveParams)
        {
            var argument = (DesignTimeArgument)resolveParams.Cell.DataContext;
 
            //get editor associated with variable's value
            var editorType = argument.GetDynamicPropertyValueEditorType(DesignTimeArgument.ArgumentDefaultValueProperty);
 
            //if yes there is a custom one - use it
            if (!typeof(DesignTimeArgument.DefaultValueEditor).IsAssignableFrom(editorType))
            {
                //get inline editor template - it will be used for both templates - view and editing; 
                resolveParams.Template = argument.GetDynamicPropertyValueEditor(DesignTimeArgument.ArgumentDefaultValueProperty).InlineEditorTemplate;
                resolveParams.IsDefaultTemplate = false;
            }
            else
            {
                //no custom editor - depending on grid state display either editable or readonly expression template
                string key = string.Empty;
                switch (argument.GetArgumentDirection())
                {
                    case PropertyKind.Property:
                        key = resolveParams.Cell.IsEditing ? "argumentPropertyEditableTemplate" : "argumentPropertyReadOnlyTemplate";
                        break;
 
                    case PropertyKind.InArgument:
                        key = resolveParams.Cell.IsEditing ? "argumentExpressionEditableTemplate" : "argumentExpressionReadOnlyTemplate";
                        break;
 
                    case PropertyKind.OutArgument:
                    case PropertyKind.InOutArgument:
                        key = "argumentOutputValueTemplate";
                        break;
                }
                resolveParams.Template = (DataTemplate)this.FindResource(key);
                resolveParams.IsDefaultTemplate = true;
            }
            return true;
        }
 
        DialogPropertyValueEditor OnLoadExtendedValueEditor(DataGridCell cell, object instance)
        {
            var argument = (DesignObjectWrapper)cell.DataContext;
            return argument.GetDynamicPropertyValueEditor(DesignTimeArgument.ArgumentDefaultValueProperty) as DialogPropertyValueEditor;
        }
 
        ModelProperty OnShowExtendedValueEditor(DataGridCell cell, object instance)
        {
            var argument = (DesignObjectWrapper)cell.DataContext;
            return argument.Content.Properties[DesignTimeArgument.ArgumentDefaultValueProperty];
        }
 
        internal void UpdateTypeDesigner(DesignTimeArgument argument)
        {
            this.dgHelper.UpdateDynamicContentColumns(argument);
        }
 
        //Check case-insensitive duplicates, which are not allowed in VB expressions 
        internal void CheckCaseInsensitiveDuplicates(VBIdentifierName identifierName, string newName)
        {
            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));
            DesignTimeArgument duplicate = this.argumentWrapperCollection.FirstOrDefault<DesignTimeArgument>(checkForDuplicates);
            if (duplicate != null)
            {
                identifierName.IsValid = false;
                identifierName.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateIdentifier, newName);
                VBIdentifierName duplicateIdentifier = duplicate.GetArgumentName();
                if (duplicateIdentifier.IsValid)
                {
                    duplicateIdentifier.IsValid = false;
                    duplicateIdentifier.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateIdentifier, duplicateIdentifier.IdentifierName);
                }
            };
        }
 
        //Check duplicates with old value. When there's only one variable duplicate with the old value, 
        //the only one variable should be valid now after the change
        void ClearCaseInsensitiveDuplicates(VBIdentifierName identifier, string oldName)
        {
            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));
            IEnumerable<DesignTimeArgument> oldDuplicates = this.argumentWrapperCollection.Where<DesignTimeArgument>(checkForOldNameDuplicates);
            if (oldDuplicates.Count<DesignTimeArgument>() == 1)
            {
                DesignTimeArgument wrapper = oldDuplicates.First<DesignTimeArgument>();
                VBIdentifierName oldDuplicate = wrapper.GetArgumentName();
                oldDuplicate.IsValid = true;
                oldDuplicate.ErrorMessage = string.Empty;
            }
        }
 
        internal void ValidateArgumentName(VBIdentifierName identifierName, string newName, string oldName)
        {
            //Check whether there're any variables' name conflict with the old name which can be cleaned up now
            this.ClearCaseInsensitiveDuplicates(identifierName, oldName);
 
            //Check whether there're any duplicates with new name                
            this.CheckCaseInsensitiveDuplicates(identifierName, newName);
        }
 
        static void OnActivitySchemaChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            ModelItem oldItem = e.OldValue as ModelItem;
            ModelItem newItem = e.NewValue as ModelItem;
            ArgumentDesigner designer = (ArgumentDesigner)dependencyObject;
 
            if (null != oldItem && null != oldItem.Properties[Members])
            {
                oldItem.Properties[Members].Collection.CollectionChanged -= designer.OnArgumentCollectionChanged;
            }
            if (null != newItem && null != newItem.Properties[Members])
            {
                newItem.Properties[Members].Collection.CollectionChanged += designer.OnArgumentCollectionChanged;
            }
            designer.OnActivitySchemaChanged(newItem);
        }
 
        static void OnContextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            ((ArgumentDesigner)dependencyObject).OnContextChanged();
        }
 
        internal void UpdateArgumentName(DesignTimeArgument argumentWrapper, string newName, string oldName)
        {
            ModelItemCollection argumentsCollection = this.GetArgumentCollection();
 
            //Since underlying object is an KeyedCollection, if we only update the property value, it won't update the key
            //Need to remove the object and add it again to update the key
            ModelItem argument = argumentWrapper.ReflectedObject;
            argumentsCollection.Remove(argument);
            argument.Properties[ArgumentNamePropertyName].SetValue(newName);
            argumentsCollection.Add(argument);
            this.ValidateArgumentName(argumentWrapper.GetArgumentName(), newName, oldName);
 
            //Update default value editor in Argument designer
            this.UpdateTypeDesigner(argumentWrapper);
        }
 
        void OnEditingControlLoaded(object sender, RoutedEventArgs args)
        {
            DataGridHelper.OnEditingControlLoaded(sender, args);
        }
 
        void OnEditingControlUnloaded(object sender, RoutedEventArgs args)
        {
            DataGridHelper.OnEditingControlUnloaded(sender, args);
        }
 
        // This is to workaround a bug that updating ModelItem from outside of ArgumentDesigner will not update ArgumentDesigner.
        internal void NotifyAnnotationTextChanged()
        {
            foreach (object item in this.argumentsDataGrid.Items)
            {
                DesignTimeArgument designTimeArgument = item as DesignTimeArgument;
                if (designTimeArgument != null)
                {
                    designTimeArgument.NotifyPropertyChanged(DesignTimeArgument.AnnotationTextProperty);
                }
            }
        }
 
        protected override void OnContextMenuOpening(ContextMenuEventArgs e)
        {
            base.OnContextMenuOpening(e);
 
            DesignerConfigurationService configurationService = this.Context.Services.GetService<DesignerConfigurationService>();
            Fx.Assert(configurationService != null, "DesignerConfigurationService should not be null");
            if (configurationService.WorkflowDesignerHostId == WorkflowDesignerHostId.Dev10)
            {
                return;
            }
 
            e.Handled = true;
 
            bool openedByKeyboard = e.CursorLeft < 0 && e.CursorTop < 0;
 
            if (openedByKeyboard)
            {
                this.ContextMenu.Placement = PlacementMode.Center;
            }
            else
            {
                this.ContextMenu.Placement = PlacementMode.MousePoint;
            }
            this.ContextMenu.PlacementTarget = this;
            this.ContextMenu.IsOpen = true;
        }
        
        protected void OnDataGridCellGotFocus(object sender, RoutedEventArgs e)
        {
            if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures)
            {
                DataGridHelper.DataGridCellGotFocus((DataGrid)sender, e);
            }
        }
 
        private void OnDeleteCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            ContextMenuUtilities.OnDeleteCommandCanExecute(e, this.argumentsDataGrid);
        }
 
        private void OnDeleteCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count > 0)
            {
                List<ModelItem> list = new List<ModelItem>();
                foreach (object item in this.argumentsDataGrid.SelectedItems)
                {
                    DesignTimeArgument designTimeArgument = item as DesignTimeArgument;
                    if (designTimeArgument != null)
                    {
                        list.Add(designTimeArgument.ReflectedObject);
                    }
                }
 
                foreach (ModelItem modelItem in list)
                {
                    foreach (DesignTimeArgument designTimeArgument in this.argumentWrapperCollection)
                    {
                        if (designTimeArgument.ReflectedObject == modelItem)
                        {
                            this.argumentWrapperCollection.Remove(designTimeArgument);
                            break;
                        }
                    }
                }
            }
 
            e.Handled = true;
        }
 
        private void OnAnnotationSeparatorLoaded(object sender, RoutedEventArgs e)
        {
            ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
        }
 
        private void OnAddAnnotationMenuLoaded(object sender, RoutedEventArgs e)
        {
            ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
        }
 
        private void OnAddAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            ContextMenuUtilities.OnAddAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
        }
 
        private void OnAddAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
            {
                AnnotationDialog dialog = new AnnotationDialog();
                dialog.Context = Context;
                dialog.Title = SR.AddAnnotationTitle;
 
                WindowHelperService service = this.Context.Services.GetService<WindowHelperService>();
                if (null != service)
                {
                    service.TrySetWindowOwner(this, dialog);
                }
                dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
 
                if (dialog.ShowDialog() == true)
                {
                    string annotationText = dialog.AnnotationText;
 
                    DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
                    variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].SetValue(annotationText);
                }
            }
 
            e.Handled = true;
        }
 
        private void OnEditAnnotationMenuLoaded(object sender, RoutedEventArgs e)
        {
            ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
        }
 
        private void OnEditAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            // call the same method as delete annotation command
            ContextMenuUtilities.OnDeleteAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
        }
 
        private void OnEditAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
            {
                DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
 
                AnnotationDialog dialog = new AnnotationDialog();
                dialog.Context = Context;
                dialog.Title = SR.EditAnnotationTitle;
                dialog.AnnotationText = variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].ComputedValue as string;
 
                WindowHelperService service = this.Context.Services.GetService<WindowHelperService>();
                if (null != service)
                {
                    service.TrySetWindowOwner(this, dialog);
                }
                dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
 
                if (dialog.ShowDialog() == true)
                {
                    string annotationText = dialog.AnnotationText;
 
                    variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].SetValue(annotationText);
                }
            }
        }
 
        private void OnDeleteAnnotationMenuLoaded(object sender, RoutedEventArgs e)
        {
            ContextMenuUtilities.OnAnnotationMenuLoaded(this.Context, (Control)sender, e);
        }
 
        private void OnDeleteAnnotationCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            ContextMenuUtilities.OnDeleteAnnotationCommandCanExecute(e, this.Context, this.argumentsDataGrid);
        }
 
        private void OnDeleteAnnotationCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.argumentsDataGrid != null && this.argumentsDataGrid.SelectedItems != null && this.argumentsDataGrid.SelectedItems.Count == 1)
            {
                DesignTimeArgument variable = (DesignTimeArgument)this.argumentsDataGrid.SelectedItems[0];
                variable.Content.Properties[DesignTimeArgument.AnnotationTextProperty].ClearValue();
            }
 
            e.Handled = true;
        }
    }
 
    sealed class DesignTimeArgument : DesignObjectWrapper
    {
        internal static readonly string ArgumentNameProperty = "Name";
        internal static readonly string ArgumentTypeProperty = "ArgumentType";
        internal static readonly string ArgumentDirectionProperty = "Direction";
        internal static readonly string ArgumentDefaultValueProperty = "Value";
        internal static readonly string IsOutputArgument = "IsOutputArgument";
        internal static readonly string OwnerSchemaProperty = "OwnerActivitySchemaType";
        internal static readonly string IsRequiredProperty = "IsRequired";
        internal static readonly string AnnotationTextProperty = "DesignTimeArgumentAnnotationText";
 
        static readonly string[] Properties =
            new string[] { ArgumentNameProperty, ArgumentTypeProperty, ArgumentDirectionProperty, ArgumentDefaultValueProperty, IsOutputArgument, OwnerSchemaProperty, IsRequiredProperty };
 
        static readonly Type inArgumentTypeReference = typeof(InArgument);
        static readonly Type outArgumentTypeReference = typeof(OutArgument);
        static readonly Type inOutArgumentTypeReference = typeof(InOutArgument);
        static readonly Type stringTypeReference = typeof(string);
        static readonly XamlSchemaContext xamlContext = new XamlSchemaContext();
        static readonly XamlType xamlType = new XamlType(typeof(string), xamlContext);
        bool argumentExpressionChanged = false;
        VBIdentifierName identifierName;
 
        public DesignTimeArgument()
        {
            throw FxTrace.Exception.AsError(new NotSupportedException(SR.InvalidConstructorCall));
        }
 
        internal DesignTimeArgument(ModelItem argument, ArgumentDesigner editor)
            : base(argument)
        {
            this.Editor = editor;
            this.ReflectedObject.Properties["Attributes"].Collection.CollectionChanged += new NotifyCollectionChangedEventHandler(OnAttributesChanged);
            this.identifierName = new VBIdentifierName(true)
            {
                IdentifierName = (string)argument.Properties[ArgumentNameProperty].ComputedValue
            };
        }
 
        void OnAttributesChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.RaisePropertyChangedEvent(IsRequiredProperty);
        }
 
        public override void Dispose()
        {
            this.ReflectedObject.Properties["Attributes"].Collection.CollectionChanged -= new NotifyCollectionChangedEventHandler(OnAttributesChanged);
            base.Dispose();
        }
 
        #region Initialize type properties code
        public static PropertyDescriptorData[] InitializeTypeProperties()
        {
            return new PropertyDescriptorData[]
            {
                new PropertyDescriptorData()
                {
                    PropertyName = ArgumentNameProperty,
                    PropertyType = typeof(VBIdentifierName),
                    PropertyAttributes = TypeDescriptor.GetAttributes(typeof(VBIdentifierName)).OfType<Attribute>().ToArray(),
                    PropertySetter = (instance, newValue) =>
                        {
                            ((DesignTimeArgument)instance).SetArgumentName((VBIdentifierName)newValue);
                        },
                    PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentName()),
                    PropertyValidator  = (instance, value, errors) => (((DesignTimeArgument)instance).ValidateArgumentName(value, errors))
                },
                new PropertyDescriptorData()
                {
                    PropertyName = ArgumentTypeProperty,
                    PropertyType = typeof(Type),
                    PropertyAttributes = TypeDescriptor.GetAttributes(typeof(Type)).OfType<Attribute>().ToArray(),
                    PropertySetter = (instance, newValue) =>
                        {
                            ((DesignTimeArgument)instance).SetArgumentType((Type)newValue);
                        },
                    PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentType()),
                    PropertyValidator = null
                },
                new PropertyDescriptorData()
                {
                    PropertyName = ArgumentDirectionProperty,
                    PropertyType = typeof(PropertyKind),
                    PropertyAttributes = TypeDescriptor.GetAttributes(typeof(PropertyKind)).OfType<Attribute>().Union( new Attribute[] { new EditorAttribute(typeof(DirectionPropertyEditor), typeof(PropertyValueEditor)) }).ToArray(),
                    PropertySetter = (instance, newValue) =>
                        {
                            ((DesignTimeArgument)instance).SetArgumentDirection((PropertyKind)newValue);
                        },
                    PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentDirection()),
                    PropertyValidator  = null
                },
                new PropertyDescriptorData()
                {
                    PropertyName = ArgumentDefaultValueProperty,
                    PropertyType = typeof(object),
                    PropertyAttributes = TypeDescriptor.GetAttributes(typeof(Activity)).OfType<Attribute>().Union(new Attribute[] { new EditorAttribute(typeof(DesignObjectWrapperDynamicPropertyEditor), typeof(PropertyValueEditor)), new EditorReuseAttribute(false) }).ToArray(),
                    PropertySetter = (instance, newValue) =>
                        {
                            ((DesignTimeArgument)instance).SetArgumentValue(newValue);
                        },
                    PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetArgumentValue()),
                    PropertyValidator  = (instance, value, errors) => (((DesignTimeArgument)instance).ValidateArgumentValue(value, errors)),
                },
                new PropertyDescriptorData()
                {
                    PropertyName = IsOutputArgument,
                    PropertyType = typeof(bool),
                    PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
                    PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetIsOutputArgument()), 
                    PropertyValidator = null,
                },
                new PropertyDescriptorData()
                {
                    PropertyName = OwnerSchemaProperty,
                    PropertyType = typeof(ModelItem),
                    PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
                    PropertyGetter = (instance) => (((DesignTimeArgument)instance).GetOwnerSchemaProperty()),
                },
                new PropertyDescriptorData()
                {
                    PropertyName = IsRequiredProperty,
                    PropertyType = typeof(bool),
                    PropertyAttributes = TypeDescriptor.GetAttributes(typeof(bool)).OfType<Attribute>().Union(
                        new Attribute[] 
                        { 
                            new EditorAttribute(typeof(IsRequiredPropertyEditor), typeof(PropertyValueEditor)), 
                            new EditorReuseAttribute(false) 
                        }
                    ).ToArray(),
                    PropertySetter = (instance, newValue) =>
                    {
                        ((DesignTimeArgument)instance).SetIsRequired(newValue);
                    },
                    PropertyValidator = null,
                    PropertyGetter = (instance) =>
                    {
                        return ((DesignTimeArgument)instance).GetIsRequired();
                    }
                },
                new PropertyDescriptorData()
                {
                    PropertyName = AnnotationTextProperty,
                    PropertyType = typeof(string),
                    PropertyAttributes = new Attribute[] { BrowsableAttribute.No },
                    PropertySetter = (instance, newValue) =>
                        {
                            ((DesignTimeArgument)instance).SetAnnotationText(newValue);
                        },
                    PropertyValidator = null,
                    PropertyGetter = (instance) =>
                        {
                            return ((DesignTimeArgument)instance).GetAnnotationText();
                        }
                },
            };
        }
        #endregion
 
        internal ArgumentDesigner Editor { get; private set; }
 
        protected override string AutomationId
        {
            get
            {
                return this.GetArgumentNameString();
            }
        }
 
        internal VBIdentifierName GetArgumentName()
        {
            return this.identifierName;
        }
 
        string GetArgumentNameString()
        {
            return (string)this.ReflectedObject.Properties[ArgumentNameProperty].ComputedValue;
        }
 
        // For screen reader to read the DataGrid row.
        public override string ToString()
        {
            string name = this.GetArgumentNameString();
            if (!string.IsNullOrEmpty(name))
            {
                return name;
            }
            return "Argument";
        }
 
        object GetAnnotationText()
        {
            ModelProperty property = this.ReflectedObject.Properties.Find(Annotation.AnnotationTextPropertyName);
 
            if (property != null)
            {
                return property.ComputedValue;
            }
            else
            {
                return null;
            }
        }
 
        void SetAnnotationText(object annotationText)
        {
            ModelProperty property = this.ReflectedObject.Properties.Find(Annotation.AnnotationTextPropertyName);
 
            if (property != null)
            {
                property.SetValue(annotationText);
            }
        }
 
        void SetArgumentName(VBIdentifierName identifierName)
        {
            using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentNameDescription")))
            {
                this.identifierName = identifierName;
                string name = identifierName.IdentifierName;
                this.Editor.UpdateArgumentName(this, name, (string)this.ReflectedObject.Properties[ArgumentNameProperty].ComputedValue);
 
                scope.Complete();
            }
        }
 
        internal Type GetArgumentType()
        {
            Type result = (Type)this.ReflectedObject.Properties["Type"].ComputedValue;
            if (this.GetArgumentDirection() != PropertyKind.Property)
            {
                result = result.GetGenericArguments()[0];
            }
            return result;
        }
 
        void SetArgumentType(Type type)
        {
            using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentTypeDescription")))
            {
                PropertyKind currentDirection = this.GetArgumentDirection();
                Type propertyType = GetTypeReference(currentDirection, type);
                this.ReflectedObject.Properties["Type"].SetValue(propertyType);
                this.TryUpdateArgumentType(type, currentDirection);
                ImportDesigner.AddImport(type.Namespace, this.Context);
                scope.Complete();
            }
        }
 
        internal PropertyKind GetArgumentDirection()
        {
            PropertyKind result = PropertyKind.Property;
            Type argumentType = (Type)this.ReflectedObject.Properties["Type"].ComputedValue;
            if (inArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
            {
                result = PropertyKind.InArgument;
            }
            else if (outArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
            {
                result = PropertyKind.OutArgument;
            }
            else if (inOutArgumentTypeReference.IsAssignableFrom(argumentType) && argumentType.IsGenericType)
            {
                result = PropertyKind.InOutArgument;
            }
            return result;
        }
 
        void SetArgumentDirection(PropertyKind direction)
        {
            using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentDirectionDescription")))
            {
                Type currentType = this.GetArgumentType();
                Type propertyType = GetTypeReference(direction, currentType);
                this.ReflectedObject.Properties["Type"].SetValue(propertyType);
                this.TryUpdateArgumentType(currentType, direction);
                if (direction == PropertyKind.Property)
                {
                    this.SetIsRequired(false);
                }
                scope.Complete();
            }
        }
 
        Type GetTypeReference(PropertyKind direction, Type type)
        {
            Type targetType = null;
            switch (direction)
            {
                case PropertyKind.InArgument:
                    targetType = typeof(InArgument<>).MakeGenericType(type);
                    break;
 
                case PropertyKind.OutArgument:
                    targetType = typeof(OutArgument<>).MakeGenericType(type);
                    break;
 
                case PropertyKind.InOutArgument:
                    targetType = typeof(InOutArgument<>).MakeGenericType(type);
                    break;
 
                case PropertyKind.Property:
                    targetType = type;
                    break;
 
                default:
                    throw FxTrace.Exception.AsError(new NotSupportedException(direction.ToString()));
            }
            return targetType;
        }
 
        void SetArgumentValue(object value)
        {
            this.argumentExpressionChanged = true;
            if (PropertyKind.Property == this.GetArgumentDirection())
            {
                //handle empty string - reset the value
                if (this.GetArgumentType() != typeof(string) && value is string && string.IsNullOrEmpty((string)value))
                {
                    value = null;
                }
                //handle conversion if needed
                else if (null != value && !this.GetArgumentType().IsAssignableFrom(value.GetType()))
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(this.GetArgumentType());
                    if (converter.CanConvertFrom(value.GetType()))
                    {
                        value = converter.ConvertFrom(value);
                    }
                    else
                    {
                        value = null;
                    }
                }
                //else: leave value as is
            }
            else
            {
                if (null != value)
                {
                    string direction = null;
                    switch (this.GetArgumentDirection())
                    {
                        case PropertyKind.InArgument:
                            direction = ArgumentDirection.In.ToString();
                            break;
 
                        case PropertyKind.OutArgument:
                            direction = ArgumentDirection.Out.ToString();
                            break;
 
                        case PropertyKind.InOutArgument:
                            direction = ArgumentDirection.InOut.ToString();
                            break;
 
                        default:
                            throw FxTrace.Exception.AsError(new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "{0} argument direction is not supported", this.GetArgumentDirection())));
                    }
                    value = this.Editor.ArgumentToExpressionConverter.ConvertBack(value, typeof(Argument), direction, CultureInfo.CurrentCulture);
                }
            }
            this.ReflectedObject.Properties[DesignTimeArgument.ArgumentDefaultValueProperty].SetValue(value);
        }
 
        internal object GetArgumentValue()
        {
            ModelItem value = this.ReflectedObject.Properties[DesignTimeArgument.ArgumentDefaultValueProperty].Value;
            object result = null;
            if (PropertyKind.Property == this.GetArgumentDirection())
            {
                if (null != value)
                {
                    result = value.GetCurrentValue();
                }
            }
            else
            {
                result = this.Editor.ArgumentToExpressionConverter.Convert(value, typeof(object), null, CultureInfo.CurrentCulture);
                ModelItem expression = result as ModelItem;
                if (null != expression)
                {
                    result = expression.GetCurrentValue();
                }
            }
            return result;
        }
 
        bool GetIsOutputArgument()
        {
            PropertyKind direction = this.GetArgumentDirection();
            return (direction == PropertyKind.OutArgument || direction == PropertyKind.InOutArgument);
        }
 
        bool IsRequired(IList attributes)
        {
            if (attributes == null)
            {
                return false;
            }
            foreach (ModelItem item in attributes)
            {
                if (typeof(RequiredArgumentAttribute).IsAssignableFrom(item.ItemType))
                {
                    return true;
                }
            }
            return false;
        }
 
        bool GetIsRequired()
        {
            ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
            return IsRequired(attributes);
        }
 
        void AddIsRequiredAttribute()
        {
            ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
            using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentIsRequiredDescription")))
            {
                attributes.Add(new RequiredArgumentAttribute());
                scope.Complete();
            }
        }
 
        void RemoveIsRequiredAttribute()
        {
            ModelItemCollection attributes = this.ReflectedObject.Properties["Attributes"].Collection;
            using (ModelEditingScope scope = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeArgumentIsRequiredDescription")))
            {
                foreach (ModelItem toRemove in attributes.Where<ModelItem>(p => typeof(RequiredArgumentAttribute).IsAssignableFrom(p.ItemType)))
                {
                    attributes.Remove(toRemove);
                }
                scope.Complete();
            }
        }
 
        void SetIsRequired(object isRequired)
        {
            bool required = isRequired is ModelItem ? (bool)(((ModelItem)isRequired).GetCurrentValue()) : (bool)isRequired;
 
            if (required && !this.GetIsRequired())
            {
                this.AddIsRequiredAttribute();
            }
            else if (!required && this.GetIsRequired())
            {
                this.RemoveIsRequiredAttribute();
            }
        }
 
        internal bool Filter(Type type)
        {
            // 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.
            return this.GetArgumentDirection() != PropertyKind.Property || !type.IsGenericType || !typeof(Argument).IsAssignableFrom(type);
        }
 
        internal ModelItem GetOwnerSchemaProperty()
        {
            return this.ReflectedObject.Parent.Parent;
        }
 
        protected override Type OnGetDynamicPropertyValueEditorType(string propertyName)
        {
            var type = this.GetArgumentType();
            var direction = this.GetArgumentDirection();
 
            //if argument name is not valid XAML member name, default value editing is disabled.
            //Since it cannot be saved.
            if (!VBIdentifierName.IsValidXamlName(this.GetArgumentName().IdentifierName))
            {
                return typeof(InvalidXamlMemberValueEditor);
            }
 
            //in case of arguments which contain handles - display HandleValueEditor
            if (typeof(Handle).IsAssignableFrom(type))
            {
                return typeof(HandleValueEditor);
            }
 
 
            //check if there are custom editors on the variable's type
            Type argumentType = null;
            switch (direction)
            {
                case PropertyKind.InArgument:
                    argumentType = typeof(InArgument<>).MakeGenericType(type);
                    break;
 
                case PropertyKind.InOutArgument:
                    argumentType = typeof(InOutArgument<>).MakeGenericType(type);
                    break;
 
                case PropertyKind.OutArgument:
                    argumentType = typeof(OutArgument<>).MakeGenericType(type);
                    break;
 
                default:
                    argumentType = type;
                    break;
            }
 
            var referenceType = typeof(PropertyValueEditor);
            var expressionEditorType = typeof(ExpressionValueEditor);
 
            //check if there are custom type editors associated with given type - 
            //first look for type editor defined for In/Out/InOut/Argument<T> (if argument is of proper direction)
            //then, look for type editor defined for type itself (i.e. T) - 
            //in search, skip ExpressionValueEditor instance - it will be returned by default for property grid, but for
            //dataGrid nothing should be used - we use default dg template
            var customEditorType = TypeDescriptor
                .GetAttributes(argumentType)
                .OfType<EditorAttribute>()
                .Where(p =>
                    {
                        Type currentType = Type.GetType(p.EditorTypeName);
                        return (expressionEditorType != currentType && referenceType.IsAssignableFrom(currentType));
                    })
                .Select(p => Type.GetType(p.EditorTypeName))
                .FirstOrDefault();
 
            //if yes - check if there is at least one editor assigner and it derives from PropertyValueEditor 
            if (null != customEditorType)
            {
                return customEditorType;
            }
 
            TypeConverter converter = TypeDescriptor.GetConverter(type);
            if (((type != stringTypeReference && (converter == null || !converter.CanConvertFrom(stringTypeReference))) && direction == PropertyKind.Property)
                || direction == PropertyKind.OutArgument || direction == PropertyKind.InOutArgument)
            {
                return typeof(ValueNotSupportedEditor);
            }
 
            //otherwise - return default expression value editor
            return typeof(DefaultValueEditor);
        }
 
        internal bool ValidateArgumentName(object value, List<string> errors)
        {
            VBIdentifierName identifier = value as VBIdentifierName;
            string name = identifier.IdentifierName;
 
            if (string.IsNullOrEmpty(name))
            {
                errors.Add(SR.EmptyArgumentName);
            }
            else
            {
                if (!VBIdentifierName.IsValidXamlName(name))
                {
                    errors.Add(string.Format(CultureInfo.CurrentUICulture, SR.InvalidXamlMemberName, name));
                }
                else
                {
                    ModelItemCollection argumentCollection = (ModelItemCollection)this.ReflectedObject.Parent;
 
                    bool duplicates =
                        argumentCollection.Any<ModelItem>(p => string.Equals(p.Properties["Name"].ComputedValue, name) && !ModelItem.Equals(p, this.ReflectedObject));
 
                    if (duplicates)
                    {
                        errors.Add(string.Format(CultureInfo.CurrentUICulture, SR.DuplicateArgumentName, name));
                    }
                }
            }
            return 0 == errors.Count;
        }
 
        [SuppressMessage(FxCop.Category.Design, FxCop.Rule.DoNotCatchGeneralExceptionTypes,
            Justification = "Exception content is displayed as error message. Propagating exceptions might lead to VS crash.")]
        [SuppressMessage("Reliability", "Reliability108",
            Justification = "Exception content is displayed as error message. Propagating exceptions might lead to VS crash.")]
        bool ValidateArgumentValue(object value, List<string> errors)
        {
            if (PropertyKind.Property == this.GetArgumentDirection())
            {
                //the value is a string and is empty - assume user wants to clear the property value
                if (value is string && string.IsNullOrEmpty((string)value))
                {
                    return true;
                }
                //validate the value for PropertyType - check if converter usage is required - if value type is the same as argument type - skip conversion
                if (null != value && !this.GetArgumentType().IsAssignableFrom(value.GetType()))
                {
                    try
                    {
                        TypeConverter converter = TypeDescriptor.GetConverter(this.GetArgumentType());
                        converter.ConvertFrom(value);
                    }
                    catch (Exception err)
                    {
                        errors.Add(err.Message);
                    }
                }
            }
            return 0 == errors.Count;
        }
 
        string GetArgumentValueExpressionText()
        {
            string currentExpressionText = null;
            object currentValue = this.GetArgumentValue();
            if (null != currentValue)
            {
                if (this.GetArgumentDirection() == PropertyKind.Property)
                {
                    TypeConverter oldConverter = TypeDescriptor.GetConverter(this.GetArgumentType());
 
                    if (oldConverter.CanConvertTo(typeof(string)))
                    {
                        currentExpressionText = (string)oldConverter.ConvertTo(currentValue, typeof(string));
                    }
                }
                else
                {
                    ModelItem expression = null;
                    if (this.ReflectedObject.TryGetPropertyValue(out expression, ArgumentDefaultValueProperty, "Expression") && null != expression)
                    {
                        var activity = expression.GetCurrentValue() as ActivityWithResult;
                        if (null != activity)
                        {
                            currentExpressionText = ExpressionHelper.GetExpressionString(activity);
                        }
                    }
                }
            }
            return currentExpressionText;
        }
 
        [SuppressMessage(FxCop.Category.Design, FxCop.Rule.DoNotCatchGeneralExceptionTypes,
            Justification = "Conversion of value when type changes might fail - argument will get null value by default. Propagating exceptions might lead to VS crash.")]
        [SuppressMessage("Reliability", "Reliability108",
            Justification = "Conversion of value when type changes might fail - argument will get null value by default. Propagating exceptions might lead to VS crash.")]
        void TryUpdateArgumentType(Type newType, PropertyKind newDirection)
        {
            if (newDirection == PropertyKind.Property)
            {
                string currentExpressionText = this.GetArgumentValueExpressionText();
                if (null != currentExpressionText)
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(newType);
                    if (converter.CanConvertFrom(typeof(string)))
                    {
                        try
                        {
                            object value = converter.ConvertFrom(currentExpressionText);
                            this.ReflectedObject.Properties[ArgumentDefaultValueProperty].SetValue(value);
                        }
                        catch (Exception err)
                        {
                            System.Diagnostics.Debug.WriteLine(err.ToString());
                            this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
                        }
                    }
                    else
                    {
                        this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
                    }
                }
                else
                {
                    this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
                }
            }
            else if (newDirection == PropertyKind.InArgument)
            {
                Argument currentArgument = this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ComputedValue as Argument;
                ActivityWithResult newExpression = null;
                bool succeeded = false;
                if (currentArgument != null)
                {
                    succeeded = ExpressionHelper.TryMorphExpression(currentArgument.Expression, false, newType, this.Context, out newExpression);
                }                                 
                else
                {
                    ////If the old direction is property, we'll try to convert the default value object to the expression object specified by global editor setting
                    string currentExpressionText = this.GetArgumentValueExpressionText();
                    if (!string.IsNullOrEmpty(currentExpressionText))
                    {                        
                        string rootEditorSetting = ExpressionHelper.GetRootEditorSetting(this.ModelTreeManager, WorkflowDesigner.GetTargetFramework(this.Context));
                        if (!string.IsNullOrEmpty(rootEditorSetting))
                        {
                            succeeded = ExpressionTextBox.TryConvertFromString(rootEditorSetting, currentExpressionText, false, newType, out newExpression);
                        }
                    }
                }
 
                if (succeeded)
                {
                    Argument newArgument = Argument.Create(newType, ArgumentDirection.In);
                    newArgument.Expression = newExpression;
                    this.ReflectedObject.Properties[ArgumentDefaultValueProperty].SetValue(newArgument);
                }
                else
                {
                    //currently if the value cannot be morphed, it's cleared.
                    this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
                }
            }
            else
            {
                this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ClearValue();
            }
        }
 
        protected override void OnReflectedObjectPropertyChanged(string propertyName)
        {
            if (string.Equals(propertyName, "Type"))
            {
                //type has changed - most likely custom value editors collection would be obsolete                
                this.RaisePropertyChangedEvent(ArgumentTypeProperty);
                this.RaisePropertyChangedEvent(ArgumentDirectionProperty);
                this.RaisePropertyChangedEvent(IsOutputArgument);
                this.RaisePropertyChangedEvent(ArgumentDefaultValueProperty);
            }
            else if (propertyName == ArgumentNameProperty)
            {
                //Change name may need to update the defaul value editor as well, so clean the cache                
                string oldValue = this.identifierName.IdentifierName;
                string newValue = GetArgumentNameString();
 
                //This is invoked in undo stack
                if (oldValue != newValue)
                {
                    this.identifierName = new VBIdentifierName(true)
                    {
                        IdentifierName = newValue
                    };
                    Editor.ValidateArgumentName(this.identifierName, newValue, oldValue);
                }
            }
            else if (propertyName == ArgumentDefaultValueProperty)
            {
                this.argumentExpressionChanged = true;
            }
            else if (propertyName == Annotation.AnnotationTextPropertyName)
            {
                RaisePropertyChangedEvent(AnnotationTextProperty);
            }
        }
 
        protected override void OnPropertyChanged(string propertyName)
        {
            if (string.Equals(propertyName, ArgumentNameProperty))
            {
                this.RaisePropertyChangedEvent(AutomationIdProperty);
            }
            else if (string.Equals(propertyName, TimestampProperty))
            {
                if ((!this.argumentExpressionChanged) && (this.Editor != null))
                {
                    this.CustomValueEditors.Clear();
                    this.Editor.UpdateTypeDesigner(this);
                }
                else
                {
                    this.argumentExpressionChanged = false;
                }
            }
            else if (string.Equals(propertyName, ArgumentDirectionProperty) || (string.Equals(propertyName, ArgumentTypeProperty)))
            {
                this.RaisePropertyChangedEvent(ArgumentDefaultValueProperty);
            }
            base.OnPropertyChanged(propertyName);
        }
 
        internal sealed class DirectionPropertyEditor : PropertyValueEditor
        {
            public DirectionPropertyEditor()
            {
                this.InlineEditorTemplate = EditorResources.GetResources()["DirectionEditor_InlineEditorTemplate"] as DataTemplate;
            }
        }
 
        internal sealed class DefaultValueEditor : ExpressionValueEditor
        {
            public DefaultValueEditor()
            {
                this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument"] as DataTemplate;
            }
        }
 
        internal sealed class IsRequiredPropertyEditor : PropertyValueEditor
        {
            public IsRequiredPropertyEditor()
            {
                this.InlineEditorTemplate = EditorResources.GetResources()["IsRequiredPropertyEditor_InlineEditorTemplate"] as DataTemplate;
            }
        }
 
        internal sealed class ValueNotSupportedEditor : PropertyValueEditor
        {
            public ValueNotSupportedEditor()
            {
                this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument_ValueNotSupported"] as DataTemplate;
            }
        }
 
        internal sealed class InvalidXamlMemberValueEditor : PropertyValueEditor
        {
            public InvalidXamlMemberValueEditor()
            {
                this.InlineEditorTemplate = EditorResources.GetResources()["inlineExpressionEditorTemplateForDesignTimeArgument_InvalidXamlMember"] as DataTemplate;
            }
        }
    }
 
    sealed class PropertyValueTextBox : TextBox
    {
        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
            this.Loaded += (s, args) =>
                {
                    //get the binding expression, and hook up exception filter
                    var expr = this.GetBindingExpression(PropertyValueTextBox.TextProperty);
                    if (null != expr && null != expr.ParentBinding)
                    {
                        expr.ParentBinding.UpdateSourceExceptionFilter = this.OnUpdateBindingException;
                    }
                };
        }
 
        object OnUpdateBindingException(object sender, Exception err)
        {
            //if exception occured, the property value is invalid (conversion to target type failed)
            if (err is TargetInvocationException && err.InnerException is ValidationException || err is ValidationException)
            {
                //show error message
                ErrorReporting.ShowErrorMessage((err.InnerException ?? err).Message);
                //and revert textbox to last valid value
                this.GetBindingExpression(PropertyValueTextBox.TextProperty).UpdateTarget();
            }
            return null;
        }
    }
 
    public enum PropertyKind
    {
        InArgument,
        InOutArgument,
        OutArgument,
        Property
    }
}