单选按钮

单选按钮(也称为选项按钮)允许用户从两个或更多相互排斥但相关的选项集合中进行选择。 单选按钮总是成组使用,并且每个选项由组中的一个单选按钮表示。

在默认状态下,RadioButtons 组中没有任何单选按钮被选中。 也就是说,所有单选按钮都被清除。 但是,一旦用户选择了单选按钮,用户将无法取消选择该按钮以将组还原到其初始清除状态。

RadioButtons 组的奇异行为将其与 复选框区分开来,这些复选框支持多选和取消选择或清除。

RadioButtons 组的示例,其中选择了一个单选按钮

这是正确的控制吗?

使用单选按钮让用户从两个或多个互斥的选项中选择一个。

一个单选按钮组,已选择其中的一个单选按钮

当用户在做出选择之前需要查看所有选项时,请使用单选按钮。 单选按钮同样强调所有选项,这意味着某些选项可能会引起比必要或所需更多的关注。

除非所有选项都值得同等关注,否则请考虑使用其他控件。 例如,若要推荐大多数用户和大多数情况下的最佳选项,请使用 组合框 将最佳选项显示为默认选项。

组合框,显示默认选项

如果只有两个可能的选项可以明确表示为单个二进制选项,例如 on/off 或 yes/no,请将它们合并为单个 复选框,切换开关 控件。 例如,对“我同意”使用单个复选框,而不是“我同意”和“我不同意”的两个单选按钮。

不要使用两个单选按钮来实现一个简单的二选一选项。

两个用于呈现二元选择的单选按钮

改用复选框:

复选框是演示二进制选择 的一个不错的选择

当用户可以选择多个选项时,请使用 复选框

复选框支持多选

当用户的选项在某个值范围内时(例如,10,20,30...100),应使用 滑块控件

滑块控件,在一系列值中显示一个值

如果选项超过八个,请使用 组合框

列表框,显示多个选项

如果可用选项基于应用的当前上下文,或者它们可能动态变化,请使用列表控件。

建议

  • 确保明确说明一组单选按钮的用途和当前状态。
  • 将单选按钮的文本标签限制为单行。
  • 如果文本标签是动态的,请考虑按钮如何自动调整大小,以及它周围的任何视觉对象会发生什么情况。
  • 除非品牌准则告诉你,否则请使用默认字体。
  • 不要并排放置两个 RadioButtons 组。 当两个 RadioButtons 组彼此相邻时,用户很难确定哪些按钮属于哪个组。

RadioButtons 概述

RadioButtons 与 RadioButton

有两种方法可以创建单选按钮组:RadioButtons 和 RadioButton。

  • 建议使用 RadioButtons 控件。 此控件简化了布局、处理键盘导航和辅助功能,并支持绑定到数据源。
  • 可以使用单个 RadioButton 控件组。

键盘访问和导航行为已在 RadioButtons 控件中进行了优化。 这些改进帮助了辅助功能用户和键盘高级用户,让他们更快、更容易地浏览选项列表。

除了这些改进之外,RadioButtons 组中单个单选按钮的默认视觉布局也通过自动化的排版、间距和边距设置得到了优化。 这种优化使得不再需要指定这些属性,因为在使用较原始的分组控件(如 StackPanelGrid)时,您可能需要这样做。

RadioButtons 控件具有特殊的导航行为,可帮助键盘用户更快、更轻松地导航列表。

键盘焦点

RadioButtons 控件支持两种状态:

  • 未选择单选按钮
  • 已选择一个单选按钮

后续部分介绍每个状态中控件的焦点行为。

未选择单选按钮

如果未选择单选按钮,列表中的第一个单选按钮将获得焦点。

注释

在起始选项卡导航中获得焦点的项目未被选择。

没有选项卡焦点的列表,没有选择

无标签页焦点的列表,且无选中项目

具有初始选项卡焦点但没有选择的列表

具有初始选项卡焦点且无选定项目的列表

已选择一个单选按钮

当用户通过按下Tab键进入已经选中单选按钮的列表时,所选的单选按钮会获得焦点。

不带选项卡焦点的列表

没有选项卡焦点的列表和所选项目

具有初始选项卡焦点的列表

附带初始选项卡焦点和已选择项目的列表

