Skip to content

Commit

Permalink
RadioButtons: Fix selected radio button not being focused on tab navi…
Browse files Browse the repository at this point in the history
…gation when first element in TAB navigation (microsoft/microsoft-ui-xaml#3048)
  • Loading branch information
Kinnara committed Aug 16, 2020
1 parent 01d2d98 commit ba20188
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 2 deletions.
1 change: 0 additions & 1 deletion ModernWpf.Controls/RadioButtons/RadioButtons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ public override void OnApplyTemplate()
UpdateItemsSource();
}

// void OnGettingFocus(object sender, GettingFocusEventArgs args);
// When focus comes from outside the RadioButtons control we will put focus on the selected radio button.
protected override void OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs args)
{
Expand Down
29 changes: 29 additions & 0 deletions test/ModernWpfTestApp/RadioButtonsCaseBundle.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. See LICENSE in the project root for license information. -->
<local:TestPage
x:Class="RadioButtons_TestUI.RadioButtonsCaseBundle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MUXControlsTestApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<WrapPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Orientation="Horizontal">
<WrapPanel.Resources>
<Style TargetType="StackPanel">
<Setter Property="Margin" Value="4"/>
<Setter Property="MaxWidth" Value="400" />
<Setter Property="MinWidth" Value="200" />
</Style>
</WrapPanel.Resources>

<StackPanel>
<TextBlock Text="Common Tests"/>
<Button x:Name="RadioButtonsPage" AutomationProperties.Name="RadioButtons Test" Margin="2" HorizontalAlignment="Stretch">RadioButtons Test</Button>
<TextBlock Text="Special Tests" />
<Button x:Name="RadioButtonsFocusPage" AutomationProperties.Name="RadioButtonsFocus Test" Margin="2" HorizontalAlignment="Stretch">RadioButtons Focus Test</Button>
</StackPanel>
</WrapPanel>
</local:TestPage>
19 changes: 19 additions & 0 deletions test/ModernWpfTestApp/RadioButtonsCaseBundle.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using MUXControlsTestApp;

namespace RadioButtons_TestUI
{
[TopLevelTestPage(Name = "RadioButtons", Icon = "RadioButton.png")]
public sealed partial class RadioButtonsCaseBundle : TestPage
{
public RadioButtonsCaseBundle()
{
this.InitializeComponent();

RadioButtonsPage.Click += delegate { Frame.NavigateWithoutAnimation(typeof(RadioButtonsPage), 0); };
RadioButtonsFocusPage.Click += delegate { Frame.NavigateWithoutAnimation(typeof(RadioButtonsFocusPage), 0); };
}
}
}
125 changes: 125 additions & 0 deletions test/ModernWpfTestApp/RadioButtonsFocusPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. See LICENSE in the project root for license information. -->
<local:TestPage
x:Class="RadioButtons_TestUI.RadioButtonsFocusPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:MUXControlsTestApp"
xmlns:controls="http://schemas.modernwpf.com/2019"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

<!-- RadioButtons test group 1 -->
<controls:RadioButtons x:Name="TestRadioButtons1" Grid.Row="0" Grid.Column="0"
Header="TestRadioButtons"
SelectionChanged="TestRadioButtons_SelectionChanged"
GotFocus="TestRadioButtons_GotFocus"
LostFocus="TestRadioButtons_LostFocus">
<sys:String>Item 1</sys:String>
<sys:String>Item 2</sys:String>
<sys:String>Item 3</sys:String>
</controls:RadioButtons>

<!-- Selected Index/Item and focus info UI -->
<Grid Grid.Row="0" Grid.Column="1" Margin="10,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<TextBlock Grid.Row="0" Grid.Column="0">Selected Index:</TextBlock>
<TextBlock x:Name="SelectedIndexTextBlock1" AutomationProperties.Name="SelectedIndexTextBlock1" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left">-1</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0">Selected Item:</TextBlock>
<TextBlock x:Name="SelectedItemTextBlock1" AutomationProperties.Name="SelectedItemTextBlock1" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left">null</TextBlock>

<TextBlock Grid.Row="2" Grid.Column="0">Focused Index:</TextBlock>
<TextBlock x:Name="FocusedIndexTextBlock1" AutomationProperties.Name="FocusedIndexTextBlock1" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left">-1</TextBlock>

<TextBlock Grid.Row="3" Grid.Column="0">Has Focus:</TextBlock>
<CheckBox x:Name="TestRadioButtons1HasFocusCheckBox" AutomationProperties.Name="TestRadioButtons1HasFocusCheckBox" Grid.Row="3" Grid.Column="1" IsTabStop="False"/>
</Grid>

<!-- Select by index UI -->
<Grid Grid.Row="0" Grid.Column="2" Margin="10,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0">Index to select:</TextBlock>
<TextBox x:Name="IndexToSelectTextBox1" AutomationProperties.Name="IndexToSelectTextBox1" Grid.Column="1" Text="-1" Margin="5,0,0,0" VerticalAlignment="Top"
IsTabStop="False"/>
<Button x:Name="SelectByIndexButton1" AutomationProperties.Name="SelectByIndexButton1" Grid.Column="2" IsTabStop="False" Click="SelectByIndexButton1_Click"
Margin="5,0,0,0" VerticalAlignment="Top">Select by index</Button>
</Grid>

<!-- RadioButtons test group 2 -->
<controls:RadioButtons x:Name="TestRadioButtons2" Grid.Row="1" Grid.Column="0"
Header="TestRadioButtons2" Margin="0,10,0,0"
SelectionChanged="TestRadioButtons2_SelectionChanged"
GotFocus="TestRadioButtons2_GotFocus"
LostFocus="TestRadioButtons2_LostFocus">
<sys:String>Item 1</sys:String>
<sys:String>Item 2</sys:String>
<sys:String>Item 3</sys:String>
</controls:RadioButtons>

<!-- Selected Index/Item and focus info UI -->
<Grid Grid.Row="1" Grid.Column="1" Margin="10,10,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<TextBlock Grid.Row="0" Grid.Column="0">Selected Index:</TextBlock>
<TextBlock x:Name="SelectedIndexTextBlock2" AutomationProperties.Name="SelectedIndexTextBlock2" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left">-1</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0">Selected Item:</TextBlock>
<TextBlock x:Name="SelectedItemTextBlock2" AutomationProperties.Name="SelectedItemTextBlock2" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left">null</TextBlock>

<TextBlock Grid.Row="2" Grid.Column="0">Focused Index:</TextBlock>
<TextBlock x:Name="FocusedIndexTextBlock2" AutomationProperties.Name="FocusedIndexTextBlock2" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left">-1</TextBlock>

<TextBlock Grid.Row="3" Grid.Column="0">Has Focus:</TextBlock>
<CheckBox x:Name="TestRadioButtons2HasFocusCheckBox" AutomationProperties.Name="TestRadioButtons2HasFocusCheckBox" Grid.Row="3" Grid.Column="1" IsTabStop="False"/>
</Grid>

<!-- Select by index UI -->
<Grid Grid.Row="1" Grid.Column="2" Margin="10,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0">Index to select:</TextBlock>
<TextBox x:Name="IndexToSelectTextBox2" AutomationProperties.Name="IndexToSelectTextBox2" Grid.Column="1" Margin="5,0,0,0" VerticalAlignment="Top" Text="-1"
IsTabStop="False"/>
<Button x:Name="SelectByIndexButton2" AutomationProperties.Name="SelectByIndexButton2" Grid.Column="2" IsTabStop="False" Click="SelectByIndexButton2_Click"
Margin="5,0,0,0" VerticalAlignment="Top">Select by index</Button>
</Grid>
</Grid>
</local:TestPage>
136 changes: 136 additions & 0 deletions test/ModernWpfTestApp/RadioButtonsFocusPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using ModernWpf.Controls;
using MUXControlsTestApp;
using System;
using System.Windows;
using System.Windows.Media;

namespace RadioButtons_TestUI
{
public sealed partial class RadioButtonsFocusPage : TestPage
{
public RadioButtonsFocusPage()
{
this.InitializeComponent();

Loaded += OnLoaded;
}

private void OnLoaded(object sender, RoutedEventArgs e)
{
ChangeTestFrameVisibility(Visibility.Collapsed);
}

private void ChangeTestFrameVisibility(Visibility visibility)
{
var testFrame = WindowEx.Current.Content as TestFrame;
testFrame.ChangeBarVisibility(visibility);
}

private void TestRadioButtons_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
var index = TestRadioButtons1.SelectedIndex;
SelectedIndexTextBlock1.Text = index.ToString();
if (TestRadioButtons1.SelectedItem != null)
{
SelectedItemTextBlock1.Text = TestRadioButtons1.SelectedItem.ToString();
}
else
{
SelectedItemTextBlock1.Text = "null";
}

}

private void TestRadioButtons2_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
var index = TestRadioButtons2.SelectedIndex;
SelectedIndexTextBlock2.Text = index.ToString();
if (TestRadioButtons2.SelectedItem != null)
{
SelectedItemTextBlock2.Text = TestRadioButtons2.SelectedItem.ToString();
}
else
{
SelectedItemTextBlock2.Text = "null";
}

}

private void TestRadioButtons_GotFocus(object sender, RoutedEventArgs e)
{
var stackPanel = VisualTreeHelper.GetChild(TestRadioButtons1, 0);
var repeater = (ItemsRepeater)VisualTreeHelper.GetChild(stackPanel, 1);
FocusedIndexTextBlock1.Text = repeater.GetElementIndex((UIElement)e.OriginalSource).ToString();
TestRadioButtons1HasFocusCheckBox.IsChecked = true;
}

private void TestRadioButtons_LostFocus(object sender, RoutedEventArgs e)
{
FocusedIndexTextBlock1.Text = "-1";
TestRadioButtons1HasFocusCheckBox.IsChecked = false;
}

private void TestRadioButtons2_GotFocus(object sender, RoutedEventArgs e)
{
var stackPanel = VisualTreeHelper.GetChild(TestRadioButtons2, 0);
var repeater = (ItemsRepeater)VisualTreeHelper.GetChild(stackPanel, 1);
FocusedIndexTextBlock2.Text = repeater.GetElementIndex((UIElement)e.OriginalSource).ToString();
TestRadioButtons2HasFocusCheckBox.IsChecked = true;
}

private void TestRadioButtons2_LostFocus(object sender, RoutedEventArgs e)
{
FocusedIndexTextBlock2.Text = "-1";
TestRadioButtons2HasFocusCheckBox.IsChecked = false;
}

private void SelectByIndexButton1_Click(object sender, RoutedEventArgs e)
{
var index = getIndexToSelect(false);
if (index != -2)
{
TestRadioButtons1.SelectedIndex = index;
}
}

private void SelectByIndexButton2_Click(object sender, RoutedEventArgs e)
{
var index = getIndexToSelect(true);
if (index != -2)
{
TestRadioButtons2.SelectedIndex = index;
}
}

private int getIndexToSelect(bool selectRadioButtons2)
{
int value;
bool success;
if (selectRadioButtons2)
{
success = Int32.TryParse(IndexToSelectTextBox2.Text, out value);
}
else
{
success = Int32.TryParse(IndexToSelectTextBox1.Text, out value);
}

if (success)
{
if (value >= 3)
{
return 1;
}
if (value < -1)
{
return -2;
}
return value;
}
return -2;
}
}
}
1 change: 0 additions & 1 deletion test/ModernWpfTestApp/RadioButtonsPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

namespace MUXControlsTestApp
{
[TopLevelTestPage(Name = "RadioButtons", Icon = "RadioButton.png")]
public sealed partial class RadioButtonsPage : TestPage
{
ObservableCollection<string> m_stringItemCollection;
Expand Down

0 comments on commit ba20188

Please sign in to comment.