Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / Validation / ValidationService.cs / 1591162 / ValidationService.cs
//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------- namespace System.Activities.Presentation.Validation { using System.Activities.Presentation.Model; using System.Activities.Presentation.Services; using System.Activities.Presentation.Xaml; using System.Activities.Statements; using System.Activities.Validation; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime; using System.Text; using System.Windows.Threading; using Microsoft.VisualBasic.Activities; using Microsoft.Win32; using System.Activities.ExpressionParser; using System.Activities.Presentation.View; using System.Activities.Expressions; using System.ComponentModel; using System.Activities.XamlIntegration; public enum ValidationState { // The numeric values of each of the enum values indicate the severity of the error. // The higher the number is, the more severe the error. See the MarkError method in the // ValidationService class for example of usage. Error = 3, Warning = 2, ChildInvalid = 1, Valid = 0 } internal enum ValidationReason { Unknown, Load, Save, ModelChange, } [Fx.Tag.XamlVisible(false)] public class ValidationService { static PropertyInfo parentPropertyInfo; EditingContext context; ModelService modelService; ModelTreeManager modelTreeManager; WorkflowViewService viewService; IValidationErrorService errorService; // Dictionary which maps the activities to their error messages and indicators // NOTE: Valid Workflow Elements/Model Items do not appear in this dictionary, // only elements which violated a constraint (Errors or Warnings or Child Validation Issues) DictionaryvalidationErrors; // Attached properties for error visuals AttachedProperty validationStateProperty; AttachedProperty validationMessageProperty; internal event EventHandler ValidationCompleted; internal class ErrorsMarkedEventArgs : EventArgs { ICollection errors; ValidationReason reason; ModelTreeManager modelTreeManager; EditingContext context; public ErrorsMarkedEventArgs(ICollection errors, ValidationReason reason, ModelTreeManager modelTreeManager, EditingContext context) { this.errors = errors; this.reason = reason; this.modelTreeManager = modelTreeManager; this.context = context; } public ICollection Errors { get { return this.errors; } } public ValidationReason Reason { get { return this.reason; } } public ModelTreeManager ModelTreeManager { get { return this.modelTreeManager; } } public bool Handled { get; set; } public EditingContext Context { get { return this.context; } } } internal event EventHandler ErrorsMarked; Sequence bodyPlaceholder; ValidationSettings settings; bool isValidationDisabled = false; const string ValidationRegKeyName = "DisableValidateOnModelItemChanged"; const string ValidationRegKeyInitialPath = "Software\\Microsoft\\.NETFramework\\"; [ThreadStatic] static StringBuilder errorBuilder; private static StringBuilder ErrorBuilder { get { if (errorBuilder == null) { errorBuilder = new StringBuilder(); } return errorBuilder; } } public ValidationService(EditingContext context) { this.context = context; this.settings = new ValidationSettings(); this.context.Services.Subscribe (new SubscribeServiceCallback (OnModelServiceAvailable)); this.context.Services.Subscribe (new SubscribeServiceCallback (OnModelTreeManagerAvailable)); this.context.Services.Subscribe (new SubscribeServiceCallback (OnErrorServiceAvailable)); this.context.Services.Subscribe (new SubscribeServiceCallback (OnAttachedPropertiesServiceAvailable)); AssemblyName currentAssemblyName = Assembly.GetExecutingAssembly().GetName(); StringBuilder validationKeyPath = new StringBuilder(90); validationKeyPath.Append(ValidationRegKeyInitialPath); validationKeyPath.AppendFormat("{0}{1}{2}", "v", currentAssemblyName.Version.ToString(), "\\"); validationKeyPath.Append(currentAssemblyName.Name); RegistryKey validationRegistryKey = Registry.CurrentUser.OpenSubKey(validationKeyPath.ToString()); if (validationRegistryKey != null) { object value = validationRegistryKey.GetValue(ValidationRegKeyName); this.isValidationDisabled = (value != null && string.Equals("1", value.ToString())); validationRegistryKey.Close(); } } Sequence BodyPlaceholder { get { if (null == this.bodyPlaceholder) { this.bodyPlaceholder = new Sequence(); } return this.bodyPlaceholder; } } public ValidationSettings Settings { get { return this.settings; } } WorkflowViewService ViewService { get { if (null == this.viewService) { this.viewService = (WorkflowViewService)this.context.Services.GetService (); } return this.viewService; } } void OnAttachedPropertiesServiceAvailable(AttachedPropertiesService attachedPropertiesService) { this.validationStateProperty = new AttachedProperty () { Getter = (modelItem) => GetValidationState(modelItem), Name = "ValidationState", OwnerType = typeof(Activity) }; attachedPropertiesService.AddProperty(this.validationStateProperty); this.validationMessageProperty = new AttachedProperty () { Getter = (modelItem) => GetValidationMessage(modelItem), Name = "ValidationMessage", OwnerType = typeof(Activity) }; attachedPropertiesService.AddProperty(this.validationMessageProperty); } ValidationState GetValidationState(ModelItem modelItem) { ValidationState validationState = ValidationState.Valid; ValidationErrorState validationError = GetValidationError(modelItem); if (validationError != null) { validationState = validationError.ValidationState; } return validationState; } string GetValidationMessage(ModelItem modelItem) { string errorMessage = string.Empty; ValidationErrorState validationError = GetValidationError(modelItem); if (validationError != null) { if (validationError.ErrorMessages != null) { ValidationService.ErrorBuilder.Clear(); foreach (string message in validationError.ErrorMessages) { ValidationService.ErrorBuilder.AppendLine(message); } ValidationService.ErrorBuilder.Remove(errorBuilder.Length - 1, 1); errorMessage = ValidationService.ErrorBuilder.ToString(); } } return errorMessage; } ValidationErrorState GetValidationError(ModelItem modelItem) { ValidationErrorState validationError = null; Activity workflowElement = modelItem.GetCurrentValue() as Activity; if (workflowElement != null) { this.ValidationErrors.TryGetValue(workflowElement, out validationError); } return validationError; } void AddValidationError(ModelItem modelItem, ValidationErrorState error) { Activity workflowElement = modelItem.GetCurrentValue() as Activity; Fx.Assert(workflowElement != null, "modelItem current value can't be null"); this.ValidationErrors.Add(workflowElement, error); } void OnModelServiceAvailable(ModelService modelService) { if (modelService != null) { this.modelService = modelService; } } void OnModelTreeManagerAvailable(ModelTreeManager modelTreeManager) { if (modelTreeManager != null) { this.modelTreeManager = modelTreeManager; } } void OnErrorServiceAvailable(IValidationErrorService errorService) { if (errorService != null) { this.errorService = errorService; if (this.isValidationDisabled) { this.errorService.ShowValidationErrors(new List { new ValidationErrorInfo(new ValidationError(SR.ValidationDisabledWarning, true)) }); } } } private void NotifyValidationPropertiesChanged(ModelItem modelItem) { // Notify an update to the attached properties this.validationStateProperty.NotifyPropertyChanged(modelItem); this.validationMessageProperty.NotifyPropertyChanged(modelItem); } public void ValidateWorkflow() { ValidateWorkflow(ValidationReason.Unknown); } internal void ValidateWorkflow(ValidationReason reason) { if (!isValidationDisabled) { ValidateActivity(GetRootElement(), reason); } } Activity GetRootElement() { Activity rootElement = null; Fx.Assert(this.modelService != null, "ModelService is null."); // ModelService should not be null ModelItem rootItem = this.modelService.Root; object root = rootItem.GetCurrentValue(); //special case handling for ActivityBuilder - its arguments must be converted to variables before validation. //otherwise, there will be validation error for each argument referenced if (root is ActivityBuilder) { var activityBuilder = (ActivityBuilder)root; this.BodyPlaceholder.Activities.Clear(); this.BodyPlaceholder.Variables.Clear(); if (activityBuilder.Implementation != null) { this.BodyPlaceholder.Activities.Add(activityBuilder.Implementation); VisualBasic.SetSettings(this.BodyPlaceholder, VisualBasic.GetSettings(root)); } ActivityBuilderHelper.GetVariables(activityBuilder).ForEach(variable => this.BodyPlaceholder.Variables.Add(variable)); rootElement = this.BodyPlaceholder; } else { rootElement = rootItem.GetRootActivity(); } return rootElement; } // Validate the imported WF element (and thus all its children) void ValidateActivity(Activity workflowElement, ValidationReason reason) { if (workflowElement != null) { Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action( () => { DesignerPerfEventProvider perfProvider = this.context.Services.GetService (); perfProvider.WorkflowDesignerValidationStart(); ValidationResults results = null; ValidationErrorInfo validationErrorInfo = null; try { results = ActivityValidationServices.Validate(workflowElement, this.settings); } catch (System.Exception e) { ModelItem rootModelItem = this.modelService.Root; Activity rootActivity = rootModelItem.GetRootActivity(); if (rootActivity != null) { // We dont want any crash propagating from here as it causes VS to crash. if (!this.ValidationErrors.ContainsKey(rootActivity)) { ValidationErrorState validationError = new ValidationErrorState(new List (), ValidationState.Error); this.ValidationErrors.Add(rootActivity, validationError); } else { this.ValidationErrors[rootActivity].ValidationState = ValidationState.Error; } this.ValidationErrors[rootActivity].ErrorMessages.Add(e.ToString()); // Notify an update to the attached properties this.NotifyValidationPropertiesChanged(rootModelItem); } validationErrorInfo = new ValidationErrorInfo(e.ToString()); } List validationErrors = null; if (results != null) { validationErrors = new List (results.Errors); validationErrors.AddRange(results.Warnings); } bool needsToMarkValidationErrors = false; if (validationErrors != null) { needsToMarkValidationErrors = MarkErrors(validationErrors, reason); } if (this.errorService != null) // Error service could be null if no implementation has been provided { List errors = new List (); if (validationErrors != null && needsToMarkValidationErrors) { foreach (ValidationError validationError in validationErrors) { ValidationErrorInfo error = new ValidationErrorInfo(validationError); errors.Add(error); } } if (validationErrorInfo != null) { errors.Add(validationErrorInfo); } this.errorService.ShowValidationErrors(errors); } perfProvider.WorkflowDesignerValidationEnd(); this.OnValidationCompleted(); })); } } protected virtual void OnValidationCompleted() { if (this.ValidationCompleted != null) { this.ValidationCompleted(this, new EventArgs()); } } // Find model item and properly create it if necessary. ModelItem FindModelItem(Activity element) { List parentChain = GetParentChain(element); Fx.Assert(parentChain != null, "Cannot find parent chain for " + element.DisplayName); Fx.Assert(this.modelTreeManager != null, "ModelTreeManager is null."); // ModelTreeManager should not be null ModelItem lowestModelItem = null; foreach (Activity parent in parentChain) { lowestModelItem = this.modelTreeManager.GetModelItem(parent); if (lowestModelItem != null) { break; } } Fx.Assert(lowestModelItem != null, "Cannot find lowest model item for parents of " + element.DisplayName); // Root ModelItem should not be null at this point // Walk the tree to create all the model items until it found the model item for the element. return this.modelTreeManager.FindFirst(lowestModelItem, (modelItem) => (modelItem.GetCurrentValue() == element)); } internal static Activity GetParent(Activity childActivity) { // Obtaining the parent from childActivity using (private) reflection. if (parentPropertyInfo == null) { parentPropertyInfo = typeof(Activity).GetProperty("Parent", BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic); } Fx.Assert(parentPropertyInfo != null, "Activity.Parent is not defined"); return parentPropertyInfo.GetValue(childActivity, null) as Activity; } // Get the parent chain of this activity. // Can't use GetParentChain activity because it can only be used in a Constraint. internal static List GetParentChain(Activity activity) { List parentChain = new List (); while (activity != null) { activity = GetParent(activity); if (activity != null) { parentChain.Add(activity); } } return parentChain; } bool MarkErrors(ICollection errors, ValidationReason reason) { // Clear the previous errors/warnings and update the visuals ClearErrors(); Fx.Assert(this.modelTreeManager != null, "ModelTreeManager is null."); // ModelTreeManager should not be null if (HandleErrorsMarked(errors, reason)) { return false; } // Iterate through the new violation list and mark errors/warnings foreach (ValidationError error in errors) { if (error.Source != null) { ModelItem modelItem = this.modelTreeManager.GetModelItem(error.Source); if (modelItem != null) { MarkError(error, modelItem); } else { MarkUnmappedValidationError(error); } } } return true; } bool HandleErrorsMarked(ICollection errors, ValidationReason reason) { if (this.ErrorsMarked != null) { ErrorsMarkedEventArgs arg = new ErrorsMarkedEventArgs (errors, reason, this.modelTreeManager, this.context); this.ErrorsMarked(this, arg); return arg.Handled; } return false; } void MarkUnmappedValidationError(ValidationError validationError) { Activity errorSource = validationError.Source; AddUnmappedValidationError(errorSource, validationError); // Mark errorSource's ancestors. foreach (Activity parent in GetParentChain(errorSource)) { ModelItem modelItem = this.modelTreeManager.GetModelItem(parent); if (modelItem == null) { AddUnmappedValidationError(parent, validationError); } else { // This parent already have a model item. // Then MarkError will propagate to all its ancestors' ModelItem. MarkParents(modelItem, validationError.IsWarning ? ValidationState.Warning : ValidationState.Error); break; } } } void AddUnmappedValidationError(Activity activity, ValidationError validationError) { ValidationErrorState currentError; if (!this.ValidationErrors.TryGetValue(activity, out currentError)) { currentError = new ValidationErrorState(new List (), ValidationState.Valid); this.ValidationErrors.Add(activity, currentError); } MergeValidationError(currentError, validationError); } static void MergeValidationError(ValidationErrorState originalError, ValidationError newError) { if (originalError.ValidationState == ValidationState.ChildInvalid) { // If original error is due to child's issue, clear the error list, // as we don't care about its child's issues anymore and want to add its own issues. originalError.ErrorMessages.Clear(); } ValidationState errorState = newError.IsWarning ? ValidationState.Warning : ValidationState.Error; if (originalError.ValidationState < errorState) { // Promote to the higher level of violation. originalError.ValidationState = errorState; } if (newError.IsWarning) { originalError.ErrorMessages.Add(string.Format(CultureInfo.CurrentUICulture, "{0}{1}", SR.WarningPrefix, newError.Message)); } else { originalError.ErrorMessages.Add(newError.Message); } } // Mark this error to corresponding ModelItem. // Mark all its ancestors accordingly. void MarkError(ValidationError error, ModelItem modelItem) { ValidationErrorState currentError = this.GetValidationError(modelItem); if (currentError == null) { currentError = new ValidationErrorState(new List (), ValidationState.Valid); this.AddValidationError(modelItem, currentError); } MergeValidationError(currentError, error); MarkParents(modelItem.Parent, this.GetValidationState(modelItem)); // Notify an update to the attached properties NotifyValidationPropertiesChanged(modelItem); } void MarkParents(ModelItem parentModelItem, ValidationState childValidationState) { List childErrors = new List (); childErrors.Add(SR.ChildValidationError); Activity parentActivity; while (parentModelItem != null) { parentActivity = parentModelItem.GetCurrentValue() as Activity; if (parentActivity != null) { bool updateAttachedProperties = false; ValidationErrorState validationError; if (!this.ValidationErrors.TryGetValue(parentActivity, out validationError)) { validationError = new ValidationErrorState(childErrors, ValidationState.ChildInvalid); this.AddValidationError(parentModelItem, validationError); updateAttachedProperties = true; } if (validationError.ValidationState < childValidationState) { validationError.ValidationState = childValidationState; updateAttachedProperties = true; } // Notify and update to the attached properties if (updateAttachedProperties) { NotifyValidationPropertiesChanged(parentModelItem); } } parentModelItem = parentModelItem.Parent; } } void ClearErrors() { // Copy over the previously marked model items before you clear the dictionaries Activity[] oldErrorList = new Activity[this.ValidationErrors.Count]; this.ValidationErrors.Keys.CopyTo(oldErrorList, 0); this.ValidationErrors.Clear(); // Iterate through the previously marked model items and notify an update to the attached properties ModelItem modelItem; foreach (Activity workflowElement in oldErrorList) { modelItem = this.modelTreeManager.GetModelItem(workflowElement); if (modelItem != null) { NotifyValidationPropertiesChanged(modelItem); } } } public void NavigateToError(string id) { ModelItem modelItem = null; if (id != null) { Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action( () => { Activity errorElement = ActivityValidationServices.Resolve(GetRootElement(), id); if (errorElement != null) { Fx.Assert(this.modelTreeManager != null, "ModelTreeManager is null."); // ModelTreeManager should not be null modelItem = this.modelTreeManager.GetModelItem(errorElement) ?? this.FindModelItem(errorElement); if (modelItem != null) { // For a VB Expression, need to focus to its parent instead. Activity activity = modelItem.GetCurrentValue() as Activity; if (activity != null && (activity.IsVisualBasicExpression())) { ModelItem parent = modelItem.Parent; while (parent != null && this.ViewService.GetDesignerType(parent.ItemType) == null) { parent = parent.Parent; } if (parent != null) { modelItem = parent; } } modelItem.Focus(); } } })); } } // Properties Dictionary ValidationErrors { get { if (this.validationErrors == null) { this.validationErrors = new Dictionary (); } return this.validationErrors; } } internal AttachedProperty ValidationStateProperty { get { return this.validationStateProperty; } } internal AttachedProperty ValidationMessageProperty { get { return this.validationMessageProperty; } } class ValidationErrorState { internal ValidationErrorState(List errorMessages, ValidationState validationState) { this.ErrorMessages = errorMessages; this.ValidationState = validationState; } internal List ErrorMessages { get; set; } internal ValidationState ValidationState { get; set; } } } } // 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
- ECDiffieHellman.cs
- DnsEndpointIdentity.cs
- FacetDescriptionElement.cs
- SecurityState.cs
- SortDescriptionCollection.cs
- DataKeyArray.cs
- SrgsOneOf.cs
- SqlErrorCollection.cs
- SystemIPInterfaceProperties.cs
- XmlQueryStaticData.cs
- BaseAppDomainProtocolHandler.cs
- DataBindingHandlerAttribute.cs
- AddInToken.cs
- InkSerializer.cs
- ListBindableAttribute.cs
- MenuItemCollection.cs
- StackOverflowException.cs
- PropertyPanel.cs
- NumericPagerField.cs
- ProgressBarAutomationPeer.cs
- glyphs.cs
- PolicyLevel.cs
- SupportsEventValidationAttribute.cs
- MimeTypeMapper.cs
- ImageList.cs
- DesignerForm.cs
- LongAverageAggregationOperator.cs
- MemoryStream.cs
- NetworkCredential.cs
- TimeSpanStorage.cs
- LinkedResource.cs
- Int32KeyFrameCollection.cs
- xml.cs
- ServiceBuildProvider.cs
- BasicViewGenerator.cs
- PngBitmapEncoder.cs
- IndexerReference.cs
- DBSchemaRow.cs
- ToolStripPanelCell.cs
- CollectionBase.cs
- VirtualDirectoryMappingCollection.cs
- DesignerAdapterAttribute.cs
- FunctionDefinition.cs
- Manipulation.cs
- AbsoluteQuery.cs
- TraceHwndHost.cs
- ElementHostAutomationPeer.cs
- NotifyIcon.cs
- BindingBase.cs
- DataContext.cs
- StatusStrip.cs
- BaseDataList.cs
- SqlMultiplexer.cs
- EnumValAlphaComparer.cs
- XmlMemberMapping.cs
- CreateUserErrorEventArgs.cs
- StatusBarItem.cs
- EntryWrittenEventArgs.cs
- DocumentViewerAutomationPeer.cs
- ContextMarshalException.cs
- BitmapFrameEncode.cs
- NamespaceInfo.cs
- xamlnodes.cs
- ToolBarButtonClickEvent.cs
- ZipIOLocalFileHeader.cs
- SecUtil.cs
- RowUpdatingEventArgs.cs
- StreamWriter.cs
- FixedSOMPage.cs
- ComAdminWrapper.cs
- Transform.cs
- DbDeleteCommandTree.cs
- TabControl.cs
- SQLBoolean.cs
- HttpHeaderCollection.cs
- MultipleViewPattern.cs
- FileDialogCustomPlacesCollection.cs
- LayoutDump.cs
- ResourceCategoryAttribute.cs
- HashAlgorithm.cs
- ProjectionPruner.cs
- XPathScanner.cs
- EventEntry.cs
- IISMapPath.cs
- BaseProcessor.cs
- PropertyMetadata.cs
- ListItemCollection.cs
- Collection.cs
- datacache.cs
- DbDataSourceEnumerator.cs
- CommandBinding.cs
- EtwTrace.cs
- TypePropertyEditor.cs
- Substitution.cs
- AssociationSetMetadata.cs
- HttpStreamFormatter.cs
- PenLineJoinValidation.cs
- FontEditor.cs
- Misc.cs
- HtmlObjectListAdapter.cs