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
- MiniModule.cs
- ValidatorCollection.cs
- RowCache.cs
- Renderer.cs
- ContextMenuStrip.cs
- IPPacketInformation.cs
- ItemChangedEventArgs.cs
- TabItemAutomationPeer.cs
- GridPatternIdentifiers.cs
- TableLayoutStyleCollection.cs
- XmlnsCache.cs
- CommandField.cs
- CodeRegionDirective.cs
- BeginEvent.cs
- cookiecollection.cs
- EntityTypeEmitter.cs
- RadioButtonBaseAdapter.cs
- XmlCodeExporter.cs
- TextParaLineResult.cs
- HttpModule.cs
- XPathDocumentIterator.cs
- HealthMonitoringSectionHelper.cs
- ContextProperty.cs
- RelationshipSet.cs
- TextBoxAutomationPeer.cs
- Vars.cs
- XpsSerializationManagerAsync.cs
- RegexNode.cs
- ArgumentNullException.cs
- ExceptionUtil.cs
- ThemeInfoAttribute.cs
- BitSet.cs
- FixedTextContainer.cs
- ProgressBarAutomationPeer.cs
- FullTextBreakpoint.cs
- ScriptMethodAttribute.cs
- TransactionFlowOption.cs
- InitializerFacet.cs
- ImplicitInputBrush.cs
- BindToObject.cs
- RouteValueDictionary.cs
- _FtpDataStream.cs
- HelloOperationCD1AsyncResult.cs
- XPathBuilder.cs
- Geometry3D.cs
- SafeProcessHandle.cs
- HttpBufferlessInputStream.cs
- LogLogRecordEnumerator.cs
- DesignTimeHTMLTextWriter.cs
- AttributeQuery.cs
- TraceLog.cs
- UmAlQuraCalendar.cs
- XmlNodeChangedEventArgs.cs
- WebEvents.cs
- SqlBulkCopy.cs
- WebBrowserBase.cs
- EdmValidator.cs
- WebPartVerbsEventArgs.cs
- ObjectAnimationUsingKeyFrames.cs
- WindowHideOrCloseTracker.cs
- ClientSettingsSection.cs
- SafeEventLogReadHandle.cs
- ToolStripItemClickedEventArgs.cs
- CustomCategoryAttribute.cs
- MediaElement.cs
- XamlStackWriter.cs
- DbSetClause.cs
- ResolveCriteria11.cs
- ComboBoxAutomationPeer.cs
- ThicknessKeyFrameCollection.cs
- UndoManager.cs
- ConstNode.cs
- ScriptingSectionGroup.cs
- DesignerLoader.cs
- IntegerValidatorAttribute.cs
- TdsParserSessionPool.cs
- ListManagerBindingsCollection.cs
- HttpApplication.cs
- ADConnectionHelper.cs
- EmptyImpersonationContext.cs
- Vector3D.cs
- WithStatement.cs
- ChannelTracker.cs
- CapabilitiesUse.cs
- DoubleStorage.cs
- ErrorTableItemStyle.cs
- FieldToken.cs
- FixedFindEngine.cs
- SqlCachedBuffer.cs
- PlainXmlWriter.cs
- NavigationPropertyEmitter.cs
- RepeaterItemEventArgs.cs
- PopOutPanel.cs
- UnsafeNetInfoNativeMethods.cs
- DataGridTablesFactory.cs
- TagPrefixAttribute.cs
- DataServiceQueryContinuation.cs
- XmlResolver.cs
- AssemblyNameProxy.cs
- OracleParameterCollection.cs