CacheRequest.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / AccessibleTech / longhorn / Automation / UIAutomationClient / System / Windows / Automation / CacheRequest.cs / 1 / CacheRequest.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Class that describes the data to be pre-fected in Automation 
//              element operations, and manange the current request.
// 
// History:
//  02/05/2004 : [....] Ported to WCP
//
//--------------------------------------------------------------------------- 

using System; 
using System.Collections; 
using System.Diagnostics;
using System.Windows.Automation; 
using MS.Internal.Automation;

namespace System.Windows.Automation
{ 
    /// 
    /// Specified type of reference to use when returning AutomationElements 
    ///  
    /// 
    /// AutomationElementMode.Full is the default, and specified that returned AutomationElements 
    /// contain a full reference to the underlying UI.
    ///
    /// AutomationElementMode.None specifies taht the returned AutomationElements have no
    /// reference to the underlying UI, and contain only cached information. 
    ///
    /// Certain operations on AutomationElements, such as GetCurrentProperty 
    /// or SetFocus require a full reference; attempting to perform these on an 
    /// AutomationElement that has AutomationElementMode.None will result in an
    /// InvalidOperationException being thrown. 
    ///
    /// Using AutomationElementMode.None can be more efficient when only properties are needed,
    /// as it avoids the overhead involved in setting up full references.
    ///  
#if (INTERNAL_COMPILE)
    internal enum AutomationElementMode 
#else 
    public enum AutomationElementMode
#endif 
    {
        /// 
        /// Specifies that returned AutomationElements have no reference to the
        /// underlying UI, and contain only cached information. 
        /// 
        None, 
 
        /// 
        /// Specifies that returned AutomationElements have a full reference to the 
        /// underlying UI.
        /// 
        Full
    } 

    // Implementation notes: 
    // 
    // CacheRequest is the user-facing class that is used to build up
    // cache requests, using Add and the other properties. When activated, 
    // the data is gathered into a UiaCacheRequest instance, which is
    // immutable - these are what the rest of UIA uses internally.
    //
    // The default cache request - which appears to be always at the bottom 
    // of the stack and which cannot be moved - is not actually part of the
    // stack. Instead, current returns it whever the stack is empty. 
 
