EventTrigger.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / EventTrigger.cs / 1 / EventTrigger.cs

                            /****************************************************************************\ 
*
* File: EventTrigger.cs
*
* An event trigger is a set of actions that will be activated in response to 
*  the specified event fired elsewhere.
* 
* Copyright (C) by Microsoft Corporation.  All rights reserved. 
*
\***************************************************************************/ 

using System.Collections;
using System.Diagnostics;
using System.Windows.Markup; 
using System.Collections.Specialized;
using System.ComponentModel; 
 
namespace System.Windows
{ 
    /// 
    ///   A class that controls a set of actions to activate in response to an event
    /// 
    [ContentProperty("Actions")] 
    public class EventTrigger : TriggerBase, IAddChild
    { 
        /////////////////////////////////////////////////////////////////////// 
        // Public members
 
        /// 
        ///     Build an empty instance of the EventTrigger object
        /// 
        public EventTrigger() 
        {
        } 
 
        /// 
        ///     Build an instance of EventTrigger associated with the given event 
        /// 
        public EventTrigger( RoutedEvent routedEvent )
        {
            RoutedEvent = routedEvent; 
        }
 
        ///  
        ///  Add an object child to this trigger's Actions
        ///  
        void IAddChild.AddChild(object value)
        {
            AddChild(value);
        } 

        ///  
        ///  Add an object child to this trigger's Actions 
        /// 
        protected virtual void AddChild(object value) 
        {
            TriggerAction action = value as TriggerAction;
            if (action == null)
            { 
                throw new ArgumentException(SR.Get(SRID.EventTriggerBadAction, value.GetType().Name));
            } 
            Actions.Add(action); 
        }
 
        /// 
        ///  Add a text string to this trigger's Actions.  Note that this
        ///  is not supported and will result in an exception.
        ///  
        void IAddChild.AddText(string text)
        { 
            AddText(text); 
        }
 
        /// 
        ///  Add a text string to this trigger's Actions.  Note that this
        ///  is not supported and will result in an exception.
        ///  
        protected virtual void AddText(string text)
        { 
            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); 
        }
 
        /// 
        ///     The Event that will activate this trigger - one must be specified
        /// before an event trigger is meaningful.
        ///  
        public RoutedEvent RoutedEvent
        { 
            get 
            {
                return _routedEvent; 
            }
            set
            {
                if ( value == null ) 
                {
                    throw new ArgumentNullException("value"); 
                } 

                if( IsSealed ) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "EventTrigger"));
                }
 
                // When used as an element trigger, we don't actually need to seal
                //  to ensure cross-thread usability.  However, if we *are* fixed on 
                //  listening to an event already, don't allow this change. 
                if( _routedEventHandler != null )
                { 
                    // Recycle the Seal error message.
                    throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "EventTrigger"));
                }
 
                _routedEvent = value;
            } 
        } 

        ///  
        ///     The x:Name of the object whose event shall trigger this
        /// EventTrigger.   If null, then this is the object being Styled
        /// and not anything under its Style.VisualTree.
        ///  
        [DefaultValue(null)]
        public string SourceName 
        { 
            get
            { 
                return _sourceName;
            }
            set
            { 
                if( IsSealed )
                { 
                    throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "EventTrigger")); 
                }
 
                _sourceName = value;
            }
        }
 
        /// 
        ///     Internal method to get the childId corresponding to the public 
        /// sourceId. 
        /// 
        internal int TriggerChildIndex 
        {
            get
            {
                return _childId; 
            }
            set 
            { 
                _childId = value;
            } 
        }

        /// 
        ///     The collection of actions to activate when the Event occurs. 
        /// At least one action is required for the trigger to be meaningful.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
        public TriggerActionCollection Actions
        { 
            get
            {
                if( _actions == null )
                { 
                    _actions = new TriggerActionCollection();
 
                    // Give the collection a back-link, this is used for the inheritance context 
                    _actions.Owner = this;
                } 
                return _actions;
            }
        }
 

        ///  
        ///     If we get a new inheritance context (or it goes to null) 
        ///     we need to tell actions about it.
        ///  
        internal override void OnInheritanceContextChangedCore(EventArgs args)
        {
            base.OnInheritanceContextChangedCore(args);
 
            if (_actions == null)
            { 
                return; 
            }
 
            for (int i=0; i<_actions.Count; i++)
            {
                DependencyObject action = _actions[i] as DependencyObject;
                if (action != null && action.InheritanceContext == this) 
                {
                    action.OnInheritanceContextChanged(args); 
                } 
            }
        } 

        /// 
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeActions() 
        {
            return ( _actions != null && _actions.Count > 0 ); 
        }

        ///////////////////////////////////////////////////////////////////////
        // Internal members 

        internal sealed override void Seal() 
        { 
            if( PropertyValues.Count > 0 )
            { 
                throw new InvalidOperationException(SR.Get(SRID.EventTriggerDoNotSetProperties));
            }

            // EnterActions/ExitActions aren't meaningful on event triggers. 
            if( HasEnterActions || HasExitActions )
            { 
                throw new InvalidOperationException(SR.Get(SRID.EventTriggerDoesNotEnterExit)); 
            }
 
            if (_routedEvent != null && _actions != null && _actions.Count > 0)
            {
                _actions.Seal(this);  // TriggerActions need a link back to me to fetch the childId corresponding the sourceId string.
            } 

            base.Seal(); // Should be almost a no-op given lack of PropertyValues 
        } 

        /////////////////////////////////////////////////////////////////////// 
        // Private members

        // Event that will fire this trigger
        private RoutedEvent _routedEvent = null; 

        // Name of the Style.VisualTree node whose event to listen to. 
        //  May remain the default value of null, which  means the object being 
        //  Styled is the target instead of something within the Style.VisualTree.
        private string _sourceName = null; 

        // Style childId corresponding to the SourceName string
        private int _childId = 0;
 
        // Actions to invoke when this trigger is fired
        private TriggerActionCollection _actions = null; 
 
        ///////////////////////////////////////////////////////////////////////
        // Storage attached to other objects to support triggers 
        //  Some of these can be moved to base class as necessary.

        //  Exists on objects that have information in their [Class].Triggers collection property. (Currently root FrameworkElement only.)
        internal static readonly UncommonField TriggerCollectionField = new UncommonField(null); 

        // This is the listener that we hook up to the SourceId element. 
        RoutedEventHandler _routedEventHandler = null; 

        // This is the SourceId-ed element. 
        FrameworkElement _source;


 
        ///////////////////////////////////////////////////////////////////////
        // Internal static methods to process event trigger information stored 
        //  in attached storage of other objects. 
        //
        // Called when the FrameworkElement and the tree structure underneath it has been 
        //  built up.  This is the earliest point we can resolve all the child
        //  node identification that may exist in a Trigger object.
        // This should be moved to base class if PropertyTrigger support is added.
        internal static void ProcessTriggerCollection( FrameworkElement triggersHost ) 
        {
            TriggerCollection triggerCollection = TriggerCollectionField.GetValue(triggersHost); 
            if( triggerCollection != null ) 
            {
                // Don't seal the collection, because we allow it to change.  We will, 
                // however, seal each of the triggers.

                for( int i = 0; i < triggerCollection.Count; i++ )
                { 
                    ProcessOneTrigger( triggersHost, triggerCollection[i] );
                } 
            } 
        }
 

        ////////////////////////////////////////////////////////////////////////
        // ProcessOneTrigger
        // 
        // Find the target element for this trigger, and set a listener for
        // the event into (pointing back to the trigger). 
 
        internal static void ProcessOneTrigger( FrameworkElement triggersHost, TriggerBase triggerBase )
        { 
            // This code path is used in the element trigger case.  We don't actually
            //  need these guys to be usable cross-thread, so we don't really need
            //  to freeze/seal these objects.  The only one expected to cause problems
            //  is a change to the RoutedEvent.  At the same time we remove this 
            //  Seal(), the RoutedEvent setter will check to see if the handler has
            //  already been created and refuse an update if so. 
            // triggerBase.Seal(); 

            EventTrigger eventTrigger = triggerBase as EventTrigger; 
            if( eventTrigger != null )
            {
                Debug.Assert( eventTrigger._routedEventHandler == null && eventTrigger._source == null);
 
                // PERF: Cache this result if it turns out we're doing a lot of lookups on the same name.
                eventTrigger._source = FrameworkElement.FindNamedFrameworkElement( triggersHost, eventTrigger.SourceName ); 
 
                // Create a statefull event delegate (which keeps a ref to the FE).
                EventTriggerSourceListener listener = new EventTriggerSourceListener( eventTrigger, triggersHost ); 


                // Store the RoutedEventHandler & target for use in DisconnectOneTrigger
                eventTrigger._routedEventHandler = new RoutedEventHandler(listener.Handler); 
                eventTrigger._source.AddHandler( eventTrigger.RoutedEvent, eventTrigger._routedEventHandler,
                                                 false /* HandledEventsToo */ ); 
            } 
            else
            { 
                throw new InvalidOperationException(SR.Get(SRID.TriggersSupportsEventTriggersOnly));
            }
        }
 
        ////////////////////////////////////////////////////////////////////////
        // 
        // DisconnectAllTriggers 
        //
        // Call DisconnectOneTrigger for each trigger in the Triggers collection. 

        internal static void DisconnectAllTriggers( FrameworkElement triggersHost )
        {
            TriggerCollection triggerCollection = TriggerCollectionField.GetValue(triggersHost); 

            if( triggerCollection != null ) 
            { 
                for( int i = 0; i < triggerCollection.Count; i++ )
                { 
                    DisconnectOneTrigger( triggersHost, triggerCollection[i] );
                }

            } 
        }
 
        //////////////////////////////////////////////////////////////////////// 
        //
        // DisconnectOneTrigger 
        //
        // In ProcessOneTrigger, we connect an event trigger to the element
        // which it targets.  Here, we remove the event listener to clean up.
 
        internal static void DisconnectOneTrigger( FrameworkElement triggersHost, TriggerBase triggerBase )
        { 
            EventTrigger eventTrigger = triggerBase as EventTrigger; 

            if( eventTrigger != null ) 
            {
                eventTrigger._source.RemoveHandler( eventTrigger.RoutedEvent, eventTrigger._routedEventHandler);
                eventTrigger._routedEventHandler = null;
            } 
            else
            { 
                throw new InvalidOperationException(SR.Get(SRID.TriggersSupportsEventTriggersOnly)); 
            }
        } 



        internal class EventTriggerSourceListener 
        {
            internal EventTriggerSourceListener( EventTrigger trigger, FrameworkElement host ) 
            { 
                _owningTrigger = trigger;
                _owningTriggerHost = host; 
            }

            internal void Handler(object sender, RoutedEventArgs e)
            { 
                // Invoke all actions of the associated EventTrigger object.
                TriggerActionCollection actions = _owningTrigger.Actions; 
                for( int j = 0; j < actions.Count; j++ ) 
                {
                    actions[j].Invoke(_owningTriggerHost); 
                }
            }

            private EventTrigger     _owningTrigger; 
            private FrameworkElement _owningTriggerHost;
        } 
 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/****************************************************************************\ 
*
* File: EventTrigger.cs
*
* An event trigger is a set of actions that will be activated in response to 
*  the specified event fired elsewhere.
* 
* Copyright (C) by Microsoft Corporation.  All rights reserved. 
*
\***************************************************************************/ 

