Code:
/ 4.0 / 4.0 / untmp / 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"; ObservableCollectionargumentWrapperCollection = 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- COM2IDispatchConverter.cs
- StreamAsIStream.cs
- Panel.cs
- PackWebRequest.cs
- KeysConverter.cs
- Image.cs
- TreeNodeStyle.cs
- SqlCacheDependencyDatabaseCollection.cs
- ListMarkerLine.cs
- HttpHostedTransportConfiguration.cs
- ListBindableAttribute.cs
- KeyInfo.cs
- InternalBufferOverflowException.cs
- TypeBuilderInstantiation.cs
- GeometryModel3D.cs
- SerializationEventsCache.cs
- ISAPIWorkerRequest.cs
- FixedTextContainer.cs
- OptimalTextSource.cs
- CalendarDateRangeChangingEventArgs.cs
- BuildProviderAppliesToAttribute.cs
- PointValueSerializer.cs
- ZipIOLocalFileDataDescriptor.cs
- TypeResolver.cs
- ExtendedPropertyInfo.cs
- ContentPathSegment.cs
- SafeFindHandle.cs
- ToolStripDropDownItem.cs
- FloatMinMaxAggregationOperator.cs
- XmlReflectionMember.cs
- XmlFormatExtensionPointAttribute.cs
- EntityClientCacheEntry.cs
- XmlTextReader.cs
- SyntaxCheck.cs
- XmlWrappingReader.cs
- ResourceContainer.cs
- ToggleButton.cs
- ObjectDataSourceMethodEventArgs.cs
- LinqDataSourceContextEventArgs.cs
- UIElementCollection.cs
- RecommendedAsConfigurableAttribute.cs
- ToolStripItemImageRenderEventArgs.cs
- CodeDelegateInvokeExpression.cs
- EasingFunctionBase.cs
- HttpModuleActionCollection.cs
- CachedTypeface.cs
- ConfigurationManagerInternalFactory.cs
- DataGridBoundColumn.cs
- DesignerSerializationOptionsAttribute.cs
- InertiaExpansionBehavior.cs
- StringWriter.cs
- CompressedStack.cs
- VisualTarget.cs
- TransformPatternIdentifiers.cs
- RegistryKey.cs
- RouteTable.cs
- DbConnectionPoolOptions.cs
- ServiceEndpointElement.cs
- PerformanceCounter.cs
- PenContexts.cs
- WindowInteractionStateTracker.cs
- DateTimeFormat.cs
- Effect.cs
- ErrorWrapper.cs
- DetailsViewPagerRow.cs
- ClassHandlersStore.cs
- CompoundFileStorageReference.cs
- AnimationStorage.cs
- ResourceReferenceExpressionConverter.cs
- WebPartActionVerb.cs
- SQLSingle.cs
- TemplateInstanceAttribute.cs
- FieldBuilder.cs
- Int16KeyFrameCollection.cs
- CreateUserWizardDesigner.cs
- ImageFormatConverter.cs
- PropertyDescriptorCollection.cs
- DataGridViewCellCollection.cs
- ChannelManager.cs
- RequestQueryParser.cs
- TransactedReceiveScope.cs
- KeyGesture.cs
- ListBox.cs
- XmlSchemaComplexType.cs
- AssociatedControlConverter.cs
- WorkflowPersistenceService.cs
- NetNamedPipeSecurityMode.cs
- ExceptionUtility.cs
- TextElementEnumerator.cs
- CommandField.cs
- NameNode.cs
- InputBindingCollection.cs
- SystemColorTracker.cs
- ArcSegment.cs
- HttpCookieCollection.cs
- BCLDebug.cs
- InputProviderSite.cs
- BasicHttpMessageCredentialType.cs
- _SslStream.cs
- PageCatalogPart.cs