| File: System\Windows\Automation\Peers\GroupItemAutomationPeer.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Windows.Automation.Provider; using System.Windows.Controls; using System.Windows.Data; using MS.Internal.Data; namespace System.Windows.Automation.Peers { /// public class GroupItemAutomationPeer : FrameworkElementAutomationPeer { /// public GroupItemAutomationPeer(GroupItem owner): base(owner) { } /// protected override string GetClassNameCore() { return "GroupItem"; } /// <summary> /// Gets the position of this GroupItem within a set. /// </summary> /// <remarks> /// Gets the CollectionViewGroupInternal linked to this groupItem via ItemForItemContainerProperty, /// this collection describes the elements belonging to this GroupItem, we need the collection this /// GroupItem belongs to, so we look one level up using Parent. /// </remarks> protected override int GetPositionInSetCore() { int positionInSet = base.GetPositionInSetCore(); if (positionInSet == AutomationProperties.AutomationPositionInSetDefault) { GroupItem groupItem = (GroupItem)Owner; CollectionViewGroupInternal group = groupItem.GetValue(ItemContainerGenerator.ItemForItemContainerProperty) as CollectionViewGroupInternal; if (group != null) { CollectionViewGroup parent = group.Parent; if (parent != null) { positionInSet = parent.Items.IndexOf(group) + 1; } } } return positionInSet; } /// <summary> /// Gets the size of a set that contains this GroupItem. /// </summary> /// <remarks> /// Gets the CollectionViewGroupInternal linked to this groupItem via ItemForItemContainerProperty, /// this collection describes the elements belonging to this GroupItem, we need the collection this /// GroupItem belongs to, so we look one level up using Parent. /// </remarks> protected override int GetSizeOfSetCore() { int sizeOfSet = base.GetSizeOfSetCore(); if (sizeOfSet == AutomationProperties.AutomationSizeOfSetDefault) { GroupItem groupItem = (GroupItem)Owner; CollectionViewGroupInternal group = groupItem.GetValue(ItemContainerGenerator.ItemForItemContainerProperty) as CollectionViewGroupInternal; if (group != null) { CollectionViewGroup parent = group.Parent; if (parent != null) { sizeOfSet = parent.Items.Count; } } } return sizeOfSet; } /// protected override AutomationControlType GetAutomationControlTypeCore() { return AutomationControlType.Group; } /// public override object GetPattern(PatternInterface patternInterface) { if(patternInterface == PatternInterface.ExpandCollapse) { GroupItem groupItem = (GroupItem)Owner; if(groupItem.Expander != null) { AutomationPeer expanderPeer = UIElementAutomationPeer.CreatePeerForElement(groupItem.Expander); if(expanderPeer != null && expanderPeer is IExpandCollapseProvider) { expanderPeer.EventsSource = this; return (IExpandCollapseProvider)expanderPeer; } } } return base.GetPattern(patternInterface); } /// protected override List<AutomationPeer> GetChildrenCore() { GroupItem owner = (GroupItem)Owner; ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(Owner); if (itemsControl != null) { ItemsControlAutomationPeer itemsControlAP = itemsControl.CreateAutomationPeer() as ItemsControlAutomationPeer; if (itemsControlAP != null) { List<AutomationPeer> children = new List<AutomationPeer>(); bool useNetFx472CompatibleAccessibilityFeatures = AccessibilitySwitches.UseNetFx472CompatibleAccessibilityFeatures; if (!useNetFx472CompatibleAccessibilityFeatures && owner.Expander != null) { _expanderPeer = UIElementAutomationPeer.CreatePeerForElement(owner.Expander); if (_expanderPeer != null) { _expanderPeer.EventsSource = this; // Call GetChildren so the Expander's toggle button updates its EventsSource as well _expanderPeer.GetChildren(); } } Panel itemsHost = owner.ItemsHost; if (itemsHost == null) { if (_expanderPeer == null) { return null; } else { children.Add(_expanderPeer); return children; } } IList childItems = itemsHost.Children; ItemPeersStorage<ItemAutomationPeer> addedChildren = new ItemPeersStorage<ItemAutomationPeer>(); foreach (UIElement child in childItems) { if (!((MS.Internal.Controls.IGeneratorHost)itemsControl).IsItemItsOwnContainer(child)) { UIElementAutomationPeer peer = child.CreateAutomationPeer() as UIElementAutomationPeer; if (peer != null) { children.Add(peer); if (useNetFx472CompatibleAccessibilityFeatures) { // // The AncestorsInvalid check is meant so that we do this call to invalidate the // GroupItemPeers containing the realized item peers only when we arrive here from an // UpdateSubtree call because that call does not otherwise descend into parts of the tree // that have their children invalid as an optimization. // if (itemsControlAP.RecentlyRealizedPeers.Count > 0 && this.AncestorsInvalid) { GroupItemAutomationPeer groupItemPeer = peer as GroupItemAutomationPeer; groupItemPeer?.InvalidateGroupItemPeersContainingRecentlyRealizedPeers(itemsControlAP.RecentlyRealizedPeers); } } else { // // The AncestorsInvalid check is meant so that we do this call to invalidate the // GroupItemPeers only when we arrive here from an // UpdateSubtree call because that call does not otherwise descend into parts of the tree // that have their children invalid as an optimization. // if (this.AncestorsInvalid) { GroupItemAutomationPeer groupItemPeer = peer as GroupItemAutomationPeer; if (groupItemPeer != null) { // invalidate all GroupItemAP children, so // that the top-level ItemsControlAP's // ItemPeers collection is repopulated. groupItemPeer.AncestorsInvalid = true; groupItemPeer.ChildrenValid = true; } } } } } else { object item = itemsControl.ItemContainerGenerator.ItemFromContainer(child); // ItemFromContainer can return {UnsetValue} if we're in a re-entrant // call while the generator is in the midst of unhooking the container. // Ignore such children. if (item == DependencyProperty.UnsetValue) { continue; } // try to reuse old peer if it exists either in Current AT or in WeakRefStorage of Peers being sent to Client ItemAutomationPeer peer = useNetFx472CompatibleAccessibilityFeatures ? itemsControlAP.ItemPeers[item] : itemsControlAP.ReusablePeerFor(item); peer = itemsControlAP.ReusePeerForItem(peer, item); if (peer != null) { if (useNetFx472CompatibleAccessibilityFeatures) { // // We have now connected the realized peer to its actual parent. Hence the cache can be cleared // int realizedPeerIndex = itemsControlAP.RecentlyRealizedPeers.IndexOf(peer); if (realizedPeerIndex >= 0) { itemsControlAP.RecentlyRealizedPeers.RemoveAt(realizedPeerIndex); } } } else { peer = itemsControlAP.CreateItemAutomationPeerInternal(item); } //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; if (peer.ChildrenValid && peer.Children == null && this.AncestorsInvalid) { peer.AncestorsInvalid = true; wrapperPeer.AncestorsInvalid = true; } } } //protection from indistinguishable items - for example, 2 strings with same value //this scenario does not work in ItemsControl however is not checked for. // Our parent's ItemPeerStorage collection may not have been cleared, // this would cause us to report 0 children, if the peer is already in the collection // check its parent, if it has been set to us, we should add it to the return collection, // but only if we haven't added a peer for this item during this GetChildrenCore call. bool itemMissingPeerInGlobalStorage = itemsControlAP.ItemPeers[item] == null; if (peer != null && (itemMissingPeerInGlobalStorage || (peer.GetParent() == this && addedChildren[item] == null))) { children.Add(peer); addedChildren[item] = peer; if (itemMissingPeerInGlobalStorage) { itemsControlAP.ItemPeers[item] = peer; } } } } return children; } } return null; } // *** DEAD CODE Only call is from dead code when UseNetFx472CompatibleAccessibilityFeatures==true *** internal void InvalidateGroupItemPeersContainingRecentlyRealizedPeers(List<ItemAutomationPeer> recentlyRealizedPeers) { ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(Owner); if (itemsControl != null) { CollectionViewGroupInternal cvg = itemsControl.ItemContainerGenerator.ItemFromContainer(Owner) as CollectionViewGroupInternal; if (cvg != null) { for (int i=0; i<recentlyRealizedPeers.Count; i++) { ItemAutomationPeer peer = recentlyRealizedPeers[i]; object item = peer.Item; if (cvg.LeafIndexOf(item) >= 0) { AncestorsInvalid = true; ChildrenValid = true; } } } } } protected override void SetFocusCore() { GroupItem owner = (GroupItem)Owner; if (!AccessibilitySwitches.UseNetFx472CompatibleAccessibilityFeatures && owner.Expander != null) { if (owner.Expander.ExpanderToggleButton?.Focus() != true) { throw new InvalidOperationException(SR.SetFocusFailed); } } else { base.SetFocusCore(); } } protected override bool IsKeyboardFocusableCore() { if (_expanderPeer != null) { return _expanderPeer.IsKeyboardFocusable(); } else { return base.IsKeyboardFocusableCore(); } } protected override bool HasKeyboardFocusCore() { if (_expanderPeer != null) { return _expanderPeer.HasKeyboardFocus(); } return base.HasKeyboardFocusCore(); } private AutomationPeer _expanderPeer = null; } }