键盘导航

有关常规键盘导航行为的详细信息,请参阅 键盘交互 - 导航

RadioButtons 组中的项已具有焦点时,用户可以在组中的项之间使用箭头键进行“内部导航”。 上下箭头键会移动到 XAML 标记中定义的“下一个”或“上一个”逻辑项。 左右方向键用于空间移动。

在单列或单行布局中,键盘导航会导致以下行为:

单列

单列 RadioButtons 组中的键盘导航示例

向上键和向下键在项之间移动。
向左键和向右键不执行任何操作。

单行

单行 RadioButtons 组中的键盘导航示例

向左键和向上键移动到上一项,向右键和向下键移动到下一项。

在多列多行网格布局中,键盘导航会导致此行为:

左/右方向键

在多列/多行 RadioButtons 组中使用键盘水平导航的示例

左右箭头键在一行中的项目之间水平移动焦点。

水平键盘导航示例,焦点位于列 的最后一项

当焦点位于列中的最后一个项目上并且按下向右键或向左键时,焦点将移动到下一列或上一列中的最后一项(如果有)。

向上/向下键

多列/行单选按钮组中垂直键盘导航的示例

上下箭头键可在列中的项目间垂直移动焦点。

以在列中最后一项聚焦的垂直键盘导航示例

当焦点位于列中的最后一个项目并且按下向下键时,焦点将移动到下一列中的第一个项目(如果有)。 当焦点位于列中的第一个项目并按下向上键时,焦点将移动到上一列中的最后一项(如果有)

有关详细信息,请参阅 键盘交互

包装

RadioButtons 组不会将焦点从第一行或列换到最后一行或从最后一行或列换到第一行。 这是因为,当用户使用屏幕阅读器时,边界感和开始和结束的明确指示会丢失,这使得视觉障碍的用户难以导航列表。

RadioButtons 控件也不支持枚举,因为控件旨在包含合理数量的项(请参阅 这是正确的控件吗?)。

焦点跟随选择

使用键盘在 RadioButtons 组中的项目之间导航时,焦点从一个项目移动到下一个项目时,将选中新聚焦的项目并清除以前聚焦的项目。

在键盘导航 之前

键盘导航前的焦点和选择示例

键盘导航前的焦点和选择。

键盘导航后

键盘导航后的焦点和选择示例

键盘导航后的焦点和选择,向下键将焦点移动到单选按钮 3,选择它,并清除单选按钮 2。

可以使用 Ctrl+箭头键进行导航,无需更改所选内容即可移动焦点。 移动焦点后,可以使用空格键选择当前具有焦点的项目。

如果使用游戏手柄或遥控器在单选按钮之间移动,“选择跟随焦点”行为将被禁用,用户必须按“A”按钮来选择当前具有焦点的单选按钮。

辅助功能行为

下表介绍了讲述人如何处理 RadioButtons 组以及宣布的内容。 此行为取决于用户如何设置讲述人详细信息首选项。

行动 解说员公告
焦点移动到所选项目 名称,RadioButton,已选中,xN
焦点移动到未选择的项目
(如果使用 Ctrl 箭头键或 Xbox 游戏板进行导航,
表示选择没有跟随焦点。
名称,RadioButton,非选定,xN

注释

讲述人为每个项目宣布的 名称AutomationProperties.Name 附加属性的值(如果该项有此属性可用);否则,则是该项目的 ToString 方法所返回的值。

x 是当前项的数目。 N 是组中的项总数。

创建 WinUI RadioButtons 组

WinUI 3 示例集应用程序包括大多数 WinUI 3 控件、特性和功能的交互式示例。 通过 Microsoft Store 获取应用,或在 GitHub 上获取源代码

RadioButtons 控件使用类似于 ItemsControl的内容模型。 这意味着你可以:

在这里,你将使用三个选项声明一个简单的 RadioButtons 控件。 Header 属性设置为为组提供标签,SelectedIndex 属性设置为提供默认选项。

<RadioButtons Header="Background color"
              SelectedIndex="0"
              SelectionChanged="BackgroundColor_SelectionChanged">
    <x:String>Red</x:String>
    <x:String>Green</x:String>
    <x:String>Blue</x:String>
</RadioButtons>

结果如下所示:

一组三个单选按钮

若要在用户选择某个选项时执行操作,请处理 SelectionChanged 事件。 在这里,将更改名为“ExampleBorder”()的 <Border x:Name="ExampleBorder" Width="100" Height="100"/> 元素的背景色。

private void BackgroundColor_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (ExampleBorder != null && sender is RadioButtons rb)
    {
        string colorName = rb.SelectedItem as string;
        switch (colorName)
        {
            case "Red":
                ExampleBorder.Background = new SolidColorBrush(Colors.Red);
                break;
            case "Green":
                ExampleBorder.Background = new SolidColorBrush(Colors.Green);
                break;
            case "Blue":
                ExampleBorder.Background = new SolidColorBrush(Colors.Blue);
                break;
        }
    }
}

