EventRoute.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / EventRoute.cs / 1305600 / EventRoute.cs

                            using System; 
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using MS.Utility; 

using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID; 
using MS.Internal;
 
namespace System.Windows
{
    /// 
    ///     Container for the route to be followed 
    ///     by a RoutedEvent when raised
    ///  
    ///  
    ///     EventRoute constitues 
    ///     a non-null  
    ///     and 
    ///     an ordered list of (target object, handler list)
    ///     pairs 
    ///      
    ///
    ///     It facilitates adding new entries to this list 
    ///     and also allows for the handlers in the list 
    ///     to be invoked
    ///  
    public sealed class EventRoute
    {
        #region Construction
 
        /// 
        ///     Constructor for  given 
        ///     the associated  
        /// 
        ///  
        ///     Non-null  to be associated with
        ///     this 
        /// 
        public EventRoute(RoutedEvent routedEvent) 
        {
            if (routedEvent == null) 
            { 
                throw new ArgumentNullException("routedEvent");
            } 

            _routedEvent = routedEvent;

            // Changed the initialization size to 16 
            // to achieve performance gain based
            // on standard app behavior 
            _routeItemList = new FrugalStructList(16); 
            _sourceItemList = new FrugalStructList(16);
        } 

        #endregion Construction

        #region External API 

        ///  
        ///     Adds this handler for the 
        ///     specified target to the route
        ///  
        /// 
        ///     NOTE: It is not an error to add a
        ///     handler for a particular target instance
        ///     twice (handler will simply be called twice). 
        /// 
        ///  
        ///     Target object whose handler is to be 
        ///     added to the route
        ///  
        /// 
        ///     Handler to be added to the route
        /// 
        ///  
        ///     Flag indicating whether or not the listener wants to
        ///     hear about events that have already been handled 
        ///  
        public void Add(object target, Delegate handler, bool handledEventsToo)
        { 
            if (target == null)
            {
                throw new ArgumentNullException("target");
            } 

            if (handler == null) 
            { 
                throw new ArgumentNullException("handler");
            } 

            RouteItem routeItem = new RouteItem(target, new RoutedEventHandlerInfo(handler, handledEventsToo));

            _routeItemList.Add(routeItem); 
        }
 
        ///  
        ///     Invokes all the handlers that have been
        ///     added to the route 
        /// 
        /// 
        ///     NOTE: If the 
        ///     of the associated  
        ///     is 
        ///     the last handlers added are the 
        ///     last ones invoked  
        ///     However if the 
        ///     of the associated  
        ///     is ,
        ///     the last handlers added are the
        ///     first ones invoked
        ///  
        /// 
        ///      
        ///     that raised the RoutedEvent 
        /// 
        ///  
        ///      that carry
        ///     all the details specific to this RoutedEvent
        /// 
        internal void InvokeHandlers(object source, RoutedEventArgs args) 
        {
            InvokeHandlersImpl(source, args, false); 
        } 

        internal void ReInvokeHandlers(object source, RoutedEventArgs args) 
        {
            InvokeHandlersImpl(source, args, true);
        }
 