    /// 
    /// Class used to specify the properties and patterns that should be 
    /// prefetched by UIAutomation when returning AutomationElements.
    /// 
#if (INTERNAL_COMPILE)
    internal sealed class CacheRequest 
#else
    public sealed class CacheRequest 
#endif 
    {
        //----------------------------------------------------- 
        //
        //  Constructors
        //
        //----------------------------------------------------- 

        #region Constructors 
 
        /// 
        /// Create a new CacheRequest with default values. 
        /// 
        /// 
        /// A Thread's current CacheRequest determins which properties,
        /// patterns and relative elements - if any - are pre-fetched by 
        /// AutomationElement.
        /// 
        /// A default cache request works on the Control view of the tree, 
        /// and does not prefetch any properties or patterns.
        /// 
        /// Use .Push or .Activate to make the CacheRequest the current active
        /// CacheRequest for the current thread.
        /// 
        public CacheRequest() 
        {
            _instanceLock = new object(); 
 
            _viewCondition = Automation.ControlViewCondition;
            _scope = TreeScope.Element; 
            _properties = new ArrayList();
            _patterns = new ArrayList();
            _automationElementMode = AutomationElementMode.Full;
 
            // We always want RuntimeID to be available...
            _properties.Add(AutomationElement.RuntimeIdProperty); 
            _uiaCacheRequest = DefaultUiaCacheRequest; 
        }
 
        // Private ctor used by Clone()
        private CacheRequest( Condition viewCondition,
                              TreeScope scope,
                              ArrayList properties, 
                              ArrayList patterns,
                              AutomationElementMode automationElementMode, 
                              UiaCoreApi.UiaCacheRequest uiaCacheRequest) 
        {
            _instanceLock = new object(); 

            _viewCondition = viewCondition;
            _scope = scope;
            _properties = properties; 
            _patterns = patterns;
            _automationElementMode = automationElementMode; 
            _uiaCacheRequest = uiaCacheRequest; 
        }
        #endregion Constructors 


        //------------------------------------------------------
        // 
        //  Public Methods
        // 
        //----------------------------------------------------- 

        #region Public Methods 

        /// 
        /// Push this CacheRequest onto this thread's stack of CacheRequests,
        /// making it the current CacheRequest for this thread. 
        /// 
        ///  
        /// Use Pop to remove this CacheRequest from the stack, making the previously 
        /// active CacheRequest active again. CacheRequests can be pushed multiple times,
        /// and on multiple threads; but for each thread, must be popped off in the 
        /// same order as they were pushed.
        ///
        /// A CacheRequest cannot be modified while it is pushed on any thread; attempting
        /// to modify it will generate an InvalidOperationException. 
        /// 
        public void Push() 
        { 
            // pushing multiple times is legal,
            // and pushing on different threads is also legal, 
            // so no preconditions to check for here.

            AutomationProperty[] propertyArray = (AutomationProperty[])_properties.ToArray(typeof(AutomationProperty));
            AutomationPattern[] patternArray = (AutomationPattern[])_patterns.ToArray(typeof(AutomationPattern)); 

            // _threadStack is thread local storage (TLS) based, so can be 
            // accessed outside of the lock. 
            if (_threadStack == null)
            { 
                _threadStack = new Stack();
            }

            _threadStack.Push(this); 

            lock (_instanceLock) 
            { 
                _refCount++;
 
                // Generate a new UiaCacheRequest
                if (_uiaCacheRequest == null)
                {
                    _uiaCacheRequest = new UiaCoreApi.UiaCacheRequest(_viewCondition, _scope, propertyArray, patternArray, _automationElementMode); 
                }
            } 
        } 

        ///  
        /// Pop this CacheRequest from the current thread's stack of CacheRequests,
        /// restoring the previously active CacheRequest.
        /// 
        ///  
        /// Only the currently active CacheRequest can be popped, attempting to pop
        /// a CacheRequest which is not the current one will result in an InvalidOperation 
        /// Exception. 
        ///
        /// The CacheRequest stack initially contains a default CacheRequest, which 
        /// cannot be popped off the stack.
        /// 
        public void Pop()
        { 
            // ensure that this is top of stack
            // (no lock needed here, since this is per-thread state) 
            if (_threadStack == null || _threadStack.Count == 0 || _threadStack.Peek() != this) 
            {
                throw new InvalidOperationException(SR.Get(SRID.CacheReqestCanOnlyPopTop)); 
            }

            _threadStack.Pop();
 
            lock (_instanceLock)
            { 
                _refCount--; 
            }
        } 

        /// 
        /// Make this the currenly active CacheRequest.
        ///  
        /// 
        /// Returns an IDisposable which should be disposed 
        /// when finished using this CacheRequest to deactivate it. 
        /// This method is designed for use within a 'using' clause.
        ///  
        public IDisposable Activate()
        {
            Push();
            return new CacheRequestActivation(this); 
        }
 
        ///  
        /// Clone this CacheRequest
        ///  
        /// 
        /// The returned CacheRequest contains the same request information, but is not
        /// pushed on the state of any thread.
        ///  
        public CacheRequest Clone()
        { 
            // New copy contains only temp state, not any locking state (_refCount) 
            return new CacheRequest(_viewCondition, _scope, (ArrayList)_properties.Clone(), (ArrayList)_patterns.Clone(), _automationElementMode, _uiaCacheRequest);
        } 

        /// 
        /// Add an AutomationProperty to this CacheRequest
        ///  
        /// The identifier of the property to add to this CacheRequest
        public void Add(AutomationProperty property) 
        { 
            Misc.ValidateArgumentNonNull(property, "property");
            lock (_instanceLock) 
            {
                CheckAccess();
                if (!_properties.Contains(property))
                { 
                    _properties.Add(property);
                    Invalidate(); 
                } 
            }
        } 

        /// 
        /// Add an AutomationPattern to this CacheRequest
        ///  
        /// The identifier of the pattern to add to this CacheRequest
        public void Add(AutomationPattern pattern) 
        { 
            Misc.ValidateArgumentNonNull(pattern, "pattern");
            lock (_instanceLock) 
            {
                CheckAccess();
                if (!_patterns.Contains(pattern))
                { 
                    _patterns.Add(pattern);
                    Invalidate(); 
                } 
            }
        } 

        #endregion Public Methods

 
        //------------------------------------------------------
        // 
        //  Public Properties 
        //
        //------------------------------------------------------ 

        #region Public Properties

        ///  
        /// Indicate which nodes should be pre-fetched
        ///  
        ///  
        /// At least one or more of of TreeScope.Element, TreeScope.Children or
        /// TreeScope.Descendants must be specified. 
        ///
        /// TreeScope.Parent and TreeScope.Ancestors are not supported.
        /// 
        public TreeScope TreeScope 
        {
            get 
            { 
                return _scope;
            } 

            set
            {
                if (value == 0) 
                {
                    throw new ArgumentException(SR.Get(SRID.TreeScopeNeedAtLeastOne)); 
                } 

                if ((value & ~(TreeScope.Element | TreeScope.Children | TreeScope.Descendants)) != 0) 
                {
                    throw new ArgumentException(SR.Get(SRID.TreeScopeElementChildrenDescendantsOnly));
                }
 
                lock (_instanceLock)
                { 
                    CheckAccess(); 
                    if (_scope != value)
                    { 
                        _scope = value;
                        Invalidate();
                    }
                } 
            }
        } 
 

        ///  
        /// Indicates the view to use when prefetching relative nodes
        /// 
        /// Defaults to Automation.ControlViewCondition
        public Condition TreeFilter 
        {
            get 
            { 
                return _viewCondition;
            } 

            set
            {
                Misc.ValidateArgumentNonNull(value, "TreeFilter"); 
                lock (_instanceLock)
                { 
                    CheckAccess(); 
                    if (_viewCondition != value)
                    { 
                        _viewCondition = value;
                        Invalidate();
                    }
                } 
            }
        } 
 
        /// 
        /// Specifies whether returned AutomationElements should contain 
        /// full references to the underlying UI, or only cached information.
        /// 
        public AutomationElementMode AutomationElementMode
        { 
            get
            { 
                return _automationElementMode; 
            }
 
            set
            {
                lock (_instanceLock)
                { 
                    CheckAccess();
                    if (_automationElementMode != value) 
                    { 
                        _automationElementMode = value;
                        Invalidate(); 
                    }
                }
            }
        } 

 
        ///  
        /// Return the most recent CacheRequest which has been activated
        /// by teh calling thread. 
        /// 
        public static CacheRequest Current
        {
            get 
            {
                if ( _threadStack == null || _threadStack.Count == 0 ) 
                    return DefaultCacheRequest; 

                return (CacheRequest)_threadStack.Peek(); 
            }
        }

 
        #endregion Public Properties
 
 
        //-----------------------------------------------------
        // 
        //  Internal Properties
        //
        //------------------------------------------------------
 
        #region Internal Properties
 
        internal static UiaCoreApi.UiaCacheRequest DefaultUiaCacheRequest 
        {
            get 
            {
                if(_defaultUiaCacheRequest == null)
                {
                    _defaultUiaCacheRequest = new UiaCoreApi.UiaCacheRequest(Automation.ControlViewCondition, TreeScope.Element, new AutomationProperty[] { AutomationElement.RuntimeIdProperty }, new AutomationPattern[] { }, AutomationElementMode.Full); 
                }
                return _defaultUiaCacheRequest; 
            } 
        }
 
        #endregion Internal Properties

        //-----------------------------------------------------
        // 
        //  Internal Methods
        // 
        //----------------------------------------------------- 

        #region Internal Methods 

        internal UiaCoreApi.UiaCacheRequest GetUiaCacheRequest()
        {
            if (_uiaCacheRequest == null) 
            {
                AutomationProperty[] propertiesArray = (AutomationProperty[])_properties.ToArray(typeof(AutomationProperty)); 
                AutomationPattern[] patternsArray = (AutomationPattern[])_patterns.ToArray(typeof(AutomationPattern)); 
                lock (_instanceLock)
                { 
                    _uiaCacheRequest = new UiaCoreApi.UiaCacheRequest(_viewCondition, _scope, propertiesArray, patternsArray, _automationElementMode);
                }
            }
 
            return _uiaCacheRequest;
        } 
 
        static internal UiaCoreApi.UiaCacheRequest CurrentUiaCacheRequest
        { 
            get
            {
                // No need to lock here, since this only uses thread state,
                // and the UiaCacheRequests are generated within a lock in Push. 
                CacheRequest current = Current;
                return current._uiaCacheRequest; 
            } 
        }
 
        #endregion Internal Methods

        //-----------------------------------------------------
        // 
        //  Private Methods
        // 
        //------------------------------------------------------ 

        #region Private Methods 

        // Ensure that this CacheRequest isn't currently in use
        // Must be called within a lock(_instanceLock) to ensure
        // thread consistency 
        void CheckAccess()
        { 
            // Make sure this isn't being used by any thread's 
            // CacheRequest stacks by using a refcount:
            // (Also check for defaultCacheRequest explicitly, since it 
            // is never explicitly added to the stack)
            if (_refCount != 0 || this == DefaultCacheRequest)
            {
                throw new InvalidOperationException(SR.Get(SRID.CacheReqestCantModifyWhileActive)); 
            }
        } 
 
        // Called when state changes - sets _uiaCacheRequest to null
        // to ensure that a clean one is generated next time Push is called 
        void Invalidate()
        {
            _uiaCacheRequest = null;
        } 

        #endregion Private Methods 
 

        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //------------------------------------------------------ 

        #region Private Fields 
 
        //--- Instance state ---
 
        // Current mutable state...
        Condition _viewCondition;
        TreeScope _scope;
        ArrayList _properties; 
        ArrayList _patterns;
        AutomationElementMode _automationElementMode; 
 
        // When we Push, the current state is bundled into this, which is
        // immutable. This is what the underlying requesting mechanism uses 
        UiaCoreApi.UiaCacheRequest _uiaCacheRequest;

        // Used to track whether this instance is in use - inc'd on Push,
        // dec'd on Pop... 
        int _refCount = 0;
 
        // Used to lock on this instance... 
        object _instanceLock = null;
 
        //--- Per-Thread state ---

        // The stack of CacheRequests for this thread. Note that these need to be inited
        // on-demand, as static initialization does not work with [ThreadStatic] members - 
        // it only applies to the first thread. Treat null as being the same as a stack with
        // just DefaultCacheRequest on it. 
        [ThreadStatic] 
        private static Stack _threadStack;
 
        //--- Global/Static state ---

        internal static readonly CacheRequest DefaultCacheRequest = new CacheRequest();
 
        internal static UiaCoreApi.UiaCacheRequest _defaultUiaCacheRequest;
 
        #endregion Private Fields 
    }
 
    //------------------------------------------------------
    //
    //  Related utility classe
    // 
    //-----------------------------------------------------
 
    // Helper class returned by Access() - a using() block 
    // will call Dispose() on this when it goes out of scope.
    internal class CacheRequestActivation : IDisposable 
    {
        internal CacheRequestActivation(CacheRequest request)
        {
            _request = request; 
        }
 
        public void Dispose() 
        {
            Debug.Assert( _request != null ); 

            if( _request != null )
            {
                _request.Pop(); 
                _request = null;
            } 
        } 

        // No finalizer - usually Dispose is used with a finalizer, 
        // but in this case, IDisposable is being used to manage scoping,
        // not ensure that resources are freed.

        private CacheRequest _request; 
    }
} 

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