76 changed files with 466 additions and 727 deletions
@ -0,0 +1,23 @@ |
|||
using System; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Automation |
|||
{ |
|||
public class AutomationPropertyChangedEventArgs : EventArgs |
|||
{ |
|||
public AutomationPropertyChangedEventArgs( |
|||
AutomationProperty property, |
|||
object? oldValue, |
|||
object? newValue) |
|||
{ |
|||
Property = property; |
|||
OldValue = oldValue; |
|||
NewValue = newValue; |
|||
} |
|||
|
|||
public AutomationProperty Property { get; } |
|||
public object? OldValue { get; } |
|||
public object? NewValue { get; } |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
using System; |
|||
using Avalonia.Automation.Peers; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Automation.Platform |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a platform implementation of a node in the UI Automation tree.
|
|||
/// </summary>
|
|||
public interface IAutomationNode |
|||
{ |
|||
/// <summary>
|
|||
/// Gets a factory which can be used to create child nodes.
|
|||
/// </summary>
|
|||
IAutomationNodeFactory Factory { get; } |
|||
|
|||
/// <summary>
|
|||
/// Called by the <see cref="AutomationPeer"/> when the children of the peer change.
|
|||
/// </summary>
|
|||
void ChildrenChanged(); |
|||
|
|||
/// <summary>
|
|||
/// Called by the <see cref="AutomationPeer"/> when a property other than the parent,
|
|||
/// children or root changes.
|
|||
/// </summary>
|
|||
/// <param name="property">The property that changed.</param>
|
|||
/// <param name="oldValue">The previous value of the property.</param>
|
|||
/// <param name="newValue">The new value of the property.</param>
|
|||
void PropertyChanged(AutomationProperty property, object? oldValue, object? newValue); |
|||
} |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
using Avalonia.Automation.Peers; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Automation.Platform |
|||
{ |
|||
/// <summary>
|
|||
/// Creates nodes in the UI Automation tree of the underlying platform.
|
|||
/// </summary>
|
|||
public interface IAutomationNodeFactory |
|||
{ |
|||
/// <summary>
|
|||
/// Creates an automation node for a peer.
|
|||
/// </summary>
|
|||
/// <param name="peer">The peer.</param>
|
|||
IAutomationNode CreateNode(AutomationPeer peer); |
|||
} |
|||
} |
|||
@ -1,20 +0,0 @@ |
|||
using Avalonia.Automation.Peers; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Automation.Platform |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a platform implementation of a root node in the UI Automation tree.
|
|||
/// </summary>
|
|||
public interface IRootAutomationNode : IAutomationNode |
|||
{ |
|||
/// <summary>
|
|||
/// Called by the <see cref="IRootProvider"/> when its focus changes.
|
|||
/// </summary>
|
|||
/// <param name="focus">
|
|||
/// The automation peer for the newly focused control or null if no control is focused.
|
|||
/// </param>
|
|||
void FocusChanged(AutomationPeer? focus); |
|||
} |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
using Avalonia.Automation.Peers; |
|||
using Avalonia.Automation.Platform; |
|||
using Avalonia.Native.Interop; |
|||
|
|||
namespace Avalonia.Native |
|||
{ |
|||
internal class AutomationNodeFactory : IAutomationNodeFactory |
|||
{ |
|||
private static AutomationNodeFactory _instance; |
|||
private readonly IAvaloniaNativeFactory _native; |
|||
|
|||
public static AutomationNodeFactory GetInstance(IAvaloniaNativeFactory native) |
|||
{ |
|||
return _instance ??= new AutomationNodeFactory(native); |
|||
} |
|||
|
|||
private AutomationNodeFactory(IAvaloniaNativeFactory native) => _native = native; |
|||
|
|||
public IAutomationNode CreateNode(AutomationPeer peer) |
|||
{ |
|||
return new AutomationNode(this, _native.CreateAutomationNode(new AvnAutomationPeer(peer))); |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
using Avalonia.Automation.Peers; |
|||
using Avalonia.Automation.Platform; |
|||
using Avalonia.Threading; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Win32.Automation |
|||
{ |
|||
internal class AutomationNodeFactory : IAutomationNodeFactory |
|||
{ |
|||
public static readonly AutomationNodeFactory Instance = new AutomationNodeFactory(); |
|||
|
|||
public IAutomationNode CreateNode(AutomationPeer peer) |
|||
{ |
|||
Dispatcher.UIThread.VerifyAccess(); |
|||
return new AutomationNode(peer); |
|||
} |
|||
} |
|||
} |
|||
@ -1,253 +1,253 @@ |
|||
using System.Linq; |
|||
using Avalonia.Automation.Peers; |
|||
using Avalonia.Automation.Platform; |
|||
using Avalonia.Automation.Provider; |
|||
using Avalonia.Controls.Presenters; |
|||
using Avalonia.Controls.Primitives; |
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Platform; |
|||
using Avalonia.UnitTests; |
|||
using Avalonia.VisualTree; |
|||
using Moq; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Controls.UnitTests.Automation |
|||
{ |
|||
public class ControlAutomationPeerTests |
|||
{ |
|||
private static Mock<IAutomationNodeFactory> _factory; |
|||
|
|||
public ControlAutomationPeerTests() |
|||
{ |
|||
_factory = new Mock<IAutomationNodeFactory>(); |
|||
_factory.Setup(x => x.CreateNode(It.IsAny<AutomationPeer>())) |
|||
.Returns(() => Mock.Of<IAutomationNode>(x => x.Factory == _factory)); |
|||
} |
|||
|
|||
public class Children |
|||
{ |
|||
[Fact] |
|||
public void Creates_Children_For_Controls_In_Visual_Tree() |
|||
{ |
|||
var panel = new Panel |
|||
{ |
|||
Children = |
|||
{ |
|||
new Border(), |
|||
new Border(), |
|||
}, |
|||
}; |
|||
|
|||
var factory = CreateFactory(); |
|||
var target = CreatePeer(factory, panel); |
|||
|
|||
Assert.Equal( |
|||
panel.GetVisualChildren(), |
|||
target.GetChildren().Cast<ControlAutomationPeer>().Select(x => x.Owner)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Creates_Children_when_Controls_Attached_To_Visual_Tree() |
|||
{ |
|||
var contentControl = new ContentControl |
|||
{ |
|||
Template = new FuncControlTemplate<ContentControl>((o, ns) => |
|||
new ContentPresenter |
|||
{ |
|||
Name = "PART_ContentPresenter", |
|||
[!ContentPresenter.ContentProperty] = o[!ContentControl.ContentProperty], |
|||
}), |
|||
Content = new Border(), |
|||
}; |
|||
|
|||
var factory = CreateFactory(); |
|||
var target = CreatePeer(factory, contentControl); |
|||
|
|||
Assert.Empty(target.GetChildren()); |
|||
|
|||
contentControl.Measure(Size.Infinity); |
|||
|
|||
Assert.Equal(1, target.GetChildren().Count); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Updates_Children_When_VisualChildren_Added() |
|||
{ |
|||
var panel = new Panel |
|||
{ |
|||
Children = |
|||
{ |
|||
new Border(), |
|||
new Border(), |
|||
}, |
|||
}; |
|||
|
|||
var factory = CreateFactory(); |
|||
var target = CreatePeer(factory, panel); |
|||
var children = target.GetChildren(); |
|||
|
|||
Assert.Equal(2, children.Count); |
|||
|
|||
panel.Children.Add(new Decorator()); |
|||
|
|||
children = target.GetChildren(); |
|||
Assert.Equal(3, children.Count); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Updates_Children_When_VisualChildren_Removed() |
|||
{ |
|||
var panel = new Panel |
|||
{ |
|||
Children = |
|||
{ |
|||
new Border(), |
|||
new Border(), |
|||
}, |
|||
}; |
|||
|
|||
var factory = CreateFactory(); |
|||
var target = CreatePeer(factory, panel); |
|||
var children = target.GetChildren(); |
|||
|
|||
Assert.Equal(2, children.Count); |
|||
|
|||
panel.Children.RemoveAt(1); |
|||
|
|||
children = target.GetChildren(); |
|||
Assert.Equal(1, children.Count); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Updates_Children_When_Visibility_Changes() |
|||
{ |
|||
var panel = new Panel |
|||
{ |
|||
Children = |
|||
{ |
|||
new Border(), |
|||
new Border(), |
|||
}, |
|||
}; |
|||
|
|||
var factory = CreateFactory(); |
|||
var target = CreatePeer(factory, panel); |
|||
var children = target.GetChildren(); |
|||
|
|||
Assert.Equal(2, children.Count); |
|||
|
|||
panel.Children[1].IsVisible = false; |
|||
children = target.GetChildren(); |
|||
Assert.Equal(1, children.Count); |
|||
|
|||
panel.Children[1].IsVisible = true; |
|||
children = target.GetChildren(); |
|||
Assert.Equal(2, children.Count); |
|||
} |
|||
} |
|||
|
|||
public class Parent |
|||
{ |
|||
[Fact] |
|||
public void Connects_Peer_To_Tree_When_GetParent_Called() |
|||
{ |
|||
var border = new Border(); |
|||
var tree = new Decorator |
|||
{ |
|||
Child = new Decorator |
|||
{ |
|||
Child = border, |
|||
} |
|||
}; |
|||
|
|||
var factory = CreateFactory(); |
|||
|
|||
// We're accessing Border directly without going via its ancestors. Because the tree
|
|||
// is built lazily, ensure that calling GetParent causes the ancestor tree to be built.
|
|||
var target = CreatePeer(factory, border); |
|||
|
|||
var parentPeer = Assert.IsAssignableFrom<ControlAutomationPeer>(target.GetParent()); |
|||
Assert.Same(border.GetVisualParent(), parentPeer.Owner); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Parent_Updated_When_Moved_To_Separate_Visual_Tree() |
|||
{ |
|||
var border = new Border(); |
|||
var root1 = new Decorator { Child = border }; |
|||
var root2 = new Decorator(); |
|||
var factory = CreateFactory(); |
|||
var target = CreatePeer(factory, border); |
|||
|
|||
var parentPeer = Assert.IsAssignableFrom<ControlAutomationPeer>(target.GetParent()); |
|||
Assert.Same(root1, parentPeer.Owner); |
|||
|
|||
root1.Child = null; |
|||
|
|||
Assert.Null(target.GetParent()); |
|||
|
|||
root2.Child = border; |
|||
|
|||
parentPeer = Assert.IsAssignableFrom<ControlAutomationPeer>(target.GetParent()); |
|||
Assert.Same(root2, parentPeer.Owner); |
|||
} |
|||
} |
|||
|
|||
private static IAutomationNodeFactory CreateFactory() |
|||
{ |
|||
var factory = new Mock<IAutomationNodeFactory>(); |
|||
factory.Setup(x => x.CreateNode(It.IsAny<AutomationPeer>())) |
|||
.Returns(() => Mock.Of<IAutomationNode>(x => x.Factory == factory.Object)); |
|||
return factory.Object; |
|||
} |
|||
|
|||
private static AutomationPeer CreatePeer(IAutomationNodeFactory factory, Control control) |
|||
{ |
|||
return ControlAutomationPeer.GetOrCreatePeer(factory, control); |
|||
} |
|||
|
|||
private class TestControl : Control |
|||
{ |
|||
protected override AutomationPeer OnCreateAutomationPeer(IAutomationNodeFactory factory) |
|||
{ |
|||
return new TestAutomationPeer(factory, this); |
|||
} |
|||
} |
|||
|
|||
private class AutomationTestRoot : TestRoot |
|||
{ |
|||
protected override AutomationPeer OnCreateAutomationPeer(IAutomationNodeFactory factory) |
|||
{ |
|||
return new TestRootAutomationPeer(factory, this); |
|||
} |
|||
} |
|||
|
|||
private class TestAutomationPeer : ControlAutomationPeer |
|||
{ |
|||
public TestAutomationPeer(IAutomationNodeFactory factory, Control owner) |
|||
: base(factory, owner) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
private class TestRootAutomationPeer : ControlAutomationPeer, IRootProvider |
|||
{ |
|||
public TestRootAutomationPeer(IAutomationNodeFactory factory, Control owner) |
|||
: base(factory, owner) |
|||
{ |
|||
} |
|||
|
|||
public ITopLevelImpl PlatformImpl => throw new System.NotImplementedException(); |
|||
|
|||
public AutomationPeer GetFocus() |
|||
{ |
|||
throw new System.NotImplementedException(); |
|||
} |
|||
|
|||
public AutomationPeer GetPeerFromPoint(Point p) |
|||
{ |
|||
throw new System.NotImplementedException(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
////using System.Linq;
|
|||
////using Avalonia.Automation.Peers;
|
|||
////using Avalonia.Automation.Platform;
|
|||
////using Avalonia.Automation.Provider;
|
|||
////using Avalonia.Controls.Presenters;
|
|||
////using Avalonia.Controls.Primitives;
|
|||
////using Avalonia.Controls.Templates;
|
|||
////using Avalonia.Platform;
|
|||
////using Avalonia.UnitTests;
|
|||
////using Avalonia.VisualTree;
|
|||
////using Moq;
|
|||
////using Xunit;
|
|||
|
|||
////namespace Avalonia.Controls.UnitTests.Automation
|
|||
////{
|
|||
//// public class ControlAutomationPeerTests
|
|||
//// {
|
|||
//// private static Mock<IAutomationNodeFactory> _factory;
|
|||
|
|||
//// public ControlAutomationPeerTests()
|
|||
//// {
|
|||
//// _factory = new Mock<IAutomationNodeFactory>();
|
|||
//// _factory.Setup(x => x.CreateNode(It.IsAny<AutomationPeer>()))
|
|||
//// .Returns(() => Mock.Of<IAutomationNode>(x => x.Factory == _factory));
|
|||
//// }
|
|||
|
|||
//// public class Children
|
|||
//// {
|
|||
//// [Fact]
|
|||
//// public void Creates_Children_For_Controls_In_Visual_Tree()
|
|||
//// {
|
|||
//// var panel = new Panel
|
|||
//// {
|
|||
//// Children =
|
|||
//// {
|
|||
//// new Border(),
|
|||
//// new Border(),
|
|||
//// },
|
|||
//// };
|
|||
|
|||
//// var factory = CreateFactory();
|
|||
//// var target = CreatePeer(factory, panel);
|
|||
|
|||
//// Assert.Equal(
|
|||
//// panel.GetVisualChildren(),
|
|||
//// target.GetChildren().Cast<ControlAutomationPeer>().Select(x => x.Owner));
|
|||
//// }
|
|||
|
|||
//// [Fact]
|
|||
//// public void Creates_Children_when_Controls_Attached_To_Visual_Tree()
|
|||
//// {
|
|||
//// var contentControl = new ContentControl
|
|||
//// {
|
|||
//// Template = new FuncControlTemplate<ContentControl>((o, ns) =>
|
|||
//// new ContentPresenter
|
|||
//// {
|
|||
//// Name = "PART_ContentPresenter",
|
|||
//// [!ContentPresenter.ContentProperty] = o[!ContentControl.ContentProperty],
|
|||
//// }),
|
|||
//// Content = new Border(),
|
|||
//// };
|
|||
|
|||
//// var factory = CreateFactory();
|
|||
//// var target = CreatePeer(factory, contentControl);
|
|||
|
|||
//// Assert.Empty(target.GetChildren());
|
|||
|
|||
//// contentControl.Measure(Size.Infinity);
|
|||
|
|||
//// Assert.Equal(1, target.GetChildren().Count);
|
|||
//// }
|
|||
|
|||
//// [Fact]
|
|||
//// public void Updates_Children_When_VisualChildren_Added()
|
|||
//// {
|
|||
//// var panel = new Panel
|
|||
//// {
|
|||
//// Children =
|
|||
//// {
|
|||
//// new Border(),
|
|||
//// new Border(),
|
|||
//// },
|
|||
//// };
|
|||
|
|||
//// var factory = CreateFactory();
|
|||
//// var target = CreatePeer(factory, panel);
|
|||
//// var children = target.GetChildren();
|
|||
|
|||
//// Assert.Equal(2, children.Count);
|
|||
|
|||
//// panel.Children.Add(new Decorator());
|
|||
|
|||
//// children = target.GetChildren();
|
|||
//// Assert.Equal(3, children.Count);
|
|||
//// }
|
|||
|
|||
//// [Fact]
|
|||
//// public void Updates_Children_When_VisualChildren_Removed()
|
|||
//// {
|
|||
//// var panel = new Panel
|
|||
//// {
|
|||
//// Children =
|
|||
//// {
|
|||
//// new Border(),
|
|||
//// new Border(),
|
|||
//// },
|
|||
//// };
|
|||
|
|||
//// var factory = CreateFactory();
|
|||
//// var target = CreatePeer(factory, panel);
|
|||
//// var children = target.GetChildren();
|
|||
|
|||
//// Assert.Equal(2, children.Count);
|
|||
|
|||
//// panel.Children.RemoveAt(1);
|
|||
|
|||
//// children = target.GetChildren();
|
|||
//// Assert.Equal(1, children.Count);
|
|||
//// }
|
|||
|
|||
//// [Fact]
|
|||
//// public void Updates_Children_When_Visibility_Changes()
|
|||
//// {
|
|||
//// var panel = new Panel
|
|||
//// {
|
|||
//// Children =
|
|||
//// {
|
|||
//// new Border(),
|
|||
//// new Border(),
|
|||
//// },
|
|||
//// };
|
|||
|
|||
//// var factory = CreateFactory();
|
|||
//// var target = CreatePeer(factory, panel);
|
|||
//// var children = target.GetChildren();
|
|||
|
|||
//// Assert.Equal(2, children.Count);
|
|||
|
|||
//// panel.Children[1].IsVisible = false;
|
|||
//// children = target.GetChildren();
|
|||
//// Assert.Equal(1, children.Count);
|
|||
|
|||
//// panel.Children[1].IsVisible = true;
|
|||
//// children = target.GetChildren();
|
|||
//// Assert.Equal(2, children.Count);
|
|||
//// }
|
|||
//// }
|
|||
|
|||
//// public class Parent
|
|||
//// {
|
|||
//// [Fact]
|
|||
//// public void Connects_Peer_To_Tree_When_GetParent_Called()
|
|||
//// {
|
|||
//// var border = new Border();
|
|||
//// var tree = new Decorator
|
|||
//// {
|
|||
//// Child = new Decorator
|
|||
//// {
|
|||
//// Child = border,
|
|||
//// }
|
|||
//// };
|
|||
|
|||
//// var factory = CreateFactory();
|
|||
|
|||
//// // We're accessing Border directly without going via its ancestors. Because the tree
|
|||
//// // is built lazily, ensure that calling GetParent causes the ancestor tree to be built.
|
|||
//// var target = CreatePeer(factory, border);
|
|||
|
|||
//// var parentPeer = Assert.IsAssignableFrom<ControlAutomationPeer>(target.GetParent());
|
|||
//// Assert.Same(border.GetVisualParent(), parentPeer.Owner);
|
|||
//// }
|
|||
|
|||
//// [Fact]
|
|||
//// public void Parent_Updated_When_Moved_To_Separate_Visual_Tree()
|
|||
//// {
|
|||
//// var border = new Border();
|
|||
//// var root1 = new Decorator { Child = border };
|
|||
//// var root2 = new Decorator();
|
|||
//// var factory = CreateFactory();
|
|||
//// var target = CreatePeer(factory, border);
|
|||
|
|||
//// var parentPeer = Assert.IsAssignableFrom<ControlAutomationPeer>(target.GetParent());
|
|||
//// Assert.Same(root1, parentPeer.Owner);
|
|||
|
|||
//// root1.Child = null;
|
|||
|
|||
//// Assert.Null(target.GetParent());
|
|||
|
|||
//// root2.Child = border;
|
|||
|
|||
//// parentPeer = Assert.IsAssignableFrom<ControlAutomationPeer>(target.GetParent());
|
|||
//// Assert.Same(root2, parentPeer.Owner);
|
|||
//// }
|
|||
//// }
|
|||
|
|||
//// private static IAutomationNodeFactory CreateFactory()
|
|||
//// {
|
|||
//// var factory = new Mock<IAutomationNodeFactory>();
|
|||
//// factory.Setup(x => x.CreateNode(It.IsAny<AutomationPeer>()))
|
|||
//// .Returns(() => Mock.Of<IAutomationNode>(x => x.Factory == factory.Object));
|
|||
//// return factory.Object;
|
|||
//// }
|
|||
|
|||
//// private static AutomationPeer CreatePeer(IAutomationNodeFactory factory, Control control)
|
|||
//// {
|
|||
//// return ControlAutomationPeer.GetOrCreatePeer(factory, control);
|
|||
//// }
|
|||
|
|||
//// private class TestControl : Control
|
|||
//// {
|
|||
//// protected override AutomationPeer OnCreateAutomationPeer(IAutomationNodeFactory factory)
|
|||
//// {
|
|||
//// return new TestAutomationPeer(factory, this);
|
|||
//// }
|
|||
//// }
|
|||
|
|||
//// private class AutomationTestRoot : TestRoot
|
|||
//// {
|
|||
//// protected override AutomationPeer OnCreateAutomationPeer(IAutomationNodeFactory factory)
|
|||
//// {
|
|||
//// return new TestRootAutomationPeer(factory, this);
|
|||
//// }
|
|||
//// }
|
|||
|
|||
//// private class TestAutomationPeer : ControlAutomationPeer
|
|||
//// {
|
|||
//// public TestAutomationPeer(IAutomationNodeFactory factory, Control owner)
|
|||
//// : base(factory, owner)
|
|||
//// {
|
|||
//// }
|
|||
//// }
|
|||
|
|||
//// private class TestRootAutomationPeer : ControlAutomationPeer, IRootProvider
|
|||
//// {
|
|||
//// public TestRootAutomationPeer(IAutomationNodeFactory factory, Control owner)
|
|||
//// : base(factory, owner)
|
|||
//// {
|
|||
//// }
|
|||
|
|||
//// public ITopLevelImpl PlatformImpl => throw new System.NotImplementedException();
|
|||
|
|||
//// public AutomationPeer GetFocus()
|
|||
//// {
|
|||
//// throw new System.NotImplementedException();
|
|||
//// }
|
|||
|
|||
//// public AutomationPeer GetPeerFromPoint(Point p)
|
|||
//// {
|
|||
//// throw new System.NotImplementedException();
|
|||
//// }
|
|||
//// }
|
|||
//// }
|
|||
////}
|
|||
|
|||
Loading…
Reference in new issue