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
- DocumentCollection.cs
- PeerNearMe.cs
- TreeViewCancelEvent.cs
- filewebresponse.cs
- RegionData.cs
- ReceiveActivityDesigner.cs
- StreamGeometryContext.cs
- DataListCommandEventArgs.cs
- _NetRes.cs
- Page.cs
- UnsafeNativeMethods.cs
- VerificationAttribute.cs
- OrderByQueryOptionExpression.cs
- InkCanvas.cs
- PackageProperties.cs
- Policy.cs
- DefaultSettingsSection.cs
- EnumValAlphaComparer.cs
- WmlFormAdapter.cs
- Permission.cs
- EdmValidator.cs
- ObjectListCommand.cs
- InitializerFacet.cs
- PropertyChangedEventManager.cs
- DataGridViewTextBoxColumn.cs
- BaseComponentEditor.cs
- EventBookmark.cs
- XPathNodePointer.cs
- TreeNodeClickEventArgs.cs
- util.cs
- GridView.cs
- ProtectedProviderSettings.cs
- WebBodyFormatMessageProperty.cs
- ReferentialConstraint.cs
- DataGridViewAccessibleObject.cs
- DataGridTableCollection.cs
- DriveNotFoundException.cs
- InvalidDataException.cs
- PasswordTextContainer.cs
- EventBuilder.cs
- CompositeControl.cs
- DetailsViewCommandEventArgs.cs
- TraceContextRecord.cs
- Queue.cs
- CompilationUnit.cs
- WebBaseEventKeyComparer.cs
- Size.cs
- DataStreamFromComStream.cs
- SecurityPermission.cs
- ClientApiGenerator.cs
- ResXResourceReader.cs
- OperationParameterInfoCollection.cs
- SafeViewOfFileHandle.cs
- PanelDesigner.cs
- ListViewDeletedEventArgs.cs
- ContentAlignmentEditor.cs
- CallContext.cs
- DependencyObjectPropertyDescriptor.cs
- fixedPageContentExtractor.cs
- MachineKeySection.cs
- EncryptedReference.cs
- Internal.cs
- QilXmlReader.cs
- HttpListenerRequest.cs
- HttpStreamMessage.cs
- safelink.cs
- PostBackOptions.cs
- EtwProvider.cs
- ParagraphResult.cs
- SystemIPGlobalStatistics.cs
- Animatable.cs
- CodePageUtils.cs
- DataKeyCollection.cs
- TypefaceMetricsCache.cs
- UserControl.cs
- MatrixAnimationUsingPath.cs
- ExpressionNode.cs
- CollectionBase.cs
- Mapping.cs
- QilTernary.cs
- SoapIgnoreAttribute.cs
- SiteMapSection.cs
- RSAPKCS1KeyExchangeFormatter.cs
- SendOperation.cs
- webbrowsersite.cs
- Utils.cs
- ACE.cs
- SqlBulkCopyColumnMappingCollection.cs
- Point4DConverter.cs
- StreamWithDictionary.cs
- ListParagraph.cs
- MessagePropertyFilter.cs
- ApplicationSecurityManager.cs
- WorkflowWebService.cs
- ISAPIRuntime.cs
- X509Certificate.cs
- GridViewColumnCollection.cs
- Win32PrintDialog.cs
- CodeTypeDelegate.cs
- HttpCacheVary.cs