File: EventHandlingScope.cs
Project: ndp\cdf\src\WF\Activities\System.Workflow.Activities.csproj (System.Workflow.Activities)
namespace System.Workflow.Activities
{
    #region Imports
 
    using System;
    using System.Text;
    using System.Reflection;
    using System.Collections;
    using System.CodeDom;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Design;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.Activities.Common;
 
    #endregion
 
    [SRDescription(SR.EventHandlingScopeActivityDescription)]
    [ToolboxItem(typeof(ActivityToolboxItem))]
    [ToolboxBitmap(typeof(EventHandlingScopeActivity), "Resources.Sequence.png")]
    [ActivityValidator(typeof(EventHandlingScopeValidator))]
    [Designer(typeof(EventHandlingScopeDesigner), typeof(IDesigner))]
    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public sealed class EventHandlingScopeActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
    {
        public EventHandlingScopeActivity()
        {
        }
        public EventHandlingScopeActivity(string name)
            : base(name)
        {
        }
 
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            Activity bodyActivity = this.BodyActivity;
 
            if (bodyActivity == null)
                return ActivityExecutionStatus.Closed;
 
            // run EventHandlers
            EventHandlersActivity eventHandlers = this.EventHandlersActivity;
            if (eventHandlers != null)
            {
                eventHandlers.RegisterForStatusChange(Activity.ClosedEvent, this);
                executionContext.ExecuteActivity(eventHandlers);
            }
 
            // run body
            bodyActivity.RegisterForStatusChange(Activity.ClosedEvent, this);
            executionContext.ExecuteActivity(bodyActivity);
 
 
            // return the status
            return this.ExecutionStatus;
        }
        protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
        {
            if (executionContext == null)
                throw new ArgumentNullException("executionContext");
 
            Activity bodyActivity = this.BodyActivity;
            EventHandlersActivity eventHandlers = this.EventHandlersActivity;
 
            if (bodyActivity == null && eventHandlers == null)
                return ActivityExecutionStatus.Closed;
 
            bool cancelScheduled = false;
 
            // check the status of body
            if (bodyActivity != null && bodyActivity.ExecutionStatus == ActivityExecutionStatus.Executing)
            {
                executionContext.CancelActivity(bodyActivity);
                cancelScheduled = true;
            }
            //Check the status of EventHandlers
            if (eventHandlers != null && eventHandlers.ExecutionStatus == ActivityExecutionStatus.Executing)
            {
                executionContext.CancelActivity(eventHandlers);
                cancelScheduled = true;
            }
 
            if (cancelScheduled ||
                        (bodyActivity != null && (bodyActivity.ExecutionStatus == ActivityExecutionStatus.Faulting ||
                        bodyActivity.ExecutionStatus == ActivityExecutionStatus.Canceling)) ||
                        (eventHandlers != null && (eventHandlers.ExecutionStatus == ActivityExecutionStatus.Faulting ||
                        eventHandlers.ExecutionStatus == ActivityExecutionStatus.Canceling))
                )
            {
                return this.ExecutionStatus;
            }
            return ActivityExecutionStatus.Closed;
        }
 
        #region IActivityEventListener<ActivityExecutionStatusChangedEventArgs> Members
 
        void IActivityEventListener<ActivityExecutionStatusChangedEventArgs>.OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
        {
            ActivityExecutionContext context = sender as ActivityExecutionContext;
            if (context == null)
                throw new ArgumentException();
 
            e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
            if (e.Activity is EventHandlersActivity)
            {
                if (this.BodyActivity.ExecutionStatus == ActivityExecutionStatus.Closed)
                {
                    context.CloseActivity();
                }
                //else Eventhandlers faulted, let exception propagate up.                                
            }
            else
            {
                EventHandlersActivity eventHandlers = this.EventHandlersActivity;
                if (eventHandlers == null || eventHandlers.ExecutionStatus == ActivityExecutionStatus.Closed)
                {
                    context.CloseActivity();
                }
                else
                {
                    eventHandlers.UnsubscribeAndClose();
                }
            }
        }
        #endregion
 
        internal EventHandlersActivity EventHandlersActivity
        {
            get
            {
                EventHandlersActivity eventHandlers = null;
                foreach (Activity child in this.EnabledActivities)
                {
                    if (child is EventHandlersActivity)
                        eventHandlers = child as EventHandlersActivity;
                }
                return eventHandlers;
            }
        }
        internal Activity BodyActivity
        {
            get
            {
                Activity body = null;
                foreach (Activity child in this.EnabledActivities)
                {
                    if (!(child is EventHandlersActivity))
                        body = child;
                }
                return body;
            }
        }
        #region Dynamic Update Methods
 
        [NonSerialized]
        private bool eventHandlersRemovedInDynamicUpdate = false;
        [NonSerialized]
        private bool bodyActivityRemovedInDynamicUpdate = false;
 
