Fixng 3214 - UIA providers support for Button control (#3215)

This commit is contained in:
Mikhail Lipin 2020-06-30 13:50:42 +03:00 коммит произвёл GitHub
Родитель 5797d8e7b0
Коммит fdb4350682
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
24 изменённых файлов: 515 добавлений и 138 удалений

Просмотреть файл

@ -9327,7 +9327,7 @@ virtual System.Windows.Forms.UpDownBase.ValidateEditText() -> void
~System.Windows.Forms.BindingSource.Sort.get -> string
~System.Windows.Forms.BindingSource.Sort.set -> void
~System.Windows.Forms.BindingsCollection.this[int index].get -> System.Windows.Forms.Binding
~System.Windows.Forms.ButtonBase.ButtonBaseAccessibleObject.ButtonBaseAccessibleObject(System.Windows.Forms.Control owner) -> void
System.Windows.Forms.ButtonBase.ButtonBaseAccessibleObject.ButtonBaseAccessibleObject(System.Windows.Forms.Control! owner) -> void
~System.Windows.Forms.ButtonBase.FlatAppearance.get -> System.Windows.Forms.FlatButtonAppearance
~System.Windows.Forms.ButtonBase.Image.get -> System.Drawing.Image
~System.Windows.Forms.ButtonBase.Image.set -> void

Просмотреть файл

@ -1,4 +1,5 @@
~override System.Windows.Forms.Splitter.CreateAccessibilityInstance() -> System.Windows.Forms.AccessibleObject
~override System.Windows.Forms.Button.CreateAccessibilityInstance() -> System.Windows.Forms.AccessibleObject
System.Windows.Forms.ListViewGroup.TitleImageIndex.get -> int
System.Windows.Forms.ListViewGroup.TitleImageIndex.set -> void
System.Windows.Forms.ListViewGroup.TitleImageKey.get -> string!

Просмотреть файл

@ -6713,4 +6713,7 @@ Stack trace where the illegal operation occurred was:
<data name="ListViewGroupImageListDescr" xml:space="preserve">
<value>The ImageList control used by the ListView for ListViewGroup images in all views.</value>
</data>
<data name="ConstructorArgumentInvalidValueType" xml:space="preserve">
<value>Argument '{0}' cannot be converted to type '{1}'.</value>
</data>
</root>

5
src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">Nezpracovaný typ {0}.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">Aktivní ovládací prvek.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">Unbehandelter Typ {0}.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">Das zurzeit aktivierte Steuerelement.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">Tipo no controlado {0}.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">Control activo actual.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">Type {0} non géré.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">Le contrôle actuellement actif.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">Tipo {0} non gestito.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">Controllo correntemente attivo.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">ハンドルされていない型 {0} です。</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">現在アクティブなコントロールです。</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">처리되지 않은 {0} 형식입니다.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">현재 활성 컨트롤입니다.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">Nieobsługiwany typ {0}.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">Aktualnie aktywny formant.</target>

Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">Tipo {0} não tratado.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">O controle ativo atualmente.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">Необработанный тип {0}.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">Активный в текущий момент элемент управления.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf сгенерированный
Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">İşlenmemiş {0} türü.</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">Şu anda etkin denetim.</target>

Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">未处理的类型 {0}。</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">当前处于活动状态的控件。</target>

Просмотреть файл

@ -1177,6 +1177,11 @@
<target state="translated">未處理的類型 {0}。</target>
<note />
</trans-unit>
<trans-unit id="ConstructorArgumentInvalidValueType">
<source>Argument '{0}' cannot be converted to type '{1}'.</source>
<target state="new">Argument '{0}' cannot be converted to type '{1}'.</target>
<note />
</trans-unit>
<trans-unit id="ContainerControlActiveControlDescr">
<source>The currently active control.</source>
<target state="translated">目前作用中的控制項。</target>

Просмотреть файл

@ -0,0 +1,37 @@
// 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 static Interop.UiaCore;
namespace System.Windows.Forms
{
public partial class Button
{
internal class ButtonAccessibleObject : ButtonBaseAccessibleObject
{
public ButtonAccessibleObject(Button owner) : base(owner)
{
}
internal override object? GetPropertyValue(UIA propertyID)
=> propertyID switch
{
UIA.NamePropertyId
=> Name,
UIA.AutomationIdPropertyId
=> Owner.Name,
UIA.ControlTypePropertyId
=> UIA.ButtonControlTypeId,
UIA.IsKeyboardFocusablePropertyId
=>
// This is necessary for compatibility with MSAA proxy:
// IsKeyboardFocusable = true regardless the control is enabled/disabled.
true,
UIA.HasKeyboardFocusPropertyId
=> Owner.Focused,
_ => base.GetPropertyValue(propertyID)
};
}
}
}

Просмотреть файл

@ -20,7 +20,7 @@ namespace System.Windows.Forms
/// </summary>
[SRDescription(nameof(SR.DescriptionButton))]
[Designer("System.Windows.Forms.Design.ButtonBaseDesigner, " + AssemblyRef.SystemDesign)]
public class Button : ButtonBase, IButtonControl
public partial class Button : ButtonBase, IButtonControl
{
/// <summary>
/// The dialog result that will be sent to the parent dialog form when
@ -87,6 +87,9 @@ namespace System.Windows.Forms
}
}
protected override AccessibleObject CreateAccessibilityInstance()
=> new ButtonAccessibleObject(this);
internal override ButtonBaseAdapter CreateFlatAdapter()
{
return new ButtonFlatAdapter(this);
@ -182,6 +185,8 @@ namespace System.Windows.Forms
}
}
internal override bool SupportsUiaProviders => true;
/// <summary>
/// Raises the <see cref='Control.OnMouseEnter'/> event.
/// </summary>
@ -249,6 +254,10 @@ namespace System.Windows.Forms
AccessibilityNotifyClients(AccessibleEvents.StateChange, -1);
AccessibilityNotifyClients(AccessibleEvents.NameChange, -1);
// UIA events:
AccessibilityObject.RaiseAutomationPropertyChangedEvent(UiaCore.UIA.NamePropertyId, Name, Name);
AccessibilityObject.RaiseAutomationEvent(UiaCore.UIA.AutomationPropertyChangedEventId);
base.OnClick(e);
}

Просмотреть файл

@ -0,0 +1,33 @@
// 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.
namespace System.Windows.Forms
{
public partial class ButtonBase
{
public class ButtonBaseAccessibleObject : ControlAccessibleObject
{
private readonly ButtonBase _owningButtonBase;
public ButtonBaseAccessibleObject(Control owner)
: base((owner is ButtonBase owningButtonBase) ? owner : throw new ArgumentException(string.Format(SR.ConstructorArgumentInvalidValueType, nameof(Owner), typeof(ButtonBase))))
{
_owningButtonBase = owningButtonBase;
}
public override AccessibleStates State
=> _owningButtonBase.IsHandleCreated && _owningButtonBase.OwnerDraw && _owningButtonBase.MouseIsDown
? base.State | AccessibleStates.Pressed
: base.State;
public override void DoDefaultAction()
{
if (_owningButtonBase.IsHandleCreated)
{
_owningButtonBase.OnClick(EventArgs.Empty);
}
}
}
}
}

Просмотреть файл

@ -19,7 +19,7 @@ namespace System.Windows.Forms
/// Implements the basic functionality required by a button control.
/// </summary>
[Designer("System.Windows.Forms.Design.ButtonBaseDesigner, " + AssemblyRef.SystemDesign)]
public abstract class ButtonBase : Control
public abstract partial class ButtonBase : Control
{
private FlatStyle flatStyle = System.Windows.Forms.FlatStyle.Standard;
private ContentAlignment imageAlign = ContentAlignment.MiddleCenter;
@ -1349,33 +1349,5 @@ namespace System.Windows.Forms
}
}
}
public class ButtonBaseAccessibleObject : ControlAccessibleObject
{
public ButtonBaseAccessibleObject(Control owner) : base(owner)
{
}
public override void DoDefaultAction()
{
((ButtonBase)Owner).OnClick(EventArgs.Empty);
}
public override AccessibleStates State
{
get
{
AccessibleStates state = base.State;
ButtonBase owner = (ButtonBase)Owner;
if (owner.OwnerDraw && owner.MouseIsDown)
{
state |= AccessibleStates.Pressed;
}
return state;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,97 @@
// 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 Xunit;
using static Interop.UiaCore;
namespace System.Windows.Forms.Tests
{
public class Button_ButtonAccessibleObjectTests
{
[WinFormsFact]
public void ButtonAccessibleObject_Ctor_NullControl_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => new Button.ButtonAccessibleObject(null));
}
[WinFormsFact]
public void ButtonAccessibleObject_Ctor_InitializesOwner()
{
using var button = new Button();
Assert.False(button.IsHandleCreated);
var buttonAccessibleObject = new Button.ButtonAccessibleObject(button);
Assert.Same(button, buttonAccessibleObject.Owner);
// TODO: ControlAccessibleObject should not force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(button.IsHandleCreated);
}
[WinFormsFact]
public void ButtonAccessibleObject_AccessibleRole_Default_ReturnsPushButton()
{
using var button = new Button
{
AccessibleRole = AccessibleRole.Default
};
Assert.False(button.IsHandleCreated);
var buttonAccessibleObject = new Button.ButtonAccessibleObject(button);
Assert.Equal(AccessibleRole.PushButton, buttonAccessibleObject.Role);
// TODO: ControlAccessibleObject should not force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(button.IsHandleCreated);
}
[WinFormsFact]
public void ButtonAccessibleObject_AccessibleRole_Custom_ReturnsExpected()
{
using var button = new Button
{
AccessibleRole = AccessibleRole.Link
};
Assert.False(button.IsHandleCreated);
var buttonAccessibleObject = new Button.ButtonAccessibleObject(button);
Assert.Equal(AccessibleRole.Link, buttonAccessibleObject.Role);
// TODO: ControlAccessibleObject should not force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(button.IsHandleCreated);
}
[WinFormsTheory]
[InlineData((int)UIA.NamePropertyId, "TestName")]
[InlineData((int)UIA.ControlTypePropertyId, UIA.ButtonControlTypeId)]
[InlineData((int)UIA.IsKeyboardFocusablePropertyId, true)]
[InlineData((int)UIA.AutomationIdPropertyId, "Button1")]
public void ButtonAccessibleObject_GetPropertyValue_Invoke_ReturnsExpected(int propertyID, object expected)
{
using var button = new Button
{
Name = "Button1",
AccessibleName = "TestName"
};
Assert.False(button.IsHandleCreated);
var buttonAccessibleObject = new Button.ButtonAccessibleObject(button);
object value = buttonAccessibleObject.GetPropertyValue((UIA)propertyID);
Assert.Equal(expected, value);
// TODO: ControlAccessibleObject should not force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(button.IsHandleCreated);
}
[WinFormsFact]
public void ButtonAccessibleObject_IsPatternSupported_Invoke_ReturnsTrue_ForLegacyIAccessiblePatternId()
{
using var button = new Button();
Assert.False(button.IsHandleCreated);
var buttonAccessibleObject = new Button.ButtonAccessibleObject(button);
Assert.True(buttonAccessibleObject.IsPatternSupported(UIA.LegacyIAccessiblePatternId));
// TODO: ControlAccessibleObject should not force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(button.IsHandleCreated);
}
}
}

Просмотреть файл

@ -0,0 +1,191 @@
// 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 WinForms.Common.Tests;
using Xunit;
namespace System.Windows.Forms.Tests
{
public class ButtonBase_ButtonBaseAccessibleObjectTests
{
[WinFormsFact]
public void ButtonBaseAccessibleObject_Ctor_NullControl_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => new ButtonBase.ButtonBaseAccessibleObject(null));
}
[WinFormsFact]
public void ButtonBaseAccessibleObject_Ctor_InvalidTypeControl_ThrowsArgumentException()
{
using var textBox = new TextBox();
Assert.Throws<ArgumentException>(() => new ButtonBase.ButtonBaseAccessibleObject(textBox));
}
[WinFormsTheory]
[InlineData(FlatStyle.Flat, true, true, AccessibleStates.Focusable | AccessibleStates.Pressed)]
[InlineData(FlatStyle.Flat, false, true, AccessibleStates.Focusable | AccessibleStates.Pressed)]
[InlineData(FlatStyle.Flat, true, false, AccessibleStates.Focusable)]
[InlineData(FlatStyle.Flat, false, false, AccessibleStates.Focusable)]
[InlineData(FlatStyle.Popup, true, true, AccessibleStates.Focusable | AccessibleStates.Pressed)]
[InlineData(FlatStyle.Popup, false, true, AccessibleStates.Focusable | AccessibleStates.Pressed)]
[InlineData(FlatStyle.Popup, true, false, AccessibleStates.Focusable)]
[InlineData(FlatStyle.Popup, false, false, AccessibleStates.Focusable)]
[InlineData(FlatStyle.Standard, true, true, AccessibleStates.Focusable | AccessibleStates.Pressed)]
[InlineData(FlatStyle.Standard, false, true, AccessibleStates.Focusable | AccessibleStates.Pressed)]
[InlineData(FlatStyle.Standard, true, false, AccessibleStates.Focusable)]
[InlineData(FlatStyle.Standard, false, false, AccessibleStates.Focusable)]
[InlineData(FlatStyle.System, true, true, AccessibleStates.Focusable)]
[InlineData(FlatStyle.System, false, true, AccessibleStates.Focusable)]
[InlineData(FlatStyle.System, true, false, AccessibleStates.Focusable)]
[InlineData(FlatStyle.System, false, false, AccessibleStates.Focusable)]
public void ButtonBaseAccessibleObject_State_is_correct(FlatStyle flatStyle, bool createControl, bool mouseIsDown, AccessibleStates expectedAccessibleState)
{
using var button = new SubButtonBase()
{
FlatStyle = flatStyle
};
if (createControl)
{
button.CreateControl();
}
Assert.Equal(createControl, button.IsHandleCreated);
if (mouseIsDown)
{
button.OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0));
}
var buttonBaseAccessibleObject = new ButtonBase.ButtonBaseAccessibleObject(button);
Assert.Equal(expectedAccessibleState, buttonBaseAccessibleObject.State);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(button.IsHandleCreated);
}
[WinFormsTheory]
[InlineData(true, true, AccessibleRole.Client)]
[InlineData(true, false, AccessibleRole.HelpBalloon)]
[InlineData(false, true, AccessibleRole.Client)]
[InlineData(false, false, AccessibleRole.HelpBalloon)]
public void ButtonBase_CreateAccessibilityInstance_InvokeWithRole_ReturnsExpected(bool createControl, bool defaultRole, AccessibleRole expectedAccessibleRole)
{
using var control = new SubButtonBase();
if (!defaultRole)
{
control.AccessibleRole = AccessibleRole.HelpBalloon;
}
if (createControl)
{
control.CreateControl();
}
Assert.Equal(createControl, control.IsHandleCreated);
ButtonBase.ButtonBaseAccessibleObject instance = Assert.IsType<ButtonBase.ButtonBaseAccessibleObject>(control.CreateAccessibilityInstance());
Assert.NotNull(instance);
Assert.Same(control, instance.Owner);
Assert.Equal(expectedAccessibleRole, instance.Role);
Assert.NotSame(control.CreateAccessibilityInstance(), instance);
Assert.NotSame(control.AccessibilityObject, instance);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(FlatStyle))]
public void ButtonBase_CreateAccessibilityInstance_InvokeWithDefaultRole_ReturnsExpected_ForAllFlatStyles(FlatStyle flatStyle)
{
using var control = new SubButtonBase()
{
FlatStyle = flatStyle
};
Assert.False(control.IsHandleCreated);
ButtonBase.ButtonBaseAccessibleObject instance = Assert.IsType<ButtonBase.ButtonBaseAccessibleObject>(control.CreateAccessibilityInstance());
Assert.Equal(AccessibleRole.Client, instance.Role);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
}
[WinFormsTheory]
[InlineData(true)]
[InlineData(false)]
public void ButtonBase_CreateAccessibilityInstance_InvokeDoDefaultAction_CallsOnClick(bool createControl)
{
using var control = new SubButtonBase();
if (createControl)
{
control.CreateControl();
}
Assert.Equal(createControl, control.IsHandleCreated);
int callCount = 0;
control.Click += (sender, e) =>
{
Assert.Same(control, sender);
Assert.Same(EventArgs.Empty, e);
callCount++;
};
var buttonBaseAccessibleObject = new ButtonBase.ButtonBaseAccessibleObject(control);
buttonBaseAccessibleObject.DoDefaultAction();
Assert.Equal(1, callCount);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
}
[WinFormsTheory]
[InlineData(true)]
[InlineData(false)]
public void ButtonBase_CreateAccessibilityInstance_InvokeIButtonControlDoDefaultAction_CallsOnClick(bool createControl)
{
using var control = new SubButtonBase();
if (createControl)
{
control.CreateControl();
}
Assert.Equal(createControl, control.IsHandleCreated);
int callCount = 0;
control.Click += (sender, e) =>
{
Assert.Same(control, sender);
Assert.Same(EventArgs.Empty, e);
callCount++;
};
int performClickCallCount = 0;
control.PerformClickAction = () => performClickCallCount++;
var buttonBaseAccessibleObject = new ButtonBase.ButtonBaseAccessibleObject(control);
buttonBaseAccessibleObject.DoDefaultAction();
Assert.Equal(1, callCount);
Assert.Equal(0, performClickCallCount);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
}
private class SubButtonBase : ButtonBase
{
public Action PerformClickAction { get; set; }
public new AccessibleObject CreateAccessibilityInstance() => base.CreateAccessibilityInstance();
public new void OnMouseDown(MouseEventArgs e) => base.OnMouseDown(e);
public void PerformClick() => PerformClickAction();
}
}
}