小窍门

还可以从 SelectionChangedEventArgs.AddedItems 属性中获取所选项目。 索引 0 处只有一个选定项,因此你可以获取如下所示的选定项:string colorName = e.AddedItems[0] as string;

选择状态

单选按钮有两种状态:已选中或清除。 在 RadioButtons 组中选择某个选项时,可以从 SelectedItem 属性获取其值,并可以从 选定索引 属性中获取其在集合中的位置。 如果用户在同一组中选择另一个单选按钮,那么该单选按钮可以被清除;但如果用户再次选择同一个单选按钮,则无法清除。 但是,可以通过编程设置为 SelectedItem = nullSelectedIndex = -1来清除单选按钮组。 (将 SelectedIndex 设置为 Items 集合范围之外的任何值将导致无选择。

RadioButtons 内容

在前面的示例中,使用简单字符串填充了 RadioButtons 控件。 该控件提供了单选按钮,并使用字符串作为每个按钮的标签。

但是,可以使用任何对象填充 RadioButtons 控件。 通常,你希望对象提供可用作文本标签的字符串表示形式。 在某些情况下,图像可能适合代替文本。

在这里,SymbolIcon 元素用于填充控件。

<RadioButtons Header="Select an icon option:">
    <SymbolIcon Symbol="Back"/>
    <SymbolIcon Symbol="Attach"/>
    <SymbolIcon Symbol="HangUp"/>
    <SymbolIcon Symbol="FullScreen"/>
</RadioButtons>

具有符号图标的组单选按钮

还可以使用单独的 RadioButton 控件填充 RadioButtons 项。 这是我们稍后讨论的一个特殊情况。 请参阅RadioButtons 组中的 RadioButton 控件。

能够使用任何对象的好处是可以将 RadioButtons 控件绑定到数据模型中的自定义类型。 下一部分演示了这一点。

数据绑定

RadioButtons 控件支持将数据绑定到其 ItemsSource 属性。 此示例演示如何将控件绑定到自定义数据源。 此示例的外观和功能与前面的背景色示例相同,但在这里,颜色画笔存储在数据模型中,而不是在 SelectionChanged 事件处理程序中创建。

<RadioButtons Header="Background color"
              SelectedIndex="0"
              SelectionChanged="BackgroundColor_SelectionChanged"
              ItemsSource="{x:Bind colorOptionItems}"/>
public sealed partial class MainPage : Page
{
    // Custom data item.
    public class ColorOptionDataModel
    {
        public string Label { get; set; }
        public SolidColorBrush ColorBrush { get; set; }

        public override string ToString()
        {
            return Label;
        }
    }

    List<ColorOptionDataModel> colorOptionItems;

    public MainPage1()
    {
        this.InitializeComponent();

        colorOptionItems = new List<ColorOptionDataModel>();
        colorOptionItems.Add(new ColorOptionDataModel()
            { Label = "Red", ColorBrush = new SolidColorBrush(Colors.Red) });
        colorOptionItems.Add(new ColorOptionDataModel()
            { Label = "Green", ColorBrush = new SolidColorBrush(Colors.Green) });
        colorOptionItems.Add(new ColorOptionDataModel()
            { Label = "Blue", ColorBrush = new SolidColorBrush(Colors.Blue) });
    }

    private void BackgroundColor_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var option = e.AddedItems[0] as ColorOptionDataModel;
        ExampleBorder.Background = option?.ColorBrush;
    }
}

