ArgumentDesigner.xaml.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / View / ArgumentDesigner.xaml.cs / 1407647 / ArgumentDesigner.xaml.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.Activities.Presentation.View 
{
    using System; 
    using System.Activities.Expressions; 
    using System.Activities.Presentation.Converters;
    using System.Activities.Presentation.Model; 
    using System.Activities.Presentation.PropertyEditing;
    using System.Activities.XamlIntegration;
    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.Input; 
    using System.Xaml; 
    using Microsoft.VisualBasic.Activities;
    using System.Xml; 

    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 argumentWrapperCollection = new ObservableCollection(); 

        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);
        } 

        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().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;
        } 
 
        protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
        { 
            base.OnIsKeyboardFocusWithinChanged(e);
            if ((bool)e.NewValue)
            {
                //Re-select the already selected row to raise DataGridSelectionChanged event, 
                //which will update the Selection context item and will refresh property grid
                object selectedRow = this.argumentsDataGrid.SelectedItem; 
                this.isSelectionChangeInternal = true; 
                this.argumentsDataGrid.SelectedItem = null;
                this.isSelectionChangeInternal = false; 
                this.argumentsDataGrid.SelectedItem = selectedRow;
            }
        }
 
        void OnDataGridArgumentSelected(object sender, RoutedEventArgs e)
        { 
            if (null != this.Context && !this.isSelectionChangeInternal) 
            {
                this.isSelectionChangeInternal = true; 
                DesignTimeArgument argument = this.dgHelper.SelectedItem();
                if (null != argument)
                {
                    this.Context.Items.SetValue(new Selection(argument.Content)); 
                }
                else 
                { 
                    this.Context.Items.SetValue(new Selection());
                } 
                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(new SubscribeContextCallback(OnItemSelected));
            } 
            this.dgHelper.Context = this.Context; 
        }
 
        void OnItemSelected(Selection selection)
        {
            if (!this.isSelectionChangeInternal)
            { 
                this.StoreLastSelection();
            } 
        } 

        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 
            {
                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().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)
        { 
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Remove:
                    foreach (DesignTimeArgument arg in e.OldItems) 
                    {
                        this.ClearCaseInsensitiveDuplicates(arg.GetArgumentName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue); 
                        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 checkForDuplicates = new Func(p => string.Equals((string)p.ReflectedObject.Properties["Name"].ComputedValue, newName, StringComparison.OrdinalIgnoreCase) && !object.Equals(p.GetArgumentName(), identifierName));
            DesignTimeArgument duplicate = this.argumentWrapperCollection.FirstOrDefault(checkForDuplicates); 
            if (duplicate != null)
            {
                identifierName.IsValid = false;
                identifierName.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateVisualBasicIdentifier, newName); 
                VBIdentifierName duplicateIdentifier = duplicate.GetArgumentName();
                if (duplicateIdentifier.IsValid) 
                { 
                    duplicateIdentifier.IsValid = false;
                    duplicateIdentifier.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateVisualBasicIdentifier, 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 checkForOldNameDuplicates = new Func(p => string.Equals((string)p.ReflectedObject.Properties["Name"].ComputedValue, oldName, StringComparison.OrdinalIgnoreCase) && !object.Equals(p.GetArgumentName(), identifier)); 
            IEnumerable oldDuplicates = this.argumentWrapperCollection.Where(checkForOldNameDuplicates);
            if (oldDuplicates.Count() == 1)
            {
                DesignTimeArgument wrapper = oldDuplicates.First(); 
                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);
        }
    }
 
    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"; 

        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().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().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().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().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().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();
                    } 
                }, 
            };
        } 
        #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"; 
        }
 
        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); 
                string currentExpression = this.GetArgumentValueExpressionText();
                this.ReflectedObject.Properties["Type"].SetValue(propertyType); 
                this.TryUpdateArgumentType(currentExpression, 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);
                string currentExpression = this.GetArgumentValueExpressionText(); 
                this.ReflectedObject.Properties["Type"].SetValue(propertyType); 
                this.TryUpdateArgumentType(currentExpression, 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(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 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 (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() 
                .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 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(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 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 IValueSerializableExpression;
                        if (null != activity) 
                        {
                            var serializer = new ActivityWithResultValueSerializer(); 
                            var context = new ParserContext(this.ReflectedObject); 
                            //check if expression can be convertered to string
                            if (serializer.CanConvertToString(activity, context)) 
                            {
                                //serialize expression to a string
                                currentExpressionText = serializer.ConvertToString(activity, context);
                                //if expression is wrapped with [ ], remove them from the string 
                                if (null != currentExpressionText &&
                                    currentExpressionText.StartsWith("[", StringComparison.CurrentCulture) && 
                                    currentExpressionText.EndsWith("]", StringComparison.CurrentCulture)) 
                                {
                                    currentExpressionText = currentExpressionText.Substring(1, currentExpressionText.Length - 2); 
                                }
                                //if source expression is a Literal add missing quotes
                                if (typeof(Literal).IsAssignableFrom(activity.GetType()))
                                { 
                                    currentExpressionText = string.Format(CultureInfo.CurrentUICulture, "\"{0}\"", currentExpressionText);
                                } 
                            } 
                        }
                    } 
                }
            }
            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(string currentExpressionText, Type newType, PropertyKind newDirection)
        {
            if (null != currentExpressionText)
            { 
                if (newDirection == PropertyKind.Property)
                { 
                    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 if (newDirection == PropertyKind.InArgument)
                { 
                    Argument currentArgument = this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ComputedValue as Argument;
                    Activity currentExpression = currentArgument != null ? currentArgument.Expression : null;
                    ActivityWithResult newExpression = ExpressionHelper.CreateExpression(newType, currentExpressionText, false, null);
                    Type targetExpressionType = typeof(VisualBasicValue<>).MakeGenericType(newType); 
                    Argument newArgument = Argument.Create(newType, ArgumentDirection.In);
                    newArgument.Expression = newExpression; 
                    this.ReflectedObject.Properties[ArgumentDefaultValueProperty].SetValue(newArgument); 
                }
                else 
                {
                    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;
            } 
        }
 
        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 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.Activities.Presentation.View 
{
    using System; 
    using System.Activities.Expressions; 
    using System.Activities.Presentation.Converters;
    using System.Activities.Presentation.Model; 
    using System.Activities.Presentation.PropertyEditing;
    using System.Activities.XamlIntegration;
    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.Input; 
    using System.Xaml; 
    using Microsoft.VisualBasic.Activities;
    using System.Xml; 

    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 argumentWrapperCollection = new ObservableCollection(); 

        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);
        } 

        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().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;
        } 
 
        protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
        { 
            base.OnIsKeyboardFocusWithinChanged(e);
            if ((bool)e.NewValue)
            {
                //Re-select the already selected row to raise DataGridSelectionChanged event, 
                //which will update the Selection context item and will refresh property grid
                object selectedRow = this.argumentsDataGrid.SelectedItem; 
                this.isSelectionChangeInternal = true; 
                this.argumentsDataGrid.SelectedItem = null;
                this.isSelectionChangeInternal = false; 
                this.argumentsDataGrid.SelectedItem = selectedRow;
            }
        }
 
        void OnDataGridArgumentSelected(object sender, RoutedEventArgs e)
        { 
            if (null != this.Context && !this.isSelectionChangeInternal) 
            {
                this.isSelectionChangeInternal = true; 
                DesignTimeArgument argument = this.dgHelper.SelectedItem();
                if (null != argument)
                {
                    this.Context.Items.SetValue(new Selection(argument.Content)); 
                }
                else 
                { 
                    this.Context.Items.SetValue(new Selection());
                } 
                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(new SubscribeContextCallback(OnItemSelected));
            } 
            this.dgHelper.Context = this.Context; 
        }
 
        void OnItemSelected(Selection selection)
        {
            if (!this.isSelectionChangeInternal)
            { 
                this.StoreLastSelection();
            } 
        } 

        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 
            {
                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().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)
        { 
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Remove:
                    foreach (DesignTimeArgument arg in e.OldItems) 
                    {
                        this.ClearCaseInsensitiveDuplicates(arg.GetArgumentName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue); 
                        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 checkForDuplicates = new Func(p => string.Equals((string)p.ReflectedObject.Properties["Name"].ComputedValue, newName, StringComparison.OrdinalIgnoreCase) && !object.Equals(p.GetArgumentName(), identifierName));
            DesignTimeArgument duplicate = this.argumentWrapperCollection.FirstOrDefault(checkForDuplicates); 
            if (duplicate != null)
            {
                identifierName.IsValid = false;
                identifierName.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateVisualBasicIdentifier, newName); 
                VBIdentifierName duplicateIdentifier = duplicate.GetArgumentName();
                if (duplicateIdentifier.IsValid) 
                { 
                    duplicateIdentifier.IsValid = false;
                    duplicateIdentifier.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateVisualBasicIdentifier, 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 checkForOldNameDuplicates = new Func(p => string.Equals((string)p.ReflectedObject.Properties["Name"].ComputedValue, oldName, StringComparison.OrdinalIgnoreCase) && !object.Equals(p.GetArgumentName(), identifier)); 
            IEnumerable oldDuplicates = this.argumentWrapperCollection.Where(checkForOldNameDuplicates);
            if (oldDuplicates.Count() == 1)
            {
                DesignTimeArgument wrapper = oldDuplicates.First(); 
                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);
        }
    }
 
    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"; 

        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().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().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().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().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().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();
                    } 
                }, 
            };
        } 
        #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"; 
        }
 
        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); 
                string currentExpression = this.GetArgumentValueExpressionText();
                this.ReflectedObject.Properties["Type"].SetValue(propertyType); 
                this.TryUpdateArgumentType(currentExpression, 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);
                string currentExpression = this.GetArgumentValueExpressionText(); 
                this.ReflectedObject.Properties["Type"].SetValue(propertyType); 
                this.TryUpdateArgumentType(currentExpression, 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(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 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 (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() 
                .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 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(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 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 IValueSerializableExpression;
                        if (null != activity) 
                        {
                            var serializer = new ActivityWithResultValueSerializer(); 
                            var context = new ParserContext(this.ReflectedObject); 
                            //check if expression can be convertered to string
                            if (serializer.CanConvertToString(activity, context)) 
                            {
                                //serialize expression to a string
                                currentExpressionText = serializer.ConvertToString(activity, context);
                                //if expression is wrapped with [ ], remove them from the string 
                                if (null != currentExpressionText &&
                                    currentExpressionText.StartsWith("[", StringComparison.CurrentCulture) && 
                                    currentExpressionText.EndsWith("]", StringComparison.CurrentCulture)) 
                                {
                                    currentExpressionText = currentExpressionText.Substring(1, currentExpressionText.Length - 2); 
                                }
                                //if source expression is a Literal add missing quotes
                                if (typeof(Literal).IsAssignableFrom(activity.GetType()))
                                { 
                                    currentExpressionText = string.Format(CultureInfo.CurrentUICulture, "\"{0}\"", currentExpressionText);
                                } 
                            } 
                        }
                    } 
                }
            }
            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(string currentExpressionText, Type newType, PropertyKind newDirection)
        {
            if (null != currentExpressionText)
            { 
                if (newDirection == PropertyKind.Property)
                { 
                    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 if (newDirection == PropertyKind.InArgument)
                { 
                    Argument currentArgument = this.ReflectedObject.Properties[ArgumentDefaultValueProperty].ComputedValue as Argument;
                    Activity currentExpression = currentArgument != null ? currentArgument.Expression : null;
                    ActivityWithResult newExpression = ExpressionHelper.CreateExpression(newType, currentExpressionText, false, null);
                    Type targetExpressionType = typeof(VisualBasicValue<>).MakeGenericType(newType); 
                    Argument newArgument = Argument.Create(newType, ArgumentDirection.In);
                    newArgument.Expression = newExpression; 
                    this.ReflectedObject.Properties[ArgumentDefaultValueProperty].SetValue(newArgument); 
                }
                else 
                {
                    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;
            } 
        }
 
        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 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK