ItemsControlAutomationPeer.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 / Framework / System / Windows / Automation / Peers / ItemsControlAutomationPeer.cs / 1477467 / ItemsControlAutomationPeer.cs

                            using System; 
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Diagnostics; 
using System.Runtime.InteropServices;
using System.Security; 
using System.Text; 
using System.Windows;
using System.Windows.Automation.Provider; 
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Interop; 
using System.Windows.Media;
 
using MS.Internal; 
using MS.Internal.Automation;
using MS.Internal.Hashing.PresentationFramework;    // HashHelper 
using MS.Win32;

namespace System.Windows.Automation.Peers
{ 

    /// 
    public abstract class ItemsControlAutomationPeer : FrameworkElementAutomationPeer, IItemContainerProvider 
    {
        /// 
        protected ItemsControlAutomationPeer(ItemsControl owner): base(owner)
        {}

        /// 
        override public object GetPattern(PatternInterface patternInterface)
        { 
            if(patternInterface == PatternInterface.Scroll) 
            {
                ItemsControl owner = (ItemsControl)Owner; 
                if(owner.ScrollHost != null)
                {
                    AutomationPeer scrollPeer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost);
                    if(scrollPeer != null && scrollPeer is IScrollProvider) 
                    {
                        scrollPeer.EventsSource = this; 
                        return (IScrollProvider)scrollPeer; 
                    }
                } 
            }
            else if (patternInterface == PatternInterface.ItemContainer)
            {
                if(Owner as ItemsControl != null && (Owner as ItemsControl).IsGrouping == false) 
                    return this;
                return null; 
            } 

            return base.GetPattern(patternInterface); 
        }


        /// 
        /// If grouping is enabled then return peers corresponding to all the items in container
        /// otherwise sees VirtualizingStackPanel(itemsHost) and return peers corresponding to 
        /// items which are de-virtualized. 
        ///
        protected override List GetChildrenCore() 
        {
            List children = null;
            ItemPeersStorage oldChildren = _dataChildren; //cache the old ones for possible reuse
            _dataChildren = new ItemPeersStorage(); 
            ItemsControl owner = (ItemsControl)Owner;
            ItemCollection items = owner.Items; 
 
            if (owner.IsGrouping)
            { 
                CollectionView cv = owner.Items.CollectionView;
                ReadOnlyObservableCollection groups = (cv != null) ? cv.Groups : null;
                if (groups != null)
                { 
                    children = new List(groups.Count);
                    for (int i = 0; i < groups.Count; i++) 
                    { 
                        object group = groups[i];
                        GroupItem groupItem = owner.ItemContainerGenerator.ContainerFromItem(group) as GroupItem; 
                        if (groupItem != null)
                        {
                            GroupItemAutomationPeer peer = groupItem.CreateAutomationPeer() as GroupItemAutomationPeer;
                            if (peer != null) 
                                children.Add(peer);
                        } 
                    } 
                    return children;
                } 
                return base.GetChildrenCore();

            }
 
            else if (items.Count > 0)
            { 
                IList childItems = null; 
                Panel itemHost = owner.ItemsHost;
 
                // To avoid the situation on legacy systems which may not have new unmanaged core. this check with old unmanaged core
                // ensures the older behavior as ItemContainer pattern won't be available.
                if (ItemContainerPatternIdentifiers.Pattern != null)
                { 
                    if (itemHost == null)
                        return null; 
 
                    childItems = itemHost.Children;
                } 
                else
                {
                    childItems = items;
                } 
                children = new List(childItems.Count);
 
                foreach (object item in childItems) 
                {
 	                object dataItem = ((ItemContainerPatternIdentifiers.Pattern != null && ((MS.Internal.Controls.IGeneratorHost)owner).IsItemItsOwnContainer(item)) ? owner.GetItemOrContainerFromContainer(item as UIElement) : item); 

                    // try to reuse old peer if it exists either in Current AT or in WeakRefStorage of Peers being sent to Client
                    ItemAutomationPeer peer = oldChildren[dataItem];
                    if (peer == null) 
                    {
                        peer = GetPeerFromWeakRefStorage(dataItem); 
                        if (peer != null) 
                        {
                            // As cached peer is getting used it must be invalidated. 
                            peer.AncestorsInvalid = false;
                            peer.ChildrenValid = false;
                        }
                    } 

                    if (peer == null) 
                    { 
                        peer = CreateItemAutomationPeer(dataItem);
                    } 

                    // perform hookup so the events sourced from wrapper peer are fired as if from the data item
                    if (peer != null)
                    { 
                        AutomationPeer wrapperPeer = peer.GetWrapperPeer();
                        if (wrapperPeer != null) 
                        { 
                            wrapperPeer.EventsSource = peer;
                        } 
                    }

                    // protection from indistinguishable items - for example, 2 strings with same value
                    // this scenario does not work in ItemsControl however is not checked for. 
                    if (_dataChildren[dataItem] == null)
                    { 
                        children.Add(peer); 
                        _dataChildren[dataItem] = peer;
                    } 
                }

                return children;
            } 

            return null; 
        } 

 

