|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Security;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Collections.Generic;
using MS.Internal;
using SR=MS.Internal.PresentationCore.SR;
using System.Windows.Automation;
using System.Windows.Automation.Provider;
using MS.Internal.Automation;
namespace System.Windows.Automation.Peers
{
///
public class UIElement3DAutomationPeer: AutomationPeer
{
///
public UIElement3DAutomationPeer(UIElement3D owner)
{
ArgumentNullException.ThrowIfNull(owner);
_owner = owner;
}
///
public UIElement3D Owner
{
get
{
return _owner;
}
}
///<summary>
/// This static helper creates an AutomationPeer for the specified element and
/// caches it - that means the created peer is going to live long and shadow the
/// element for its lifetime. The peer will be used by Automation to proxy the element, and
/// to fire events to the Automation when something happens with the element.
/// The created peer is returned from this method and also from subsequent calls to this method
/// and <seealso cref="FromElement"/>. The type of the peer is determined by the
/// <seealso cref="UIElement3D.OnCreateAutomationPeer"/> virtual callback. If UIElement3D does not
/// implement the callback, there will be no peer and this method will return 'null' (in other
/// words, there is no such thing as a 'default peer').
///</summary>
public static AutomationPeer CreatePeerForElement(UIElement3D element)
{
ArgumentNullException.ThrowIfNull(element);
return element.CreateAutomationPeer();
}
///
public static AutomationPeer FromElement(UIElement3D element)
{
ArgumentNullException.ThrowIfNull(element);
return element.GetAutomationPeer();
}
///
override protected List<AutomationPeer> GetChildrenCore()
{
List<AutomationPeer> children = null;
iterate(_owner,
(IteratorCallback)delegate(AutomationPeer peer)
{
if (children == null)
children = new List<AutomationPeer>();
children.Add(peer);
return (false);
});
return children;
}
private delegate bool IteratorCallback(AutomationPeer peer);
//
private static bool iterate(DependencyObject parent, IteratorCallback callback)
{
bool done = false;
if(parent != null)
{
AutomationPeer peer = null;
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count && !done; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if( child != null
&& child is UIElement
&& (peer = UIElementAutomationPeer.CreatePeerForElement((UIElement)child)) != null )
{
done = callback(peer);
}
else if ( child != null
&& child is UIElement3D
&& (peer = CreatePeerForElement(((UIElement3D)child))) != null )
{
done = callback(peer);
}
else
{
done = iterate(child, callback);
}
}
}
return done;
}
///
override public object GetPattern(PatternInterface patternInterface)
{
//Support synchronized input
if (patternInterface == PatternInterface.SynchronizedInput)
{
// Adaptor object is used here to avoid loading UIA assemblies in non-UIA scenarios.
if (_synchronizedInputPattern == null)
_synchronizedInputPattern = new SynchronizedInputAdaptor(_owner);
return _synchronizedInputPattern;
}
return null;
}
//
// P R O P E R T I E S
//
///
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
///
protected override string GetAutomationIdCore()
{
return (AutomationProperties.GetAutomationId(_owner));
}
///
protected override string GetNameCore()
{
return (AutomationProperties.GetName(_owner));
}
///
protected override string GetHelpTextCore()
{
return (AutomationProperties.GetHelpText(_owner));
}
/// <summary>
/// <see cref="AutomationPeer.GetBoundingRectangleCore"/>
/// </summary>
override protected Rect GetBoundingRectangleCore()
{
Rect rectScreen;
if (!ComputeBoundingRectangle(out rectScreen))
{
rectScreen = Rect.Empty;
}
return rectScreen;
}
///
private bool ComputeBoundingRectangle(out Rect rect)
{
rect = Rect.Empty;
PresentationSource presentationSource = PresentationSource.CriticalFromVisual(_owner);
// If there's no source, the element is not visible, return empty rect
if(presentationSource == null)
return false;
HwndSource hwndSource = presentationSource as HwndSource;
// If the source isn't an HwndSource, there's not much we can do, return empty rect
if(hwndSource == null)
return false;
Rect rectElement = _owner.Visual2DContentBounds;
// we use VisualTreeHelper.GetContainingVisual2D to transform from the containing Viewport3DVisual
Rect rectRoot = PointUtil.ElementToRoot(rectElement, VisualTreeHelper.GetContainingVisual2D(_owner), presentationSource);
Rect rectClient = PointUtil.RootToClient(rectRoot, presentationSource);
rect = PointUtil.ClientToScreen(rectClient, hwndSource);
return true;
}
///
override protected bool IsOffscreenCore()
{
IsOffscreenBehavior behavior = AutomationProperties.GetIsOffscreenBehavior(_owner);
switch (behavior)
{
case IsOffscreenBehavior.Onscreen :
return false;
case IsOffscreenBehavior.Offscreen :
return true;
case IsOffscreenBehavior.FromClip:
{
bool isOffscreen = !_owner.IsVisible;
if (!isOffscreen)
{
UIElement containingUIElement = GetContainingUIElement(_owner);
if (containingUIElement != null)
{
Rect boundingRect = UIElementAutomationPeer.CalculateVisibleBoundingRect(containingUIElement);
isOffscreen = (DoubleUtil.AreClose(boundingRect, Rect.Empty) ||
DoubleUtil.AreClose(boundingRect.Height, 0) ||
DoubleUtil.AreClose(boundingRect.Width, 0));
}
}
return isOffscreen;
}
default :
return !_owner.IsVisible;
}
}
/// <summary>
/// Returns the closest UIElement that contains the given DependencyObject
/// </summary>
private static UIElement GetContainingUIElement(DependencyObject reference)
{
UIElement element = null;
while (reference != null)
{
element = reference as UIElement;
if (element != null) break;
reference = VisualTreeHelper.GetParent(reference);
}
return element;
}
///
override protected AutomationOrientation GetOrientationCore()
{
return (AutomationOrientation.None);
}
///
override protected string GetItemTypeCore()
{
return AutomationProperties.GetItemType(_owner);
}
///
override protected string GetClassNameCore()
{
return string.Empty;
}
///
override protected string GetItemStatusCore()
{
return AutomationProperties.GetItemStatus(_owner);
}
///
override protected bool IsRequiredForFormCore()
{
return AutomationProperties.GetIsRequiredForForm(_owner);
}
///
override protected bool IsKeyboardFocusableCore()
{
return Keyboard.IsFocusable(_owner);
}
///
override protected bool HasKeyboardFocusCore()
{
return _owner.IsKeyboardFocused;
}
///
override protected bool IsEnabledCore()
{
return _owner.IsEnabled;
}
///
override protected bool IsDialogCore()
{
return AutomationProperties.GetIsDialog(_owner);
}
///
override protected bool IsPasswordCore()
{
return false;
}
///
override protected bool IsContentElementCore()
{
return true;
}
///
override protected bool IsControlElementCore()
{
// We only want this peer to show up in the Control view if it is visible
// For compat we allow falling back to legacy behavior (returning true always)
// based on AppContext flags, IncludeInvisibleElementsInControlView evaluates them.
return IncludeInvisibleElementsInControlView || _owner.IsVisible;
}
///
override protected AutomationPeer GetLabeledByCore()
{
UIElement element = AutomationProperties.GetLabeledBy(_owner);
if (element != null)
return element.GetAutomationPeer();
return null;
}
///
override protected string GetAcceleratorKeyCore()
{
return AutomationProperties.GetAcceleratorKey(_owner);
}
///
override protected string GetAccessKeyCore()
{
string result = AutomationProperties.GetAccessKey(_owner);
if (string.IsNullOrEmpty(result))
return AccessKeyManager.InternalGetAccessKeyCharacter(_owner);
return string.Empty;
}
override protected AutomationLiveSetting GetLiveSettingCore()
{
return AutomationProperties.GetLiveSetting(_owner);
}
/// <summary>
/// Provides a value for UIAutomation's PositionInSet property
/// Reads <see cref="AutomationProperties.PositionInSetProperty"/> and returns the value.
/// </summary>
override protected int GetPositionInSetCore()
{
return AutomationProperties.GetPositionInSet(_owner);
}
/// <summary>
/// Provides a value for UIAutomation's SizeOfSet property
/// Reads <see cref="AutomationProperties.SizeOfSetProperty"/> and returns the value.
/// </summary>
override protected int GetSizeOfSetCore()
{
return AutomationProperties.GetSizeOfSet(_owner);
}
/// <summary>
/// Provides a value for UIAutomation's HeadingLevel property
/// Reads <see cref="AutomationProperties.HeadingLevelProperty"/> and returns the value
/// </summary>
override protected AutomationHeadingLevel GetHeadingLevelCore()
{
return AutomationProperties.GetHeadingLevel(_owner);
}
//
// M E T H O D S
//
/// <summary>
/// <see cref="AutomationPeer.GetClickablePointCore"/>
/// </summary>
override protected Point GetClickablePointCore()
{
Rect rectScreen;
Point pt = new Point(double.NaN, double.NaN);
if (ComputeBoundingRectangle(out rectScreen))
{
pt = new Point(rectScreen.Left + rectScreen.Width * 0.5, rectScreen.Top + rectScreen.Height * 0.5);
}
return pt;
}
///
override protected void SetFocusCore()
{
if (!_owner.Focus())
throw new InvalidOperationException(SR.SetFocusFailed);
}
///
internal override Rect GetVisibleBoundingRectCore()
{
return GetBoundingRectangle();
}
private UIElement3D _owner;
private SynchronizedInputAdaptor _synchronizedInputPattern;
}
}
|