Skip to content

Commit

Permalink
Merge pull request #10430 from AvaloniaUI/add-radioButtonAutomationPeer
Browse files Browse the repository at this point in the history
Add RadioButtonAutomationPeer
  • Loading branch information
Takoooooo authored Feb 23, 2023
2 parents ae1fcfe + de7559f commit 31a691c
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 0 deletions.
10 changes: 10 additions & 0 deletions samples/IntegrationTestApp/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@
</StackPanel>
</TabItem>

<TabItem Header="RadioButton">
<StackPanel Orientation="Vertical">
<RadioButton Name="BasicRadioButton">Sample RadioButton</RadioButton>
<StackPanel Orientation="Vertical">
<RadioButton Name="ThreeStatesRadioButton1" IsChecked="True" IsThreeState="True">Three States: Option 1</RadioButton>
<RadioButton Name="ThreeStatesRadioButton2" IsChecked="False" IsThreeState="True">Three States: Option 2</RadioButton>
</StackPanel>
</StackPanel>
</TabItem>

<TabItem Header="CheckBox">
<StackPanel>
<CheckBox Name="UncheckedCheckBox">Unchecked</CheckBox>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;

namespace Avalonia.Controls.Automation.Peers
{
public class RadioButtonAutomationPeer : ToggleButtonAutomationPeer, ISelectionItemProvider
{
public RadioButtonAutomationPeer(RadioButton owner) : base(owner)
{
owner.PropertyChanged += (a, e) =>
{
if (e.Property == RadioButton.IsCheckedProperty)
{
RaiseToggleStatePropertyChangedEvent((bool?)e.OldValue, (bool?)e.NewValue);
}
};
}

override protected string GetClassNameCore()
{
return "RadioButton";
}

override protected AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.RadioButton;
}

public bool IsSelected => ((RadioButton)Owner).IsChecked == true;

public ISelectionProvider? SelectionContainer => null;

public void AddToSelection()
{
if (((RadioButton)Owner).IsChecked != true)
throw new InvalidOperationException("Operation cannot be performed");
}

public void RemoveFromSelection()
{
if (((RadioButton)Owner).IsChecked == true)
throw new InvalidOperationException("Operation cannot be performed");
}

public void Select()
{
if (!IsEnabled())
throw new InvalidOperationException("Element is disabled thus it cannot be selected");

((RadioButton)Owner).IsChecked = true;
}

internal virtual void RaiseToggleStatePropertyChangedEvent(bool? oldValue, bool? newValue)
{
RaisePropertyChangedEvent(
SelectionItemPatternIdentifiers.IsSelectedProperty,
oldValue == true,
newValue == true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Avalonia.Automation.Provider;

namespace Avalonia.Automation
{
/// <summary>
/// Contains values used as identifiers by <see cref="ISelectionItemProvider"/>.
/// </summary>
public static class SelectionItemPatternIdentifiers
{
/// <summary>Indicates the element is currently selected.</summary>
public static AutomationProperty IsSelectedProperty { get; } = new AutomationProperty();

/// <summary>Indicates the element is currently selected.</summary>
public static AutomationProperty SelectionContainerProperty { get; } = new AutomationProperty();
}
}
7 changes: 7 additions & 0 deletions src/Avalonia.Controls/RadioButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Automation.Peers;
using Avalonia.Controls.Primitives;
using Avalonia.Reactive;
using Avalonia.Rendering;
Expand Down Expand Up @@ -147,6 +149,11 @@ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e
}
}

protected override AutomationPeer OnCreateAutomationPeer()
{
return new RadioButtonAutomationPeer(this);
}

private void SetGroupName(string? newGroupName)
{
var oldGroupName = GroupName;
Expand Down
2 changes: 2 additions & 0 deletions src/Windows/Avalonia.Win32/Automation/AutomationNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ internal partial class AutomationNode : MarshalByRefObject,
{ SelectionPatternIdentifiers.CanSelectMultipleProperty, UiaPropertyId.SelectionCanSelectMultiple },
{ SelectionPatternIdentifiers.IsSelectionRequiredProperty, UiaPropertyId.SelectionIsSelectionRequired },
{ SelectionPatternIdentifiers.SelectionProperty, UiaPropertyId.SelectionSelection },
{ SelectionItemPatternIdentifiers.IsSelectedProperty, UiaPropertyId.SelectionItemIsSelected },
{ SelectionItemPatternIdentifiers.SelectionContainerProperty, UiaPropertyId.SelectionItemSelectionContainer }
};

private static ConditionalWeakTable<AutomationPeer, AutomationNode> s_nodes = new();
Expand Down
48 changes: 48 additions & 0 deletions tests/Avalonia.IntegrationTests.Appium/RadioButtonTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using OpenQA.Selenium.Appium;
using Xunit;

namespace Avalonia.IntegrationTests.Appium
{
[Collection("Default")]
public class RadioButtonTests
{
private readonly AppiumDriver<AppiumWebElement> _session;

public RadioButtonTests(TestAppFixture fixture)
{
_session = fixture.Session;

var tabs = _session.FindElementByAccessibilityId("MainTabs");
tabs.FindElementByName("RadioButton").Click();
}


[Fact]
public void RadioButton_IsChecked_True_When_Clicked()
{
var button = _session.FindElementByAccessibilityId("BasicRadioButton");
Assert.False(button.GetIsChecked());
button.Click();
Assert.True(button.GetIsChecked());
}

[Fact]
public void ThreeState_RadioButton_IsChecked_False_When_Other_ThreeState_RadioButton_Checked()
{
var button1 = _session.FindElementByAccessibilityId("ThreeStatesRadioButton1");
var button2 = _session.FindElementByAccessibilityId("ThreeStatesRadioButton2");
Assert.True(button1.GetIsChecked());
Assert.False(button2.GetIsChecked());
button2.Click();
Assert.False(button1.GetIsChecked());
Assert.True(button2.GetIsChecked());
}

}
}

0 comments on commit 31a691c

Please sign in to comment.