RadioButtons 组中的 RadioButton 控件

可以使用单个 RadioButton 控件来填充 RadioButtons 项。 为了做到这一点,你可以访问某些属性,例如 AutomationProperties.Name,或者你可能已有 RadioButton 代码,但想要利用 RadioButtons的布局和导航功能。

<RadioButtons Header="Background color">
    <RadioButton Content="Red" Tag="red" AutomationProperties.Name="red"/>
    <RadioButton Content="Green" Tag="green" AutomationProperties.Name="green"/>
    <RadioButton Content="Blue" Tag="blue" AutomationProperties.Name="blue"/>
</RadioButtons>

RadioButton 组中使用 RadioButtons 控件时,RadioButtons 控件知道如何呈现 RadioButton,因此不会出现两个选择环的情况。

但是,应注意某些行为。 建议在单个控件上或在 RadioButtons上处理状态和事件,但不要同时处理两者,以避免冲突。

此表显示这两个控件上的相关事件和属性。

RadioButton RadioButtons
选中的未选中的单击 选择更改
IsChecked 选定项选定索引

如果处理单个 RadioButton上的事件(例如 CheckedUnchecked),并且同时处理 RadioButtons.SelectionChanged 事件,则这两类事件都会被触发。 首先发生 RadioButton 事件,然后发生 RadioButtons.SelectionChanged 事件,这可能会导致冲突。

IsCheckedSelectedItemSelectedIndex 属性保持同步。 对一个属性的更改会更新另一个属性。

忽略 RadioButton.GroupName 属性。 组由 RadioButtons 控件创建。

定义多个列

默认情况下,RadioButtons 控件垂直排列其单选按钮于单列中。 你可以设置 MaxColumns 属性,以便让控件将单选按钮排列在多个列中。 执行此操作时,它们按列优先顺序排列,项目从上到下填充,然后从左到右排列。

<RadioButtons Header="RadioButtons in columns" MaxColumns="3">
    <x:String>Item 1</x:String>
    <x:String>Item 2</x:String>
    <x:String>Item 3</x:String>
    <x:String>Item 4</x:String>
    <x:String>Item 5</x:String>
    <x:String>Item 6</x:String>
</RadioButtons>

在两个三列组中包含的 单选按钮

小窍门

若要将项目排列在单个水平行中,请将 MaxColumns 设置为等于组中的项数。

创建自己的 RadioButton 组

重要

建议使用 RadioButtons 控件对 RadioButton 元素进行分组。

单选按钮在组中工作。 可以通过以下两种方式之一对单个 RadioButton 控件进行分组:

  • 将它们放在同一个父容器中。
  • 将每个单选按钮上的 GroupName 属性设置为相同的值。

在此示例中,第一组单选按钮由于位于同一堆栈面板内而被隐式分组。 第二个组分为两个堆栈面板,因此 GroupName 用于将它们显式分组为单个组。

<StackPanel>
    <StackPanel>
        <TextBlock Text="Background" Style="{ThemeResource BaseTextBlockStyle}"/>
        <!-- Group 1 - implicit grouping -->
        <StackPanel Orientation="Horizontal">
            <RadioButton Content="Green" Tag="green" Checked="BGRadioButton_Checked"/>
            <RadioButton Content="Yellow" Tag="yellow" Checked="BGRadioButton_Checked"/>
            <RadioButton Content="White" Tag="white" Checked="BGRadioButton_Checked"
                         IsChecked="True"/>
        </StackPanel>
    </StackPanel>

    <StackPanel>
        <TextBlock Text="BorderBrush" Style="{ThemeResource BaseTextBlockStyle}"/>
        <!-- Group 2 - grouped by GroupName -->
        <StackPanel Orientation="Horizontal">
            <StackPanel>
                <RadioButton Content="Green" Tag="green" GroupName="BorderBrush"
                             Checked="BorderRadioButton_Checked"/>
                <RadioButton Content="Yellow" Tag="yellow" GroupName="BorderBrush"
                             Checked="BorderRadioButton_Checked" IsChecked="True"/>
                <RadioButton Content="White" Tag="white"  GroupName="BorderBrush"
                             Checked="BorderRadioButton_Checked"/>
            </StackPanel>
        </StackPanel>
    </StackPanel>
    <Border x:Name="ExampleBorder"
            BorderBrush="#FFFFD700" Background="#FFFFFFFF"
            BorderThickness="10" Height="50" Margin="0,10"/>