        protected override void OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity)
        {
            base.OnActivityChangeRemove(executionContext, removedActivity);
 
            if (removedActivity is EventHandlersActivity)
                eventHandlersRemovedInDynamicUpdate = true;
            else
                bodyActivityRemovedInDynamicUpdate = true;
        }
 
        protected override void OnWorkflowChangesCompleted(ActivityExecutionContext executionContext)
        {
            base.OnWorkflowChangesCompleted(executionContext);
 
            switch (this.ExecutionStatus)
            {
                case ActivityExecutionStatus.Executing:
                    if (bodyActivityRemovedInDynamicUpdate)
                    {
                        if (EventHandlersActivity == null || EventHandlersActivity.ExecutionStatus == ActivityExecutionStatus.Closed)
                            executionContext.CloseActivity();
                        else if (EventHandlersActivity.ExecutionStatus == ActivityExecutionStatus.Executing)
                            EventHandlersActivity.UnsubscribeAndClose();
                    }
                    if (eventHandlersRemovedInDynamicUpdate)
                    {
                        if (BodyActivity == null || BodyActivity.ExecutionStatus == ActivityExecutionStatus.Closed)
                            executionContext.CloseActivity();
                    }
                    break;
                default:
                    break;
            }
            eventHandlersRemovedInDynamicUpdate = false;
            bodyActivityRemovedInDynamicUpdate = false;
        }
        #endregion
    }
 
    #region Class EventHandlingScopeValidator
    internal sealed class EventHandlingScopeValidator : CompositeActivityValidator
    {
        public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
        {
            ValidationErrorCollection validationErrors = base.Validate(manager, obj);
 
            EventHandlingScopeActivity compositeActivity = obj as EventHandlingScopeActivity;
            if (compositeActivity == null)
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(EventHandlingScopeActivity).FullName), "obj");
 
            //we only allow one activity to be inserted
            int childCount = 0;
            int eventHandlersCount = 0;
            foreach (Activity child in compositeActivity.EnabledActivities)
            {
                if (child is EventHandlersActivity)
                    eventHandlersCount++;
                else
                    childCount++;
            }
 
            // check if more than two activities inside the collection
            if (childCount > 1)
                validationErrors.Add(new ValidationError(SR.GetString(SR.Error_MoreThanTwoActivitiesInEventHandlingScope, compositeActivity.QualifiedName), ErrorNumbers.Error_MoreThanTwoActivitiesInEventHandlingScope));
 
            // check if more than one EventHandlers
            if (eventHandlersCount > 1)
                validationErrors.Add(new ValidationError(SR.GetString(SR.Error_MoreThanOneEventHandlersDecl, compositeActivity.GetType().Name), ErrorNumbers.Error_ScopeMoreThanOneEventHandlersDecl));
 
            return validationErrors;
        }
 
        public override ValidationError ValidateActivityChange(Activity activity, ActivityChangeAction action)
        {
            if (activity == null)
                throw new ArgumentNullException("activity");
            if (action == null)
                throw new ArgumentNullException("action");
 
            if (activity.ExecutionStatus != ActivityExecutionStatus.Initialized &&
                activity.ExecutionStatus != ActivityExecutionStatus.Executing &&
                activity.ExecutionStatus != ActivityExecutionStatus.Closed)
            {
                return new ValidationError(SR.GetString(SR.Error_DynamicActivity2, activity.QualifiedName, Enum.GetName(typeof(ActivityExecutionStatus), activity.ExecutionStatus), activity.GetType().FullName), ErrorNumbers.Error_DynamicActivity2);
            }
            if (activity.ExecutionStatus == ActivityExecutionStatus.Executing && action is AddedActivityAction)
            {
                return new ValidationError(SR.GetString(SR.Error_DynamicActivity3, activity.QualifiedName, Enum.GetName(typeof(ActivityExecutionStatus), activity.ExecutionStatus), activity.GetType().FullName), ErrorNumbers.Error_DynamicActivity2);
            }
            return null;
        }
    }
    #endregion
 
    #region Class EventHandlingScopeDesigner
 
    [ActivityDesignerTheme(typeof(EventHandlingScopeActivityDesignerTheme))]
    internal sealed class EventHandlingScopeDesigner : SequentialActivityDesigner
    {
        #region Properties and Methods
        public override bool CanExpandCollapse
        {
            get
            {
                return false;
            }
        }
        #endregion
 
        public override bool CanInsertActivities(HitTestInfo insertLocation, System.Collections.ObjectModel.ReadOnlyCollection<Activity> activitiesToInsert)
        {
            //we only allow one activity to be inserted
            int childCount = 0;
            foreach (Activity child in ((EventHandlingScopeActivity)this.Activity).Activities)
            {
                if (!Helpers.IsFrameworkActivity(child) &&
                    !(child is EventHandlersActivity))
                    childCount++;
            }
            if (childCount > 0)
                return false;
 
            return base.CanInsertActivities(insertLocation, activitiesToInsert);
        }
    }
    #endregion
 
    #region EventHandlingScopeActivityDesignerTheme
    internal sealed class EventHandlingScopeActivityDesignerTheme : CompositeDesignerTheme
    {
        public EventHandlingScopeActivityDesignerTheme(WorkflowTheme theme)
            : base(theme)
        {
            this.ShowDropShadow = false;
            this.ConnectorStartCap = LineAnchor.None;
            this.ConnectorEndCap = LineAnchor.ArrowAnchor;
            this.ForeColor = Color.FromArgb(0xFF, 0x00, 0x00, 0x00);
            this.BorderColor = Color.FromArgb(0xFF, 0xE0, 0xE0, 0xE0);
            this.BorderStyle = DashStyle.Dash;
            this.BackColorStart = Color.FromArgb(0x00, 0x00, 0x00, 0x00);
            this.BackColorEnd = Color.FromArgb(0x00, 0x00, 0x00, 0x00);
        }
    }
    #endregion
}