using System.Collections;
using System.Diagnostics;
using System.Windows.Markup; 
using System.Collections.Specialized;
using System.ComponentModel; 
 
namespace System.Windows
{ 
    /// 
    ///   A class that controls a set of actions to activate in response to an event
    /// 
    [ContentProperty("Actions")] 
    public class EventTrigger : TriggerBase, IAddChild
    { 
        /////////////////////////////////////////////////////////////////////// 
        // Public members
 
        /// 
        ///     Build an empty instance of the EventTrigger object
        /// 
        public EventTrigger() 
        {
        } 
 
        /// 
        ///     Build an instance of EventTrigger associated with the given event 
        /// 
        public EventTrigger( RoutedEvent routedEvent )
        {
            RoutedEvent = routedEvent; 
        }
 
        ///  
        ///  Add an object child to this trigger's Actions
        ///  
        void IAddChild.AddChild(object value)
        {
            AddChild(value);
        } 

        ///  
        ///  Add an object child to this trigger's Actions 
        /// 
        protected virtual void AddChild(object value) 
        {
            TriggerAction action = value as TriggerAction;
            if (action == null)
            { 
                throw new ArgumentException(SR.Get(SRID.EventTriggerBadAction, value.GetType().Name));
            } 
            Actions.Add(action); 
        }
 
        /// 
        ///  Add a text string to this trigger's Actions.  Note that this
        ///  is not supported and will result in an exception.
        ///  
        void IAddChild.AddText(string text)
        { 
            AddText(text); 
        }
 
        /// 
        ///  Add a text string to this trigger's Actions.  Note that this
        ///  is not supported and will result in an exception.
        ///  
        protected virtual void AddText(string text)
        { 
            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); 
        }
 