        private void InvokeHandlersImpl(object source, RoutedEventArgs args, bool reRaised)
        { 
            if (source == null) 
            {
                throw new ArgumentNullException("source"); 
            }

            if (args == null)
            { 
                throw new ArgumentNullException("args");
            } 
 
            if (args.Source == null)
            { 
                throw new ArgumentException(SR.Get(SRID.SourceNotSet));
            }

            if (args.RoutedEvent != _routedEvent) 
            {
                throw new ArgumentException(SR.Get(SRID.Mismatched_RoutedEvent)); 
            } 

            // Check RoutingStrategy to know the order of invocation 
            if (args.RoutedEvent.RoutingStrategy == RoutingStrategy.Bubble ||
                args.RoutedEvent.RoutingStrategy == RoutingStrategy.Direct)
            {
                int endSourceChangeIndex = 0; 

                // If the RoutingStrategy of the associated is 
                // Bubble the handlers for the last target 
                // added are the last ones invoked
                // Invoke class listeners 
                for (int i=0; i<_routeItemList.Count; i++)
                {
                    // Query for new source only if we are
                    // past the range of the previous source change 
                    if (i >= endSourceChangeIndex)
                    { 
                        // Get the source at this point in the bubble route and also 
                        // the index at which this source change seizes to apply
                        object newSource = GetBubbleSource(i, out endSourceChangeIndex); 

                        // Set appropriate source
                        // The first call to setsource seems redundant
                        // but is necessary because the source could have 
                        // been modified during BuildRoute call and hence
                        // may need to be reset to the original source. 
                        // Note: we skip this logic if reRaised is set, which is done when we're trying 
                        //       to convert MouseDown/Up into a MouseLeft/RightButtonDown/Up
                        if(!reRaised) 
                        {
                            if (newSource == null)
                                args.Source=source;
                            else 
                                args.Source=newSource;
                        } 
                    } 

                    // Invoke listeners 

                    if( TraceRoutedEvent.IsEnabled )
                    {
                        TraceRoutedEvent.Trace( 
                            TraceEventType.Start,
                            TraceRoutedEvent.InvokeHandlers, 
                            _routeItemList[i].Target, 
                            args,
                            args.Handled ); 

                    }

                    _routeItemList[i].InvokeHandler(args); 

                    if( TraceRoutedEvent.IsEnabled ) 
                    { 
                        TraceRoutedEvent.Trace(
                            TraceEventType.Stop, 
                            TraceRoutedEvent.InvokeHandlers,
                            _routeItemList[i].Target,
                            args,
                            args.Handled ); 
                    }
 
 
                }
            } 
            else
            {
                int startSourceChangeIndex = _routeItemList.Count;
                int endTargetIndex =_routeItemList.Count-1; 
                int startTargetIndex;
 
                // If the RoutingStrategy of the associated is 
                // Tunnel the handlers for the last target
                // added are the first ones invoked 
                while (endTargetIndex >= 0)
                {
                    // For tunnel events we need to invoke handlers for the last target first.
                    // However the handlers for that individual target must be fired in the right order. 
                    // Eg. Class Handlers must be fired before Instance Handlers.
                    object currTarget = _routeItemList[endTargetIndex].Target; 
                    for (startTargetIndex=endTargetIndex; startTargetIndex>=0; startTargetIndex--) 
                    {
                        if (_routeItemList[startTargetIndex].Target != currTarget) 
                        {
                            break;
                        }
                    } 

                    for (int i=startTargetIndex+1; i<=endTargetIndex; i++) 
                    { 
                        // Query for new source only if we are
                        // past the range of the previous source change 
                        if (i < startSourceChangeIndex)
                        {
                            // Get the source at this point in the tunnel route and also
                            // the index at which this source change seizes to apply 
                            object newSource = GetTunnelSource(i, out startSourceChangeIndex);
 
                            // Set appropriate source 
                            // The first call to setsource seems redundant
                            // but is necessary because the source could have 
                            // been modified during BuildRoute call and hence
                            // may need to be reset to the original source.
                            if (newSource == null)
                                args.Source=source; 
                            else
                                args.Source=newSource; 
                        } 

 
                        if( TraceRoutedEvent.IsEnabled )
                        {
                            TraceRoutedEvent.Trace(
                                TraceEventType.Start, 
                                TraceRoutedEvent.InvokeHandlers,
                                _routeItemList[i].Target, 
                                args, 
                                args.Handled );
                        } 

                        // Invoke listeners
                        _routeItemList[i].InvokeHandler(args);
 
                        if( TraceRoutedEvent.IsEnabled )
                        { 
                            TraceRoutedEvent.Trace( 
                                TraceEventType.Stop,
                                TraceRoutedEvent.InvokeHandlers, 
                                _routeItemList[i].Target,
                                args,
                                args.Handled );
                        } 

                    } 
 
                    endTargetIndex = startTargetIndex;
                } 
            }
        }