        internal void AddProxyToWeakRefStorage(WeakReference wr, ItemAutomationPeer itemPeer)
        {
            ItemsControl owner = this.Owner as ItemsControl; 
            ItemCollection items = owner.Items;
            if(items != null) 
            { 
                if(GetPeerFromWeakRefStorage(itemPeer.Item) == null)
                    WeakRefElementProxyStorage[itemPeer.Item] = wr; 
            }
        }

        /// 
        IRawElementProviderSimple IItemContainerProvider.FindItemByProperty(IRawElementProviderSimple startAfter, int propertyId, object value)
        { 
            ResetChildrenCache(); 
            // Checks if propertyId is valid else throws ArgumentException to notify it as invalid argument is being passed
            if (propertyId != 0) 
            {
                if (!IsPropertySupportedByControlForFindItem(propertyId))
                {
                    throw new ArgumentException(SR.Get(SRID.PropertyNotSupported)); 
                }
            } 
 
            ItemsControl owner = (ItemsControl)Owner;
 
            ItemCollection items = null;
            if(owner != null)
                items = owner.Items;
 
            if (items != null && items.Count > 0)
            { 
                ItemAutomationPeer startAfterItem = null; 
                if (startAfter != null)
                { 
                    // get the peer corresponding to this provider
                    startAfterItem = PeerFromProvider(startAfter) as ItemAutomationPeer;
                    if(startAfterItem == null)
                        return null; 
                }
 
                // startIndex refers to the index of the item just after startAfterItem 
                int startIndex = 0;
                if (startAfterItem != null) 
                {
                    if (startAfterItem.Item == null)
                    {
                        throw new InvalidOperationException(SR.Get(SRID.InavalidStartItem)); 
                    }
 
                    // To find the index of the item in items collection which occurs 
                    // immidiately after startAfterItem.Item
                    startIndex = items.IndexOf(startAfterItem.Item)+ 1; 
                    if (startIndex == 0 || startIndex == items.Count)
                        return null;
                }
 
                if (propertyId == 0)
                { 
                    for (int i = startIndex; i < items.Count; i++) 
                    {
                        // This is to handle the case of when dataItems are just plain strings and have duplicates, 
                        // only the first occurence of duplicate Items will be returned. It has also been used couple more times below.
                        if (items.IndexOf(items[i]) != i)
                            continue;
                        return (ProviderFromPeer(FindOrCreateItemAutomationPeer(items[i]))); 
                    }
                } 
 
                ItemAutomationPeer currentItemPeer;
                object currentValue = null; 
                for (int i = startIndex; i < items.Count; i++)
                {
                    currentItemPeer = FindOrCreateItemAutomationPeer(items[i]);
                    if (currentItemPeer == null) 
                        continue;
                    try{ 
                        currentValue = GetSupportedPropertyValue(currentItemPeer, propertyId); 
                        }
                    catch(Exception ex) 
                    {
                        if(ex is ElementNotAvailableException)
                            continue;
                    } 

                    if (value == null || currentValue == null) 
                    { 
                        // Accept null as value corresponding to the property if it finds an item with null as the value of corresponding property else ignore.
                        if (currentValue == null && value == null && items.IndexOf(items[i]) == i) 
                            return (ProviderFromPeer(currentItemPeer));
                        else
                            continue;
                    } 

                    // Match is found within the specified criterion of search 
                    if (value.Equals(currentValue) && items.IndexOf(items[i]) == i) 
                        return (ProviderFromPeer(currentItemPeer));
                } 
            }
            return null;
        }
 
        /// 
        /// Verifies whether the propertyId is supported by find criterion. It can be overriden by derived classes 
        /// if they wish to support more properties. 
        /// 
        /// Property Id to be verified 
        /// true if property id is supported else false
        virtual internal bool IsPropertySupportedByControlForFindItem(int id)
        {
            return ItemsControlAutomationPeer.IsPropertySupportedByControlForFindItemInternal(id); 
        }
 