        /// 
        ///     The Event that will activate this trigger - one must be specified
        /// before an event trigger is meaningful.
        ///  
        public RoutedEvent RoutedEvent
        { 
            get 
            {
                return _routedEvent; 
            }
            set
            {
                if ( value == null ) 
                {
                    throw new ArgumentNullException("value"); 
                } 

                if( IsSealed ) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "EventTrigger"));
                }
 
                // When used as an element trigger, we don't actually need to seal
                //  to ensure cross-thread usability.  However, if we *are* fixed on 
                //  listening to an event already, don't allow this change. 
                if( _routedEventHandler != null )
                { 
                    // Recycle the Seal error message.
                    throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "EventTrigger"));
                }
 
                _routedEvent = value;
            } 
        } 

        ///  
        ///     The x:Name of the object whose event shall trigger this
        /// EventTrigger.   If null, then this is the object being Styled
        /// and not anything under its Style.VisualTree.
        ///  
        [DefaultValue(null)]
        public string SourceName 
        { 
            get
            { 
                return _sourceName;
            }
            set
            { 
                if( IsSealed )
                { 
                    throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "EventTrigger")); 
                }
 
                _sourceName = value;
            }
        }
 
        /// 
        ///     Internal method to get the childId corresponding to the public 
        /// sourceId. 
        /// 
        internal int TriggerChildIndex 
        {
            get
            {
                return _childId; 
            }
            set 
            { 
                _childId = value;
            } 
        }

        /// 
        ///     The collection of actions to activate when the Event occurs. 
        /// At least one action is required for the trigger to be meaningful.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
        public TriggerActionCollection Actions
        { 
            get
            {
                if( _actions == null )
                { 
                    _actions = new TriggerActionCollection();
 
                    // Give the collection a back-link, this is used for the inheritance context 
                    _actions.Owner = this;
                } 
                return _actions;
            }
        }
 

        ///  
        ///     If we get a new inheritance context (or it goes to null) 
        ///     we need to tell actions about it.
        ///  
        internal override void OnInheritanceContextChangedCore(EventArgs args)
        {
            base.OnInheritanceContextChangedCore(args);
 
            if (_actions == null)
            { 
                return; 
            }
 
            for (int i=0; i<_actions.Count; i++)
            {
                DependencyObject action = _actions[i] as DependencyObject;
                if (action != null && action.InheritanceContext == this) 
                {
                    action.OnInheritanceContextChanged(args); 
                } 
            }
        } 

        /// 
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeActions() 
        {
            return ( _actions != null && _actions.Count > 0 ); 
        }

        ///////////////////////////////////////////////////////////////////////
        // Internal members 

        internal sealed override void Seal() 
        { 
            if( PropertyValues.Count > 0 )
            { 
                throw new InvalidOperationException(SR.Get(SRID.EventTriggerDoNotSetProperties));
            }

            // EnterActions/ExitActions aren't meaningful on event triggers. 
            if( HasEnterActions || HasExitActions )
            { 
                throw new InvalidOperationException(SR.Get(SRID.EventTriggerDoesNotEnterExit)); 
            }
 
            if (_routedEvent != null && _actions != null && _actions.Count > 0)
            {
                _actions.Seal(this);  // TriggerActions need a link back to me to fetch the childId corresponding the sourceId string.
            } 

            base.Seal(); // Should be almost a no-op given lack of PropertyValues 
        } 

        /////////////////////////////////////////////////////////////////////// 
        // Private members

        // Event that will fire this trigger
        private RoutedEvent _routedEvent = null; 

        // Name of the Style.VisualTree node whose event to listen to. 
        //  May remain the default value of null, which  means the object being 
        //  Styled is the target instead of something within the Style.VisualTree.
        private string _sourceName = null; 

        // Style childId corresponding to the SourceName string
        private int _childId = 0;
 
        // Actions to invoke when this trigger is fired
        private TriggerActionCollection _actions = null; 
 
        ///////////////////////////////////////////////////////////////////////
        // Storage attached to other objects to support triggers 
        //  Some of these can be moved to base class as necessary.

        //  Exists on objects that have information in their [Class].Triggers collection property. (Currently root FrameworkElement only.)
        internal static readonly UncommonField TriggerCollectionField = new UncommonField(null); 

        // This is the listener that we hook up to the SourceId element. 
        RoutedEventHandler _routedEventHandler = null; 

        // This is the SourceId-ed element. 
        FrameworkElement _source;


 
        ///////////////////////////////////////////////////////////////////////
        // Internal static methods to process event trigger information stored 
        //  in attached storage of other objects. 
        //
        // Called when the FrameworkElement and the tree structure underneath it has been 
        //  built up.  This is the earliest point we can resolve all the child
        //  node identification that may exist in a Trigger object.
        // This should be moved to base class if PropertyTrigger support is added.
        internal static void ProcessTriggerCollection( FrameworkElement triggersHost ) 
        {
            TriggerCollection triggerCollection = TriggerCollectionField.GetValue(triggersHost); 
            if( triggerCollection != null ) 
            {
                // Don't seal the collection, because we allow it to change.  We will, 
                // however, seal each of the triggers.

                for( int i = 0; i < triggerCollection.Count; i++ )
                { 
                    ProcessOneTrigger( triggersHost, triggerCollection[i] );
                } 
            } 
        }
 

        ////////////////////////////////////////////////////////////////////////
        // ProcessOneTrigger
        // 
        // Find the target element for this trigger, and set a listener for
        // the event into (pointing back to the trigger). 
 
        internal static void ProcessOneTrigger( FrameworkElement triggersHost, TriggerBase triggerBase )
        { 
            // This code path is used in the element trigger case.  We don't actually
            //  need these guys to be usable cross-thread, so we don't really need
            //  to freeze/seal these objects.  The only one expected to cause problems
            //  is a change to the RoutedEvent.  At the same time we remove this 
            //  Seal(), the RoutedEvent setter will check to see if the handler has
            //  already been created and refuse an update if so. 
            // triggerBase.Seal(); 

            EventTrigger eventTrigger = triggerBase as EventTrigger; 
            if( eventTrigger != null )
            {
                Debug.Assert( eventTrigger._routedEventHandler == null && eventTrigger._source == null);
 
                // PERF: Cache this result if it turns out we're doing a lot of lookups on the same name.
                eventTrigger._source = FrameworkElement.FindNamedFrameworkElement( triggersHost, eventTrigger.SourceName ); 
 
                // Create a statefull event delegate (which keeps a ref to the FE).
                EventTriggerSourceListener listener = new EventTriggerSourceListener( eventTrigger, triggersHost ); 


                // Store the RoutedEventHandler & target for use in DisconnectOneTrigger
                eventTrigger._routedEventHandler = new RoutedEventHandler(listener.Handler); 
                eventTrigger._source.AddHandler( eventTrigger.RoutedEvent, eventTrigger._routedEventHandler,
                                                 false /* HandledEventsToo */ ); 
            } 
            else
            { 
                throw new InvalidOperationException(SR.Get(SRID.TriggersSupportsEventTriggersOnly));
            }
        }
 
        ////////////////////////////////////////////////////////////////////////
        // 
        // DisconnectAllTriggers 
        //
        // Call DisconnectOneTrigger for each trigger in the Triggers collection. 

        internal static void DisconnectAllTriggers( FrameworkElement triggersHost )
        {
            TriggerCollection triggerCollection = TriggerCollectionField.GetValue(triggersHost); 

            if( triggerCollection != null ) 
            { 
                for( int i = 0; i < triggerCollection.Count; i++ )
                { 
                    DisconnectOneTrigger( triggersHost, triggerCollection[i] );
                }

            } 
        }
 
        //////////////////////////////////////////////////////////////////////// 
        //
        // DisconnectOneTrigger 
        //
        // In ProcessOneTrigger, we connect an event trigger to the element
        // which it targets.  Here, we remove the event listener to clean up.
 
        internal static void DisconnectOneTrigger( FrameworkElement triggersHost, TriggerBase triggerBase )
        { 
            EventTrigger eventTrigger = triggerBase as EventTrigger; 

            if( eventTrigger != null ) 
            {
                eventTrigger._source.RemoveHandler( eventTrigger.RoutedEvent, eventTrigger._routedEventHandler);
                eventTrigger._routedEventHandler = null;
            } 
            else
            { 
                throw new InvalidOperationException(SR.Get(SRID.TriggersSupportsEventTriggersOnly)); 
            }
        } 



        internal class EventTriggerSourceListener 
        {
            internal EventTriggerSourceListener( EventTrigger trigger, FrameworkElement host ) 
            { 
                _owningTrigger = trigger;
                _owningTriggerHost = host; 
            }

            internal void Handler(object sender, RoutedEventArgs e)
            { 
                // Invoke all actions of the associated EventTrigger object.
                TriggerActionCollection actions = _owningTrigger.Actions; 
                for( int j = 0; j < actions.Count; j++ ) 
                {
                    actions[j].Invoke(_owningTriggerHost); 
                }
            }

            private EventTrigger     _owningTrigger; 
            private FrameworkElement _owningTriggerHost;
        } 
 
    }
} 

// 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