        ///  
        ///     Pushes the given node at the top of the stack of branches.
        ///  
        ///  
        ///     If a node in the tree has different visual and logical,
        ///     FrameworkElement will store the node on this stack of 
        ///     branches.  If the route ever returns to the same logical
        ///     tree, the event source will be restored.
        ///     
        ///     NOTE: This method needs to be public because it is used 
        ///     by FrameworkElement.
        ///  
        ///  
        ///     The node where the visual parent is different from the logical
        ///     parent. 
        /// 
        /// 
        ///     The source that is currently being used, and which should be
        ///     restored when this branch is popped off the stack. 
        /// 
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] 
        public void PushBranchNode(object node, object source) 
        {
            BranchNode branchNode = new BranchNode(); 
            branchNode.Node = node;
            branchNode.Source = source;

            BranchNodeStack.Push(branchNode); 
        }
 
        ///  
        ///     Pops the given node from the top of the stack of branches.
        ///  
        /// 
        ///     If a node in the tree has different visual and logical,
        ///     FrameworkElement will store the node on this stack of
        ///     branches.  If the route ever returns to the same logical 
        ///     tree, the event source will be restored.
        ///      
        ///     NOTE: This method needs to be public because it is used 
        ///     by FrameworkElement.
        ///  
        /// 
        ///     The node where the visual parent was different from the
        ///     logical parent.
        ///  
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
        public object PopBranchNode() 
        { 
            if (BranchNodeStack.Count == 0)
                return null; 

            BranchNode branchNode = BranchNodeStack.Pop();

            return branchNode.Node; 
        }
 
        ///  
        ///     Peeks the given node from the top of the stack of branches.
        ///  
        /// 
        ///     If a node in the tree has different visual and logical,
        ///     FrameworkElement will store the node on this stack of
        ///     branches.  If the route ever returns to the same logical 
        ///     tree, the event source will be restored.
        ///      
        ///     NOTE: This method needs to be public because it is used 
        ///     by FrameworkElement.
        ///  
        /// 
        ///     The node where the visual parent was different from the
        ///     logical parent.
        ///  
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
        public object PeekBranchNode() 
        { 
            if (BranchNodeStack.Count == 0)
                return null; 

            BranchNode branchNode = BranchNodeStack.Peek();

            return branchNode.Node; 
        }
 
        ///  
        ///     Peeks the given source from the top of the stack of branches.
        ///  
        /// 
        ///     If a node in the tree has different visual and logical,
        ///     FrameworkElement will store the node on this stack of
        ///     branches.  If the route ever returns to the same logical 
        ///     tree, the event source will be restored.
        ///      
        ///     NOTE: This method needs to be public because it is used 
        ///     by FrameworkElement.
        ///  
        /// 
        ///     The source that was stored along with the node where the
        ///     visual parent was different from the logical parent.
        ///  
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
        public object PeekBranchSource() 
        { 
            if (BranchNodeStack.Count == 0)
                return null; 

            BranchNode branchNode = BranchNodeStack.Peek();

            return branchNode.Source; 
        }
 
        #endregion External API 

        #region Operations 

        // Return associated RoutedEvent
        internal RoutedEvent RoutedEvent
        { 
            get {return _routedEvent;}
            set { _routedEvent = value; } 
        } 

        // A BranchNode indicates a point in the tree where the logical and 
        // visual structure might diverge.  When building a route, we store
        // this branch node for every logical link we find.  Along with the
        // node where the possible divergence occurred, we store the source
        // that the event should use.  This is so that the source of an 
        // event will always be in the logical tree of the element handling
        // the event. 
        private struct BranchNode 
        {
            public object Node; 
            public object Source;
        }