Просмотреть файл

@ -4490,105 +4490,6 @@ namespace System.Windows.Forms.Tests
Assert.Equal(2, callCount);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(FlatStyle))]
public void ButtonBase_CreateAccessibilityInstance_Invoke_ReturnsExpected(FlatStyle flatStyle)
{
using var control = new SubButtonBase
{
FlatStyle = flatStyle
};
ButtonBase.ButtonBaseAccessibleObject instance = Assert.IsType<ButtonBase.ButtonBaseAccessibleObject>(control.CreateAccessibilityInstance());
Assert.NotNull(instance);
Assert.Same(control, instance.Owner);
Assert.Equal(AccessibleStates.Focusable, instance.State);
Assert.Equal(AccessibleRole.Client, instance.Role);
Assert.NotSame(control.CreateAccessibilityInstance(), instance);
Assert.NotSame(control.AccessibilityObject, instance);
}
[WinFormsTheory]
[InlineData(FlatStyle.Flat, AccessibleStates.Pressed | AccessibleStates.Focusable)]
[InlineData(FlatStyle.Popup, AccessibleStates.Pressed | AccessibleStates.Focusable)]
[InlineData(FlatStyle.Standard, AccessibleStates.Pressed | AccessibleStates.Focusable)]
[InlineData(FlatStyle.System, AccessibleStates.Focusable)]
public void ButtonBase_CreateAccessibilityInstance_InvokeMouseDown_ReturnsExpected(FlatStyle flatStyle, AccessibleStates expectedState)
{
using var control = new SubButtonBase
{
FlatStyle = flatStyle
};
control.OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0));
ButtonBase.ButtonBaseAccessibleObject instance = Assert.IsType<ButtonBase.ButtonBaseAccessibleObject>(control.CreateAccessibilityInstance());
Assert.NotNull(instance);
Assert.Same(control, instance.Owner);
Assert.Equal(expectedState, instance.State);
Assert.Equal(AccessibleRole.Client, instance.Role);
Assert.NotSame(control.CreateAccessibilityInstance(), instance);
Assert.NotSame(control.AccessibilityObject, instance);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(FlatStyle))]
public void ButtonBase_CreateAccessibilityInstance_InvokeWithCustomRole_ReturnsExpected(FlatStyle flatStyle)
{
using var control = new SubButtonBase
{
FlatStyle = flatStyle,
AccessibleRole = AccessibleRole.HelpBalloon
};
ButtonBase.ButtonBaseAccessibleObject instance = Assert.IsType<ButtonBase.ButtonBaseAccessibleObject>(control.CreateAccessibilityInstance());
Assert.NotNull(instance);
Assert.Same(control, instance.Owner);
Assert.Equal(AccessibleStates.Focusable, instance.State);
Assert.Equal(AccessibleRole.HelpBalloon, instance.Role);
Assert.NotSame(control.CreateAccessibilityInstance(), instance);
Assert.NotSame(control.AccessibilityObject, instance);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(FlatStyle))]
public void ButtonBase_CreateAccessibilityInstance_InvokeDoDefaultAction_CallsOnClick(FlatStyle flatStyle)
{
using var control = new SubButtonBase
{
FlatStyle = flatStyle
};
int callCount = 0;
control.Click += (sender, e) =>
{
Assert.Same(control, sender);
Assert.Same(EventArgs.Empty, e);
callCount++;
};
ButtonBase.ButtonBaseAccessibleObject instance = Assert.IsType<ButtonBase.ButtonBaseAccessibleObject>(control.CreateAccessibilityInstance());
instance.DoDefaultAction();
Assert.Equal(1, callCount);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(FlatStyle))]
public void ButtonBase_CreateAccessibilityInstance_InvokeIButtonControlDoDefaultAction_CallsOnClick(FlatStyle flatStyle)
{
using var control = new ButtonControl
{
FlatStyle = flatStyle
};
int callCount = 0;
control.Click += (sender, e) =>
{
Assert.Same(control, sender);
Assert.Same(EventArgs.Empty, e);
callCount++;
};
int performClickCallCount = 0;
control.PerformClickAction = () => performClickCallCount++;
ButtonBase.ButtonBaseAccessibleObject instance = Assert.IsType<ButtonBase.ButtonBaseAccessibleObject>(control.CreateAccessibilityInstance());
instance.DoDefaultAction();
Assert.Equal(1, callCount);
Assert.Equal(0, performClickCallCount);
}
[WinFormsFact]
public void ButtonBase_Dispose_Invoke_Success()
{

Просмотреть файл

@ -11,6 +11,7 @@ using Moq;
using WinForms.Common.Tests;
using Xunit;
using static Interop;
using static Interop.UiaCore;
using static Interop.User32;
namespace System.Windows.Forms.Tests
@ -1813,13 +1814,17 @@ namespace System.Windows.Forms.Tests
control.Click += handler;
control.OnClick(eventArgs);
Assert.Equal(1, callCount);
Assert.False(control.IsHandleCreated);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
// Remove handler.
control.Click -= handler;
control.OnClick(eventArgs);
Assert.Equal(1, callCount);
Assert.False(control.IsHandleCreated);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
}
[WinFormsTheory]
@ -1849,7 +1854,9 @@ namespace System.Windows.Forms.Tests
control.OnClick(eventArgs);
Assert.Equal(1, callCount);
Assert.Equal(DialogResult.Yes, form.DialogResult);
Assert.False(control.IsHandleCreated);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
Assert.False(parent.IsHandleCreated);
Assert.False(form.IsHandleCreated);
@ -1858,7 +1865,9 @@ namespace System.Windows.Forms.Tests
control.OnClick(eventArgs);
Assert.Equal(1, callCount);
Assert.Equal(DialogResult.Yes, form.DialogResult);
Assert.False(control.IsHandleCreated);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
Assert.False(parent.IsHandleCreated);
Assert.False(form.IsHandleCreated);
}
@ -2994,13 +3003,17 @@ namespace System.Windows.Forms.Tests
control.Click += handler;
control.PerformClick();
Assert.Equal(1, callCount);
Assert.False(control.IsHandleCreated);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
// Remove handler.
control.Click -= handler;
control.PerformClick();
Assert.Equal(1, callCount);
Assert.False(control.IsHandleCreated);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(control.IsHandleCreated);
}
[WinFormsFact]
@ -3165,7 +3178,9 @@ namespace System.Windows.Forms.Tests
};
Assert.Equal(expectedClickCallCount != 0, control.ProcessMnemonic(charCode));
Assert.Equal(expectedClickCallCount, clickCallCount);
Assert.False(control.IsHandleCreated);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.Equal(expectedClickCallCount != 0, control.IsHandleCreated);
}
[WinFormsTheory]
@ -3205,6 +3220,24 @@ namespace System.Windows.Forms.Tests
Assert.Equal("System.Windows.Forms.Button, Text: ", control.ToString());
}
[WinFormsFact]
public void Button_RaiseAutomationEvent_Invoke_Success()
{
using var button = new TestButton();
Assert.False(button.IsHandleCreated);
var accessibleObject = (SubButtonAccessibleObject)button.AccessibilityObject;
Assert.Equal(0, accessibleObject.RaiseAutomationEventCallsCount);
Assert.Equal(0, accessibleObject.RaiseAutomationPropertyChangedEventCallsCount);
button.PerformClick();
Assert.Equal(1, accessibleObject.RaiseAutomationEventCallsCount);
Assert.Equal(1, accessibleObject.RaiseAutomationPropertyChangedEventCallsCount);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.True(button.IsHandleCreated);
}
[WinFormsFact]
public void Button_ToString_InvokeShortText_ReturnsExpected()
{
@ -3463,7 +3496,9 @@ namespace System.Windows.Forms.Tests
control.WndProc(ref m);
Assert.Equal(expectedResult, m.Result);
Assert.Equal(expectedCallCount, callCount);
Assert.False(control.IsHandleCreated);
// TODO: ControlAccessibleObject shouldn't force handle creation, tracked in https://github.com/dotnet/winforms/issues/3062
Assert.Equal(expectedCallCount > 0, control.IsHandleCreated);
}
}
@ -3603,5 +3638,38 @@ namespace System.Windows.Forms.Tests
public new void WndProc(ref Message m) => base.WndProc(ref m);
}
private class TestButton : Button
{
protected override AccessibleObject CreateAccessibilityInstance()
{
return new SubButtonAccessibleObject(this);
}
}
private class SubButtonAccessibleObject : Button.ButtonAccessibleObject
{
public SubButtonAccessibleObject(Button owner) : base(owner)
{
RaiseAutomationEventCallsCount = 0;
RaiseAutomationPropertyChangedEventCallsCount = 0;
}
public int RaiseAutomationEventCallsCount { get; private set; }
public int RaiseAutomationPropertyChangedEventCallsCount { get; private set; }
internal override bool RaiseAutomationEvent(UIA eventId)
{
RaiseAutomationEventCallsCount++;
return base.RaiseAutomationEvent(eventId);
}
internal override bool RaiseAutomationPropertyChangedEvent(UIA propertyId, object oldValue, object newValue)
{
RaiseAutomationPropertyChangedEventCallsCount++;
return base.RaiseAutomationPropertyChangedEvent(propertyId, oldValue, newValue);
}
}
}
}