Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / ArgumentFixer.cs / 1305376 / ArgumentFixer.cs
//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------- namespace System.Activities.Presentation { using System.Activities.Expressions; using System.ServiceModel.Activities; using System.Activities.Statements; using Microsoft.VisualBasic.Activities; using System.Collections.Generic; using System.Activities.Presentation.Model; using System.Activities.Presentation.Validation; using System.Linq; using System.Activities.ExpressionParser; using System.Activities.Validation; using System.Reflection; using System.ComponentModel; using System.Runtime; using System.Activities.Presentation.View; using System.Linq.Expressions; //base of helper class to fix one argument for one activity abstract class ActivityArgumentFixer { public abstract Type ActivityType { get; } public abstract bool NeedsToFix(Activity activity, ActivityWithResult expression, bool isLocation); public abstract void Fix(Activity activity, Argument newArgument); } class ActivityArgumentFixer: ActivityArgumentFixer where TActivity : Activity { Func argumentGetter; Action argumentSetter; public ActivityArgumentFixer(Func argumentGetter, Action argumentSetter) { this.argumentGetter = argumentGetter; this.argumentSetter = argumentSetter; } public override bool NeedsToFix(Activity activity, ActivityWithResult expression, bool isLocation) { TActivity concreteActivity = activity as TActivity; if (concreteActivity == null) { return false; } Argument argument = this.argumentGetter(concreteActivity, isLocation); return argument != null && argument.Expression == expression; } public override void Fix(Activity activity, Argument newArgument) { TActivity concreteActivity = activity as TActivity; if (concreteActivity == null) { return; } this.argumentSetter(concreteActivity, newArgument); } public override Type ActivityType { get { return typeof(TActivity); } } } //utility class to fix up invalid arguments for activities after validation static class ArgumentFixer { static Dictionary argumentFixers = new Dictionary (); public static void RegisterArgumentFixer (ActivityArgumentFixer fixer) { ArgumentFixer.argumentFixers[fixer.ActivityType] = fixer; } // // In some of our activities, such as non generic Assign, exposes arguments with no type constraints. // // In that case, the designer has to infer the type based on user entered expressions. // But those expression's inferred type changes when its context changes. // Such context includes (e.g. Namespaces, Variable definition, References ...) // // To maintain data laziness of our designers (so as to minimize user perceived latency), we postpone to // work of type re-inferencing until validation pass where we will need to walk the tree. // // This method is used to update the argument objects (and the underlying expression objects as well) // due to new type inferencing requirements. // // This is NOT the long term solution. Doing type inference right is not a realistic goal for Dev10 at // this stage now. This should be consider a patch so as to make a reasonable experience for Assign. // public static void UpdateInvalidArgumentsIfNecessary(object sender, ValidationService.ErrorsMarkedEventArgs args) { if (args.Reason != ValidationReason.ModelChange) { return; } // Re-compile erroreous expressions to see if update is necessary Dictionary lvalueReplacements = ComputeLocationExpressionReplacements( from error in args.Errors where IsVisualBasicReferenceForUntypedArgument(error.Source) select error, args.Context); Dictionary rvalueReplacements = ComputeValueExpressionReplacements( from error in args.Errors where IsVisualBasicValueForUntypedArgument(error.Source) select error, args.Context); using (EditingScope editingScope = args.ModelTreeManager.CreateEditingScope(string.Empty)) { editingScope.SuppressUndo = true; //Assign has special requirement that Value has to have the same type as To, so we need to track all Assign activities whose To have been changed Dictionary modifiedAssigns = new Dictionary (); foreach (ActivityWithResult expressionToFix in lvalueReplacements.Keys) { Type expectedType = lvalueReplacements[expressionToFix]; string expressionText = ExpressionHelper.GetExpressionString(expressionToFix); if (expressionToFix.ResultType.GetGenericArguments()[0] != expectedType) { args.Handled = true; Argument newArgument = ConstructNewArgument(true, expectedType, expressionText); ReplaceArgument(expressionToFix, newArgument, args.ModelTreeManager); } Assign modifiedAssign = ValidationService.GetParent(expressionToFix) as Assign; if (modifiedAssign != null) { modifiedAssigns.Add(modifiedAssign, expectedType); } } foreach (ActivityWithResult expressionToFix in rvalueReplacements.Keys) { Type expectedType = rvalueReplacements[expressionToFix]; string expressionText = ExpressionHelper.GetExpressionString(expressionToFix); // Here is where more type inferencing is happening. // Depending on context, r-value might not take the type inferred from the compiler. // // A classic example will be Assign string value to Nothing. By default, VB compiler // output object as the expected type which is not really what I want. // Assign assignToFix = ValidationService.GetParent(expressionToFix) as Assign; if (assignToFix != null) { if (modifiedAssigns.ContainsKey(assignToFix)) { expectedType = modifiedAssigns[assignToFix]; modifiedAssigns.Remove(assignToFix); } else if (assignToFix.To != null) { expectedType = assignToFix.To.ArgumentType; } } if (expressionToFix.ResultType != expectedType) { args.Handled = true; Argument newArgument = ConstructNewArgument(false, expectedType, expressionText); ReplaceArgument(expressionToFix, newArgument, args.ModelTreeManager); } } foreach (Assign otherAssign in modifiedAssigns.Keys) { if (otherAssign.Value != null) { ActivityWithResult offendingExpression = otherAssign.Value.Expression; Type expectedType = modifiedAssigns[otherAssign]; if (offendingExpression.ResultType != expectedType) { string expressionText = ExpressionHelper.GetExpressionString(offendingExpression); if (expressionText != null) { args.Handled = true; Argument newArgument = ConstructNewArgument(false, expectedType, expressionText); ReplaceArgument(offendingExpression, newArgument, args.ModelTreeManager); } // Since r-value of Assign could potentially be any other expression activities, but type inferencing will stop here. // There is no way to update expression activities now. } } } // The completion of this specific editing scope will NOT result in an UndoUnit. // This is done so to avoid infinite loop of validation -> fixup -> validation -> ... // This is also done to avoid undo -> fixup -> undo -> ... // See UndoEngine for details on how I skipped that. editingScope.Complete(); } } static Dictionary ComputeLocationExpressionReplacements(IEnumerable lvalueErrors, EditingContext context) { Dictionary lvalueReplacements = new Dictionary (); foreach (ValidationError lvalueError in lvalueErrors) { ActivityWithResult offendingExpression = (ActivityWithResult)lvalueError.Source; Type returnType; SourceExpressionException compileError; VisualBasicSettings settings; VisualBasicDesignerHelper.RecompileVisualBasicReference( offendingExpression, out returnType, out compileError, out settings); if (compileError == null) { lvalueReplacements.Add(offendingExpression, returnType); if (settings != null) { //merge with import designer foreach (VisualBasicImportReference reference in settings.ImportReferences) { ImportDesigner.AddImport(reference.Import, context); } } } } return lvalueReplacements; } static Dictionary ComputeValueExpressionReplacements(IEnumerable rvalueErrors, EditingContext context) { Dictionary rvalueReplacements = new Dictionary (); foreach (ValidationError rvalueError in rvalueErrors) { ActivityWithResult offendingExpression = (ActivityWithResult)rvalueError.Source; Type returnType; SourceExpressionException compileError; VisualBasicSettings settings; VisualBasicDesignerHelper.RecompileVisualBasicValue( offendingExpression, out returnType, out compileError, out settings); if (compileError == null) { rvalueReplacements.Add(offendingExpression, returnType); if (settings != null) { //merge with import designer foreach (VisualBasicImportReference reference in settings.ImportReferences) { ImportDesigner.AddImport(reference.Import, context); } } } } return rvalueReplacements; } static void ReplaceArgument(ActivityWithResult expressionToReplace, Argument newArgument, ModelTreeManager modelTreeManager) { ModelItem expressionModelItem = modelTreeManager.GetModelItem(expressionToReplace); if (expressionModelItem != null) { ModelItem argumentModelItem = expressionModelItem.Parent; ModelItem parentObject = argumentModelItem.Parent; if (argumentModelItem.Source != null) { ModelProperty argumentProperty = parentObject.Properties[argumentModelItem.Source.Name]; Type argumentPropertyType = argumentProperty.PropertyType; if (argumentPropertyType == typeof(InArgument) || argumentPropertyType == typeof(OutArgument)) { ModelItem newArgumentModel = parentObject.Properties[argumentModelItem.Source.Name].SetValue(newArgument); //make sure argument.Expression is wrapped in ModelItem as well ModelItem newExpressionModel = newArgumentModel.Properties["Expression"].Value; } } } else { Activity parentActivity = ValidationService.GetParent(expressionToReplace); ActivityArgumentFixer fixer; if (ArgumentFixer.argumentFixers.TryGetValue(parentActivity.GetType(), out fixer)) { fixer.Fix(parentActivity, newArgument); } } } static Argument ConstructNewArgument(bool isLocationExpression, Type expectedType, string expressionText) { Argument newArgument = null; if (isLocationExpression) { newArgument = (Argument)Activator.CreateInstance(typeof(OutArgument<>).MakeGenericType(expectedType)); } else { newArgument = (Argument)Activator.CreateInstance(typeof(InArgument<>).MakeGenericType(expectedType)); } ActivityWithResult newExpression = ExpressionHelper.CreateExpression(expectedType, expressionText, isLocationExpression, null); newArgument.Expression = newExpression; return newArgument; } static bool IsGenericType(Type query, Type genericTypeDefintion) { return query.IsGenericType && query.GetGenericTypeDefinition() == genericTypeDefintion; } static bool IsVisualBasicReferenceForUntypedArgument(Activity expression) { if (!IsGenericType(expression.GetType(), typeof(VisualBasicReference<>))) { return false; } //only VB expressions for untyped arguments need to be fixed up, //however there is no way to tell which argument on expression belongs to so we only handle few activities //which are known to have untyped arguments now. Activity parentActivity = ValidationService.GetParent(expression); ActivityArgumentFixer fixer; if (!ArgumentFixer.argumentFixers.TryGetValue(parentActivity.GetType(), out fixer)) { return false; } return fixer.NeedsToFix(parentActivity, expression as ActivityWithResult, true); } static bool IsVisualBasicValueForUntypedArgument(Activity expression) { if (!IsGenericType(expression.GetType(), typeof(VisualBasicValue<>))) { return false; } //only VB expressions for untyped arguments need to be fixed up, //however there is no way to tell which argument on expression belongs to so we only handle few activities //which are known to have untyped arguments now. Activity parentActivity = ValidationService.GetParent(expression); ActivityArgumentFixer fixer; if (!ArgumentFixer.argumentFixers.TryGetValue(parentActivity.GetType(), out fixer)) { return false; } return fixer.NeedsToFix(parentActivity, expression as ActivityWithResult, false); } } } // 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
- SingleResultAttribute.cs
- DynamicRendererThreadManager.cs
- MinimizableAttributeTypeConverter.cs
- DataSourceCache.cs
- RangeValidator.cs
- InputBinding.cs
- ProgramNode.cs
- AssociationSet.cs
- TemplateBindingExpression.cs
- PageFunction.cs
- Visitors.cs
- Baml2006KeyRecord.cs
- UnsafeNativeMethods.cs
- PublisherIdentityPermission.cs
- ReturnType.cs
- TypeConverterHelper.cs
- DefaultValueMapping.cs
- ItemContainerGenerator.cs
- GeneralTransform.cs
- ObjectConverter.cs
- GuidConverter.cs
- GeneralTransform.cs
- LayoutUtils.cs
- CalendarData.cs
- COM2EnumConverter.cs
- ContentPosition.cs
- HeaderUtility.cs
- CustomAttributeFormatException.cs
- ToolStripManager.cs
- MemberInfoSerializationHolder.cs
- CompositionAdorner.cs
- PassportAuthenticationModule.cs
- CompilerTypeWithParams.cs
- COM2PictureConverter.cs
- DataBindingHandlerAttribute.cs
- _NativeSSPI.cs
- TypedReference.cs
- NumberFunctions.cs
- LocalizableAttribute.cs
- ExpressionPrefixAttribute.cs
- UITypeEditor.cs
- SessionState.cs
- SerializerWriterEventHandlers.cs
- OdbcConnectionPoolProviderInfo.cs
- DetailsViewCommandEventArgs.cs
- Select.cs
- ConfigsHelper.cs
- ColumnCollection.cs
- login.cs
- NullEntityWrapper.cs
- ListControlConvertEventArgs.cs
- ServicesUtilities.cs
- DomainUpDown.cs
- DynamicResourceExtension.cs
- CustomAttributeFormatException.cs
- DbSetClause.cs
- VisualSerializer.cs
- CfgParser.cs
- PageThemeCodeDomTreeGenerator.cs
- StylusCollection.cs
- DateTimeFormatInfoScanner.cs
- TextSelectionHelper.cs
- SystemResources.cs
- ConstructorBuilder.cs
- CheckedListBox.cs
- InheritanceContextHelper.cs
- AutomationPatternInfo.cs
- Stylus.cs
- Compensate.cs
- AssemblyFilter.cs
- COAUTHINFO.cs
- UnsignedPublishLicense.cs
- IPGlobalProperties.cs
- FixedNode.cs
- NegationPusher.cs
- ItemsChangedEventArgs.cs
- BindingEntityInfo.cs
- GregorianCalendar.cs
- ChtmlTextWriter.cs
- COAUTHIDENTITY.cs
- WebPartPersonalization.cs
- WebPartMinimizeVerb.cs
- BaseDataBoundControl.cs
- AppearanceEditorPart.cs
- RegexFCD.cs
- PeerApplicationLaunchInfo.cs
- FormatterConverter.cs
- HostingPreferredMapPath.cs
- OperationValidationEventArgs.cs
- ContextTokenTypeConverter.cs
- KnownBoxes.cs
- HttpWriter.cs
- ConfigurationStrings.cs
- WindowsFormsSectionHandler.cs
- StringValueSerializer.cs
- FillErrorEventArgs.cs
- XmlIncludeAttribute.cs
- ElementHost.cs
- EnglishPluralizationService.cs
- TreeNodeMouseHoverEvent.cs