</StackPanel>
private void BGRadioButton_Checked(object sender, RoutedEventArgs e)
{
    RadioButton rb = sender as RadioButton;

    if (rb != null && ExampleBorder != null)
    {
        string colorName = rb.Tag.ToString();
        switch (colorName)
        {
            case "yellow":
                ExampleBorder.Background = new SolidColorBrush(Colors.Yellow);
                break;
            case "green":
                ExampleBorder.Background = new SolidColorBrush(Colors.Green);
                break;
            case "white":
                ExampleBorder.Background = new SolidColorBrush(Colors.White);
                break;
        }
    }
}

private void BorderRadioButton_Checked(object sender, RoutedEventArgs e)
{
    RadioButton rb = sender as RadioButton;

    if (rb != null && ExampleBorder != null)
    {
        string colorName = rb.Tag.ToString();
        switch (colorName)
        {
            case "yellow":
                ExampleBorder.BorderBrush = new SolidColorBrush(Colors.Gold);
                break;
            case "green":
                ExampleBorder.BorderBrush = new SolidColorBrush(Colors.DarkGreen);
                break;
            case "white":
                ExampleBorder.BorderBrush = new SolidColorBrush(Colors.White);
                break;
        }
    }
}

这两组 RadioButton 控件如下所示:

两个组中的单选按钮

单选按钮状态

单选按钮有两种状态:已选中或清除。 选择单选按钮时,其 IsChecked 属性被设定为 true。 清除单选按钮时,其 IsChecked 属性 false。 如果用户在同一组中选择另一个单选按钮,那么该单选按钮可以被清除;但如果用户再次选择同一个单选按钮,则无法清除。 但是,可以通过以编程方式将单选按钮的 IsChecked 属性设置为 false来清除它。

要考虑的视觉元素

单个 RadioButton 控件的默认间距不同于 RadioButtons 组提供的间距。 若要将 RadioButtons 间距应用于单个 RadioButton 控件,请将 Margin 值设为 0,0,7,3,如下所示。

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="RadioButton">
            <Setter Property="Margin" Value="0,0,7,3"/>
        </Style>
    </StackPanel.Resources>
    <TextBlock Text="Background"/>
    <RadioButton Content="Item 1"/>
    <RadioButton Content="Item 2"/>
    <RadioButton Content="Item 3"/>
</StackPanel>

以下图像展示了组中单选按钮的首选间距。

显示一组单选按钮的图像,垂直排列

图像显示单选按钮的间距准则

注释

如果使用 WinUI RadioButtons 控件,则间距、边距和方向已得到优化。

UWP 和 WinUI 2

重要

本文中的信息和示例是针对使用 Windows App SDKWinUI 3 的应用优化的,但通常适用于使用 WinUI 2 的 UWP 应用。 有关特定于平台的信息和示例,请参阅 UWP API 参考。

本部分包含在 UWP 或 WinUI 2 应用中使用该控件所需的信息。

UWP 应用的 RadioButtons 控件包含在 WinUI 2 中。 有关详细信息(包括安装说明),请参阅 WinUI 2。 这些控件的 API 存在于 Windows.UI.Xaml.ControlsMicrosoft.UI.Xaml.Controls 命名空间中。

可通过两种方式创建单选按钮组。

  • 从 WinUI 2.3 开始,我们建议使用 RadioButtons 控件。 此控件简化了布局、处理键盘导航和辅助功能,并支持绑定到数据源。
  • 可以使用单个 RadioButton 控件组。 如果你的应用不使用 WinUI 2.3 或更高版本,则这是唯一的选项。

建议使用最新的 WinUI 2 来获取所有控件的最新样式和模板。

若要将本文中的代码与 WinUI 2 配合使用,请使用 XAML 中的别名(我们使用 muxc)来表示项目中包括的 Windows UI 库 API。 有关详细信息,请参阅 WinUI 2 入门

xmlns:muxc="using:Microsoft.UI.Xaml.Controls"

<muxc:RadioButtons />