        // Branch nodes are stored on a stack, which we create on-demand. 
        private Stack BranchNodeStack
        { 
            get 
            {
                if (_branchNodeStack == null) 
                {
                    _branchNodeStack = new Stack(1);
                }
 
                return _branchNodeStack;
            } 
        } 

        // Add the given source to the source item list 
        // indicating what the source will be this point
        // onwards in the route
        internal void AddSource(object source)
        { 
            int startIndex = _routeItemList.Count;
            _sourceItemList.Add(new SourceItem(startIndex, source)); 
        } 

        // Determine what the RoutedEventArgs.Source should be, at this 
        // point in the bubble. Also the endIndex output parameter tells
        // you the exact index of the handlersList at which this source
        // change ceases to apply
        private object GetBubbleSource(int index, out int endIndex) 
        {
            // If the Source never changes during the route execution, 
            // then we're done (just return null). 
            if (_sourceItemList.Count == 0)
            { 
                endIndex = _routeItemList.Count;
                return null;
            }
 
            // Similarly, if we're not to the point of the route of the first Source
            // change, simply return null. 
            if (index < _sourceItemList[0].StartIndex) 
            {
                endIndex = _sourceItemList[0].StartIndex; 
                return null;
            }

            // See if we should be using one of the intermediate 
            // sources
            for (int i=0; i<_sourceItemList.Count -1; i++) 
            { 
                if (index >= _sourceItemList[i].StartIndex &&
                    index < _sourceItemList[i+1].StartIndex) 
                {
                    endIndex = _sourceItemList[i+1].StartIndex;
                    return _sourceItemList[i].Source;
                } 
            }
 
            // If we get here, we're on the last one, 
            // so return that.
            endIndex = _routeItemList.Count; 
            return _sourceItemList[_sourceItemList.Count -1].Source;
        }

        // Determine what the RoutedEventArgs.Source should be, at this 
        // point in the tunnel. Also the startIndex output parameter tells
        // you the exact index of the handlersList at which this source 
        // change starts to apply 
        private object GetTunnelSource(int index, out int startIndex)
        { 
            // If the Source never changes during the route execution,
            // then we're done (just return null).
            if (_sourceItemList.Count == 0)
            { 
                startIndex = 0;
                return null; 
            } 

            // Similarly, if we're past the point of the route of the first Source 
            // change, simply return null.
            if (index < _sourceItemList[0].StartIndex)
            {
                startIndex = 0; 
                return null;
            } 
 
            // See if we should be using one of the intermediate
            // sources 
            for (int i=0; i<_sourceItemList.Count -1; i++)
            {
                if (index >= _sourceItemList[i].StartIndex &&
                    index < _sourceItemList[i+1].StartIndex) 
                {
                    startIndex = _sourceItemList[i].StartIndex; 
                    return _sourceItemList[i].Source; 
                }
            } 

            // If we get here, we're on the last one, so return that.
            startIndex = _sourceItemList[_sourceItemList.Count -1].StartIndex;
            return _sourceItemList[_sourceItemList.Count -1].Source; 
        }
 
        ///  
        ///     Cleanup all the references within the data
        ///  
        internal void Clear()
        {
            _routedEvent = null;
 
            _routeItemList.Clear();
 
            if (_branchNodeStack != null) 
            {
                _branchNodeStack.Clear(); 
            }

            _sourceItemList.Clear();
        } 

        #endregion Operations 
 
        #region Data
 
        private RoutedEvent _routedEvent;

        // Stores the routed event handlers to be
        // invoked for the associated RoutedEvent 
        private FrugalStructList _routeItemList;
 
        // Stores the branching nodes in the route 
        // that need to be backtracked while
        // augmenting the route 
        private Stack _branchNodeStack;

        // Stores Source Items for separated trees
        private FrugalStructList _sourceItemList; 

        #endregion Data 
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK