-
Notifications
You must be signed in to change notification settings - Fork 2k
Improve VisualState order and prevent sticky Focused visual state #27477
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 9 commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
4c54fbb
Make `PointerOver` to have higher priority than `Focused`
MartyIX 89d21a4
Sandbox demo for easy testing
MartyIX 825cd7a
Revert "Sandbox demo for easy testing"
MartyIX dc831a6
Copy WinUI focus state pattern
mattleibow f61491c
Update src/TestUtils/src/UITest.Appium/HelperExtensions.cs
mattleibow 403d1e5
Update src/TestUtils/src/UITest.Appium/HelperExtensions.cs
mattleibow a31747c
Update src/TestUtils/src/UITest.Appium/HelperExtensions.cs
mattleibow 72e7d0c
Add checks for actual screen density
mattleibow dd79425
Try and order the state changes better
mattleibow eac003b
Merge main into dev/focus-visual-states and resolve VisualState confl…
kubaflo 2e44d5a
Address review feedback: fix comment typos and fill XML doc
kubaflo a71beef
Address AI review: guard Unfocused churn and gate hover tests to desktop
kubaflo be44ebb
Gate all Issue19752 UI tests to desktop
kubaflo 37157d3
Gate: reset cursor position before each test to ensure predictable in…
kubaflo 48e2541
Address AI review: fix build error, InvalidCastException, and hot-pat…
kubaflo 554d7ca
Add cross-platform unit test for sticky Focused state on disable
kubaflo 58bc52e
Merge remote-tracking branch 'upstream/net11.0' into dev/focus-visual…
kubaflo 1a0ea8b
Make VisualStateManager.FocusStates public for .NET 11
kubaflo 77535a4
Restore net11.0 versions of unrelated files pulled in by the earlier …
kubaflo 4c0ad1e
Merge branch 'net11.0' into dev/focus-visual-states
kubaflo fca651c
Fix merge-corrupted net-android PublicAPI entry for VisualStateManage…
kubaflo 4a88afe
Merge branch 'net11.0' into dev/focus-visual-states
kubaflo d81b3bf
Address review feedback for #27477
Copilot 4745386
Fix unfocused visual state ordering
Copilot 63c0137
Tighten visual state review fixes
Copilot 8052433
Reapply visual states for precedence
Copilot e635492
Limit forced visual state reapplication
Copilot 12a9ee1
Handle pointer-over focus transitions
Copilot a5d128c
Stabilize focus transition edge cases
Copilot 9cc6403
Address review feedback for #27477
Copilot d3fc3ae
Address review feedback for #27477
Copilot c7bd118
Address review feedback for #27477
Copilot 6eac57d
Address review feedback for #27477
Copilot 17f081f
Address review feedback for #27477
Copilot 6a0da51
Address review feedback for #27477
Copilot f2a6435
Address review feedback for #27477
Copilot 19108f2
Address review feedback for #27477
Copilot e854dc2
Address review feedback for #27477
Copilot f076de8
Address review feedback for #27477
Copilot 959f64a
Address review feedback for #27477
Copilot 200e647
Address review feedback for #27477
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,4 +6,4 @@ public MainPage() | |
| { | ||
| InitializeComponent(); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
src/Controls/tests/TestCases.HostApp/Issues/Issue19752.xaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| <?xml version="1.0" encoding="utf-8" ?> | ||
| <ContentPage | ||
| xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
| x:Class="Maui.Controls.Sample.Issues.Issue19752" | ||
| xmlns:cv1="clr-namespace:Maui.Controls.Sample" | ||
| xmlns:local="clr-namespace:Maui.Controls.Sample.Issues" | ||
| x:Name="ThisMainPage" | ||
|
Comment on lines
+6
to
+8
Comment on lines
+6
to
+8
|
||
| Title="Main Page"> | ||
|
Comment on lines
+2
to
+9
Comment on lines
+2
to
+9
|
||
|
|
||
| <VerticalStackLayout Padding="20,120" Spacing="20"> | ||
| <VerticalStackLayout.Resources> | ||
| <Style TargetType="Button"> | ||
| <Setter Property="VisualStateManager.VisualStateGroups"> | ||
| <VisualStateGroupList> | ||
| <VisualStateGroup x:Name="CommonStates"> | ||
| <VisualState x:Name="Normal"> | ||
| <VisualState.Setters> | ||
| <Setter Property="Text" Value="Normal"/> | ||
| </VisualState.Setters> | ||
| </VisualState> | ||
| <VisualState x:Name="PointerOver"> | ||
| <VisualState.Setters> | ||
| <Setter Property="Text" Value="PointerOver"/> | ||
| </VisualState.Setters> | ||
| </VisualState> | ||
| <VisualState x:Name="Pressed"> | ||
| <VisualState.Setters> | ||
| <Setter Property="Text" Value="Pressed"/> | ||
| </VisualState.Setters> | ||
| </VisualState> | ||
| <VisualState x:Name="Disabled"> | ||
| <VisualState.Setters> | ||
| <Setter Property="Text" Value="Disabled"/> | ||
| </VisualState.Setters> | ||
| </VisualState> | ||
| </VisualStateGroup> | ||
| <VisualStateGroup x:Name="FocusStates"> | ||
| <VisualState x:Name="Focused"> | ||
| <VisualState.Setters> | ||
| <Setter Property="Text" Value="Focused"/> | ||
| <Setter Property="BorderColor" Value="Red"/> | ||
| <Setter Property="Margin" Value="20,0"/> | ||
| </VisualState.Setters> | ||
| </VisualState> | ||
| <VisualState x:Name="Unfocused"> | ||
| <VisualState.Setters> | ||
| <Setter Property="Text" Value="Unfocused"/> | ||
| <Setter Property="BorderColor" Value="Lime"/> | ||
| <Setter Property="Margin" Value="0"/> | ||
| </VisualState.Setters> | ||
| </VisualState> | ||
| </VisualStateGroup> | ||
| </VisualStateGroupList> | ||
| </Setter> | ||
| </Style> | ||
| </VerticalStackLayout.Resources> | ||
|
|
||
| <Button x:Name="button1" AutomationId="button1" Clicked="OnButtonClicked" /> | ||
|
|
||
| <Button x:Name="button2" AutomationId="button2" Clicked="OnButtonClicked" IsEnabled="False" /> | ||
|
|
||
| <Button x:Name="button3" AutomationId="button3" Clicked="OnButtonClicked" /> | ||
|
|
||
| </VerticalStackLayout> | ||
|
|
||
| </ContentPage> | ||
29 changes: 29 additions & 0 deletions
29
src/Controls/tests/TestCases.HostApp/Issues/Issue19752.xaml.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Collections.ObjectModel; | ||
| using System.ComponentModel; | ||
| using System.Runtime.CompilerServices; | ||
| using System.Windows.Input; | ||
| using System.Collections.Specialized; | ||
|
|
||
| namespace Maui.Controls.Sample.Issues | ||
|
kubaflo marked this conversation as resolved.
|
||
| { | ||
| [XamlCompilation(XamlCompilationOptions.Compile)] | ||
| [Issue(IssueTracker.Github, 19752, "Button does not behave properly when pointer hovers over the button because it's in focused state.")] | ||
| public partial class Issue19752 | ||
|
|
||
| { | ||
|
Comment on lines
+5
to
+8
|
||
| public Issue19752() | ||
| { | ||
| InitializeComponent(); | ||
| } | ||
|
|
||
| private void OnButtonClicked(object sender, EventArgs e) | ||
| { | ||
| // this code just enables all the buttons and disables the current one | ||
| // except for the first button which is always enabled | ||
|
|
||
| button2.IsEnabled = sender != button2; | ||
| button3.IsEnabled = sender != button3; | ||
| } | ||
| } | ||
| } | ||
125 changes: 125 additions & 0 deletions
125
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19752.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| using NUnit.Framework; | ||
| using UITest.Appium; | ||
| using UITest.Core; | ||
|
|
||
| namespace Microsoft.Maui.TestCases.Tests.Issues; | ||
|
|
||
| [Category(UITestCategories.Focus)] | ||
| public class Issue19752(TestDevice device) : _IssuesUITest(device) | ||
| { | ||
| public override string Issue => "Button does not behave properly when pointer hovers over the button because it's in focused state."; | ||
|
|
||
| protected override bool ResetAfterEachTest => true; | ||
|
|
||
| [Test] | ||
| public void InitialStateAreAllCorrect() | ||
|
Comment on lines
+52
to
+53
|
||
| { | ||
|
Comment on lines
+52
to
+54
Comment on lines
+52
to
+54
Comment on lines
+52
to
+54
|
||
| Assert.That(App.FindElement("button1").GetText(), Is.EqualTo("Normal")); | ||
| Assert.That(App.FindElement("button2").GetText(), Is.EqualTo("Disabled")); | ||
| Assert.That(App.FindElement("button3").GetText(), Is.EqualTo("Normal")); | ||
|
kubaflo marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| [Test] | ||
| public void HoveringOverButtonMovesToPointerOverState() | ||
| { | ||
| App.MoveCursor("button1"); | ||
|
|
||
| // when the mouse moves over a button, it gets a state | ||
| Assert.That(App.FindElement("button1").GetText(), Is.EqualTo("PointerOver")); | ||
|
kubaflo marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| // TODO: find a way to send actions to appium and then read values simultaneously | ||
| // [Test] | ||
| // public void PressingButtonMovesToPressedState() | ||
| // { | ||
| // Task.Run(() => | ||
| // { | ||
| //#if MACCATALYST | ||
| // App.LongPress("button1"); | ||
| //#else | ||
| // App.TouchAndHold("button1"); | ||
| //#endif | ||
| // }); | ||
|
|
||
| // // pressing and holding the mouse is pressed | ||
| // App.WaitForTextToBePresentInElement("button1", "Pressed"); | ||
| // Assert.That(App.FindElement("button1").GetText(), Is.EqualTo("Pressed")); | ||
| // } | ||
|
|
||
|
Comment on lines
+75
to
+92
Comment on lines
+75
to
+92
Comment on lines
+75
to
+92
|
||
| [Test] | ||
| public void PressingAndReleasingButtonMovesToPointerOverState() | ||
| { | ||
| var rectBefore = App.FindElement("button1").GetRect(); | ||
|
|
||
|
|
||
| App.Tap("button1"); | ||
|
Comment on lines
+99
to
+101
|
||
|
|
||
| // pressing a button sets it to be focused, but the pointer over state is appplied after | ||
|
kubaflo marked this conversation as resolved.
Outdated
|
||
| Assert.That(App.FindElement("button1").GetText(), Is.EqualTo("PointerOver")); | ||
|
|
||
| // we are shrinking the focused button a bit | ||
| var rectAfter = App.FindElement("button1").GetRect(); | ||
|
Comment on lines
+99
to
+107
|
||
| Assert.That(rectBefore, Is.Not.EqualTo(rectAfter)); | ||
| } | ||
|
|
||
| [Test] | ||
| public void HoveringOverButtonAndThenMovingOffMovesToNormalState() | ||
| { | ||
| var rectBefore = App.FindElement("button1").GetRect(); | ||
|
|
||
|
|
||
|
Comment on lines
+120
to
+121
|
||
| App.MoveCursor("button1"); | ||
| App.MoveCursor("button2"); | ||
|
|
||
| // hovering over a button and then moving off goes back to the normal state | ||
| // and does not affect focus | ||
| Assert.That(App.FindElement("button1").GetText(), Is.EqualTo("Normal")); | ||
|
|
||
| // we are shrinking the focused button a bit, but the button is still not focused | ||
| var rectAfter = App.FindElement("button1").GetRect(); | ||
|
|
||
| Assert.That(rectBefore, Is.EqualTo(rectAfter)); | ||
|
Comment on lines
+120
to
+131
|
||
| } | ||
|
Comment on lines
+130
to
+132
|
||
|
|
||
| [Test] | ||
| public void EnablingButtonMovesToNormalState() | ||
| { | ||
| App.Tap("button1"); | ||
|
|
||
| // enabling a button just switches to the normal state | ||
| Assert.That(App.FindElement("button2").GetText(), Is.EqualTo("Normal")); | ||
| } | ||
|
|
||
| [Test] | ||
| public void DisablingUnfocusedButtonMovesToDisabledState() | ||
| { | ||
| var rectBefore = App.FindElement("button2").GetRect(); | ||
|
|
||
|
|
||
|
Comment on lines
+152
to
+153
|
||
| App.Tap("button1"); // focus button 1 | ||
| App.Tap("button2"); // move the focus to button 2, but then disable it | ||
|
|
||
| // the button is disabled without a focus chnage as it never had focus | ||
|
kubaflo marked this conversation as resolved.
Outdated
|
||
| Assert.That(App.FindElement("button2").GetText(), Is.EqualTo("Disabled")); | ||
|
|
||
| // we are shrinking the focused button a bit, but the button never had focus | ||
| var rectAfter = App.FindElement("button2").GetRect(); | ||
|
|
||
| Assert.That(rectBefore, Is.EqualTo(rectAfter)); | ||
|
Comment on lines
+152
to
+162
|
||
|
|
||
|
Comment on lines
+161
to
+163
|
||
| // this forces focus to button 3 which is set on top of the normal state | ||
| Assert.That(App.FindElement("button3").GetText(), Is.EqualTo("Focused")); | ||
| } | ||
|
|
||
| [Test] | ||
| public void DisablingFocusedButtonMovesToDisabledState() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if my setup is wrong but I tried to run this test on Windows and I got: Details
(I rebased on the latest |
||
| { | ||
| var rectBefore = App.FindElement("button3").GetRect(); | ||
|
|
||
|
|
||
|
Comment on lines
+177
to
+178
|
||
| App.Tap("button1"); // focus button 1 | ||
| App.Tap("button2"); // move the focus to button 2, but then disable it forcing focus to button 3 | ||
| App.Tap("button3"); // disable the focused button | ||
|
|
||
| // this disables the button, but the unfocus change is applied before all states | ||
| Assert.That(App.FindElement("button3").GetText(), Is.EqualTo("Disabled")); | ||
|
|
||
| // we are shrinking the focused button a bit, so it should have been unfocused after disabling | ||
| var rectAfter = App.FindElement("button3").GetRect(); | ||
|
|
||
| Assert.That(rectBefore, Is.EqualTo(rectAfter)); | ||
|
Comment on lines
+187
to
+188
Comment on lines
+177
to
+188
|
||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.