/// <summary>
        /// Traverse the specified connector, if possible.
        /// This is NOT thread-safe, you must call it in a critical section.
        /// </summary>
        /// <param name="connector"></param>
        /// <param name="args">Optional event args related to the connector traversal</param>
        /// <returns>true if the connector was traversed.</returns>
        protected bool TraverseConnector(IUmlConnector connector, TransitionEventArgs args = null)
        {
            bool traversed = false;

            if (CurrentNode == connector.Supplier && connector.CanTraverse &&
                (connector.Consumer.CanEnter || connector.Consumer == connector.Supplier))
            {
                // Broke this condition out separately because the order of TryExit is important.
                if (connector.Supplier.TryExit()
                    // If Consumer is Supplier, just make sure again that Consumer can enter now that it has been exited.
                    && (connector.Consumer != connector.Supplier || connector.Consumer.CanEnter))
                {
                    // Hook up to the connector's traversed event so that the CurrentNode value will be set before the node is entered.
                    // This allows a node's ENTER and DO behaviors to rely on the new current state.
                    connector.Traversed += HandleConnectorTraversed;

                    // Successful traversal will first set the current state in this machine,
                    // then set the new state on this machine's IStatefulModel. This order is important.
                    traversed = connector.Traverse(args);

                    // Traversal attempt is finished.  Whether it succeeded or failed, the event handling is no longer needed.
                    connector.Traversed -= HandleConnectorTraversed;
                }
            }
            return(traversed);
        }
        public void AddConnector(IUmlConnector connector)
        {
            if (connector == null)
            {
                return;
            }

            _connectors.Add(connector);
            connector.Traversed += HandleOutboundConnectorTraversed;
        }
        protected bool TraverseConnector(IUmlConnector connector, TransitionEventArgs args = null)
        {
            // If this machine is paused, don't allow transitions.
            lock (_executionLock)
            {
                if (ExecutableState == ExecutableState.Paused && CompletionCause == CompletionCause.Pending)
                {
                    return(false);
                }
            }

            bool transitioned = false;

            lock (_connectorTraversalLock)
            {
                if (CurrentNode == connector.Supplier && connector.CanTraverse &&
                    connector.Consumer != null && connector.Consumer.CanEnter &&
                    connector.Supplier != null && connector.Supplier.TryExit())
                {
                    // Hook up to the connector's traversed event so that the CurrentNode value will be set before the node is entered.
                    // This allows a node's ENTER and DO behaviors to rely on the new current state.
                    connector.Traversed += HandleConnectorTraversed;

                    transitioned = connector.Traverse(args);
                    if (!transitioned)
                    {
                        LogService.Log(LogType, LogMessageType.Error, Name,
                                       string.Format(CultureInfo.InvariantCulture, "Exited '{0}' but failed to transition into '{1}' node.  Machine is in a limbo state.",
                                                     connector.Supplier.Name, connector.Consumer.Name));
                    }

                    // Traversal attempt is finished.  Whether it succeeded or failed, the event handling is no longer needed.
                    connector.Traversed -= HandleConnectorTraversed;
                }
            }
            if (transitioned)
            {
                // Try to keep this activation running.
                RunToCompletion();
            }
            return(transitioned);
        }