        internal static bool IsPropertySupportedByControlForFindItemInternal(int id) 
        {
            if (AutomationElementIdentifiers.NameProperty.Id == id) 
                return true;
            else if (AutomationElementIdentifiers.AutomationIdProperty.Id == id)
                return true;
            else if (AutomationElementIdentifiers.ControlTypeProperty.Id == id) 
                return true;
            else 
                return false; 
        }
 
        /// 
        /// This method is responsible for providing the value corresponding to the propertyId for itemPeer
        /// This method can be overriden by derived classes if they support more properties for search.
        ///  
        /// 
        ///  
        /// returns the property value 
        virtual internal object GetSupportedPropertyValue(ItemAutomationPeer itemPeer, int propertyId)
        { 
            return ItemsControlAutomationPeer.GetSupportedPropertyValueInternal(itemPeer, propertyId);
        }

        internal static object GetSupportedPropertyValueInternal(AutomationPeer itemPeer, int propertyId) 
        {
            return itemPeer.GetPropertyValue(propertyId); 
        } 

        ///  
        /// It returns the ItemAutomationPeer if it exist corresponding to the item otherwise it creates
        /// one and does add the Handle and parent info by calling TrySetParentInfo.
        /// 
        ///  
        /// Security Critical - Calls a Security Critical operation TrySetParentInfo which adds parent peer and provides
        ///                     security critical Hwnd value for this peer created asynchronously. 
        /// SecurityTreatAsSafe - It's being called from this object which is real parent for the item peer. 
        /// 
        ///  
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        virtual internal ItemAutomationPeer FindOrCreateItemAutomationPeer(object item)
        { 
            ItemAutomationPeer peer = ItemPeers[item];
            if (peer == null) 
                peer = GetPeerFromWeakRefStorage(item); 

            if (peer == null) 
            {
                peer = CreateItemAutomationPeer(item);
                if (peer != null)
                { 
                    peer.TrySetParentInfo(this);
                    //perform hookup so the events sourced from wrapper peer are fired as if from the data item 
                    AutomationPeer wrapperPeer = peer.GetWrapperPeer(); 
                    if (wrapperPeer != null)
                    { 
                        wrapperPeer.EventsSource = peer;
                    }
                }
            } 

            return peer; 
        } 

        // Called by GroupItemAutomationPeer 
        internal ItemAutomationPeer CreateItemAutomationPeerInternal(object item)
        {
            return CreateItemAutomationPeer(item);
        } 

        /// 
        abstract protected ItemAutomationPeer CreateItemAutomationPeer(object item); 

 
        // UpdateChildrenIntenal is called with ItemsInvalidateLimit to ensure we don�t fire unnecessary structure change events when items are just scrolled in/out of view in case of
        // virtualized controls.
        override internal void UpdateChildren()
        { 
            UpdateChildrenInternal(AutomationInteropProvider.ItemsInvalidateLimit);
            WeakRefElementProxyStorage.PurgeWeakRefCollection(); 
        } 

        // Provides Peer if exist in Weak Reference Storage 
        internal ItemAutomationPeer GetPeerFromWeakRefStorage(object item)
        {
            ItemAutomationPeer returnPeer = null;
            WeakReference weakRefEP = WeakRefElementProxyStorage[item]; 
            if(weakRefEP != null)
            { 
                ElementProxy provider = weakRefEP.Target as ElementProxy; 
                if(provider != null)
                { 
                    returnPeer = PeerFromProvider(provider as IRawElementProviderSimple) as ItemAutomationPeer;
                    if(returnPeer == null)
                        WeakRefElementProxyStorage.Remove(item);
                } 
                else
                    WeakRefElementProxyStorage.Remove(item); 
 
            }
 
            return returnPeer;
        }

        // 
        internal AutomationPeer GetExistingPeerByItem(object item, bool checkInWeakRefStorage)
        { 
            AutomationPeer returnPeer = null; 
            if(checkInWeakRefStorage)
            { 
                returnPeer = GetPeerFromWeakRefStorage(item);
            }
            if(returnPeer == null)
            { 
                returnPeer = ItemPeers[item];
            } 
 
            return returnPeer;
        } 

        // Derived classes should be able to access peers cache
        internal ItemPeersStorage ItemPeers
        { 
            get { return _dataChildren; }
 
            set { _dataChildren = value; } 
        }
 
        internal ItemPeersStorage WeakRefElementProxyStorage
        {
            get { return _WeakRefElementProxyStorage; }
 
            set { _WeakRefElementProxyStorage = value; }
        } 
 
        private ItemPeersStorage _dataChildren = new ItemPeersStorage();
        private ItemPeersStorage _WeakRefElementProxyStorage = new ItemPeersStorage(); 
    }

    internal class ItemPeersStorage where T : class
    { 
        public ItemPeersStorage()
        { 
        } 

        public void Clear() 
        {
            _usesHashCode = false;
            _count = 0;
 
            if (_hashtable != null)
                _hashtable.Clear(); 
 
            if (_list != null)
                _list.Clear(); 
        }

        public T this[object item]
        { 
            get
            { 
                if (_count == 0 || item == null) 
                    return default(T);
 
                if (_usesHashCode)
                {
                    if (_hashtable == null)
                        return default(T); 

                    return _hashtable[item] as T; 
                } 
                else
                { 
                    if (_list == null)
                        return default(T);

                    for (int i = 0; i < _list.Count; i++) 
                    {
                        KeyValuePair pair = _list[i]; 
                        if (Object.Equals(item, pair.Key)) 
                            return pair.Value;
                    } 

                    return default(T);
                }
            } 
            set
            { 
                // Does not cache null items 
                if (item == null)
                    return; 

                // When we add the first item we need to determine whether to use hashtable or list
                if (_count == 0)
                { 
                    _usesHashCode = item != null && HashHelper.HasReliableHashCode(item);
                } 
 
                if (_usesHashCode)
                { 
                    if (_hashtable == null)
                        _hashtable = new Hashtable();

                    if(!_hashtable.Contains(item) && value is T) 
                        _hashtable[item] = value;
                    else 
                        Debug.Assert(false,"it must not add already present Item"); 

                } 
                else
                {
                    if (_list == null)
                        _list = new List>(); 
                    if(value is T)
                        _list.Add(new KeyValuePair(item, value)); 
                } 

                _count++; 
            }
        }

        public void Remove(object item) 
        {
            if(_usesHashCode) 
            { 
                if(item != null && _hashtable.Contains(item))
                { 
                    _hashtable.Remove(item);
                    if(!_hashtable.Contains(item))
                        _count--;
                } 
            }
            else 
            { 
                if (_list != null)
                { 
                    int i =0;
                    for (i = 0; i < _list.Count; i++)
                    {
                        KeyValuePair pair = _list[i]; 
                        if (Object.Equals(item, pair.Key))
                            break; 
                    } 
                    if(i < _list.Count)
                    { 
                        _list.RemoveAt(i);
                        _count--;
                    }
                } 
            }
        } 
 
        // To purge the collection corresponding to WeakReference for dead references
        // 
        public void PurgeWeakRefCollection()
        {
            if(!(typeof(T).IsAssignableFrom(typeof(System.WeakReference))))
                return; 
            List cleanUpItemsCollection = new List();
 
            if(_usesHashCode) 
            {
                if(_hashtable == null) 
                    return;
                foreach(DictionaryEntry dictionaryEntry in _hashtable)
                {
                    WeakReference weakRef = dictionaryEntry.Value as WeakReference; 
                    if(weakRef == null)
                    { 
                        cleanUpItemsCollection.Add(dictionaryEntry.Key); 
                        continue;
                    } 
                    ElementProxy proxy = weakRef.Target as ElementProxy;
                    if(proxy == null)
                    {
                        cleanUpItemsCollection.Add(dictionaryEntry.Key); 
                        continue;
                    } 
                    ItemAutomationPeer peer = proxy.Peer as ItemAutomationPeer; 
                    if(peer == null)
                        cleanUpItemsCollection.Add(dictionaryEntry.Key); 
                }
            }

            else 
            {
                if(_list == null) 
                    return; 
                foreach(KeyValuePair keyValuePair in _list)
                { 
                    WeakReference weakRef = keyValuePair.Value as WeakReference;
                    if(weakRef == null)
                    {
                        cleanUpItemsCollection.Add(keyValuePair.Key); 
                        continue;
                    } 
                    ElementProxy proxy = weakRef.Target as ElementProxy; 
                    if(proxy == null)
                    { 
                        cleanUpItemsCollection.Add(keyValuePair.Key);
                        continue;
                    }
                    ItemAutomationPeer peer = proxy.Peer as ItemAutomationPeer; 
                    if(peer == null)
                        cleanUpItemsCollection.Add(keyValuePair.Key); 
                } 
            }
 
            foreach(object item in cleanUpItemsCollection)
            {
                Remove(item);
            } 

        } 
 
        public int Count
        { 
            get { return _count; }
        }

        private Hashtable _hashtable = null; 
        private List> _list = null;
        private int _count = 0; 
        private bool _usesHashCode = false; 
    }
} 




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