组合框和列表框

使用组合框(也称下拉列表)可提供一个项列表供用户选择。 组合框最初处于紧凑状态,可展开以显示可选择项的列表。 列表框类似于组合框,但不可折叠,也没有紧凑状态。 可以在本文末尾详细了解列表框。

组合框在关闭后,会显示当前的选择或为空(如果没有选中项)。 当用户展开组合框时,它会显示可选择项的列表。

下拉列表在紧凑状态下的图像。

这是正确的控件吗?

  • 使用下拉列表让用户能从一组项目中选择单个值,这些项目可以用单行文字充分表示。
  • 使用列表或网格视图而不是组合框来显示包含多行文本或图像的项目。
  • 如果项目少于五个,可考虑使用单选按钮(如果只能选择一个项目)或复选框(如果可以选择多个项目)。
  • 当选择项在应用程序流程中处于次要地位时,请使用组合框。 如果大多数用户在大多数情况下都推荐使用默认选项,那么使用列表视图显示所有项 目可能会引起对选项的更多关注,而非必要。 使用组合框可以节省空间并减少干扰。

示例

紧凑状态下的组合框可以显示一个标题。

处于紧凑状态的下拉列表的屏幕截图。

虽然组合框扩展后可支持更长的字符串长度,但应避免字符串过长而难以读取。

包含长文本字符串的下拉列表示例

如果组合框中的集合足够长,就会出现一个滚动条来容纳它。 对列表中的项目进行逻辑分组。

下拉列表中的滚动条示例

建议

  • 将组合框项的文本内容限制为一行。
  • 按最合理的顺序对组合框中的项目进行排序。 将相关选项组合在一起,并将最常见的选项放在最前面。 按字母顺序排列名称,按数字顺序排列数字,按时间顺序排列日期。

列表框

列表框允许用户从一个集合中选择单个或多个项目。 列表框与下拉列表类似,但列表框始终是打开的,没有紧凑(非展开)状态。 如果没有足够的空间显示所有内容,则可以滚动显示列表中的项目。

列表框是合适的控件吗?

  • 当列表中的项目足够重要而需要突出显示,并且屏幕空间足够大,可以显示完整列表时,就会用到列表框。
  • 在重要的选择中,列表框应能引起用户对全部替代项的注意。 相比之下,下拉列表一开始就会吸引用户对所选项目的注意。
  • 避免在以下情况时使用列表框:
    • 列表的项目数量非常少。 如果一个单选列表框总是有相同的 2 个选项,那么用单选按钮来表示可能会更好。 如果列表中有 3 或 4 个静态项目,也可以考虑使用单选按钮。
    • 列表框为单选式且始终具有两个相同选项,其中一个可表示为另一个的对立面,例如“打开”和“关闭”。使用单个复选框或切换开关。
    • 项目数量非常多。 对于长列表,网格视图和列表视图是更好的选择。 对于很长的分组数据列表,最好使用语义缩放。
    • 项目是连续的数值。 如果是这种情况,请考虑使用滑块
    • 在应用程序的流程中,选择项是次要的,或者在大多数情况下建议大多数用户使用默认选项。 请改为使用下拉列表。

关于列表框的建议

  • 列表框中项目的理想范围是 3 到 9 个。
  • 当列表框中的项目可以动态变化时,列表框的效果更好。
  • 如有可能,请设置列表框的大小,使其项目列表无需平移或滚动。
  • 确认列表框的目的以及当前选择的项目是否明确。
  • 为触摸反馈和所选项目状态预留视觉效果和动画。
  • 将列表框项的文本内容限制为一行。 如果项目是视觉效果,则可以自定义大小。 如果项目包含多行文本或图像,请改为使用网格视图或列表视图。
  • 除非品牌准则指示使用其他字体,否则请使用默认字体。
  • 不要使用列表框来执行命令或动态显示或隐藏其他控件。

UWP 和 WinUI 2

重要

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

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

此控件的 API 存在于 Windows.UI.Xaml.Controls 命名空间中。

WinUI 2.2 或更高版本包含此控件的使用圆角的新模板。 有关详细信息,请参阅圆角半径

创建组合框

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

填充组合框时,可以将对象直接添加到集,也可以将 ItemsSource 属性绑定到数据源。 添加到 ComboBox 的项会包装到 ComboBoxItem 容器中。

下面是一个简单的组合框,已在 XAML 中添加项。

<ComboBox Header="Colors" PlaceholderText="Pick a color" Width="200">
    <x:String>Blue</x:String>
    <x:String>Green</x:String>
    <x:String>Red</x:String>
    <x:String>Yellow</x:String>
</ComboBox>

以下示例演示了如何将组合框绑定到 FontFamily 对象的集合。

<ComboBox x:Name="FontsCombo" Header="Fonts" Height="44" Width="296"
          ItemsSource="{x:Bind fonts}" DisplayMemberPath="Source"/>
ObservableCollection<FontFamily> fonts = new ObservableCollection<FontFamily>()
{
    fonts.Add(new FontFamily("Arial"));
    fonts.Add(new FontFamily("Courier New"));
    fonts.Add(new FontFamily("Times New Roman"));
};

项选择

与 ListView 和 GridView 一样,ComboBox 派生自 Selector,因此你可以采用同一标准方式获取用户的选择。

可以通过 SelectedItem 属性获取或设置组合框的所选项,以及通过 SelectedIndex 属性获取或设置所选项的索引。

要获取所选数据项的特定属性的值,可以使用 SelectedValue 属性。 在这种情况下,可以设置 SelectedValuePath,以便指定要从所选项的哪个属性获取值。

提示

如果通过设置 SelectedItem 或 SelectedIndex 来指示默认选择,并且是在填充组合框项集合之前设置该属性,则会出现异常。 除非是在 XAML 中定义项,否则最好是处理组合框的 Loaded 事件,并在 Loaded 事件处理程序中设置 SelectedItem 或 SelectedIndex。

可以在 XAML 中绑定到这些属性,或者通过处理 SelectionChanged 事件来响应选择变化。

在事件处理程序代码中,可以从 SelectionChangedEventArgs.AddedItems 属性获取所选项。 可以从 SelectionChangedEventArgs.RemovedItems 属性获取以前选择的项(如果有)。 AddedItems 和 RemovedItems 集合都只包含 1 个项,因为组合框不支持多选。

此示例显示了如何处理 SelectionChanged 事件,以及如何绑定到所选项。

<StackPanel>
    <ComboBox x:Name="colorComboBox" Width="200"
              Header="Colors" PlaceholderText="Pick a color"
              SelectionChanged="ColorComboBox_SelectionChanged">
        <x:String>Blue</x:String>
        <x:String>Green</x:String>
        <x:String>Red</x:String>
        <x:String>Yellow</x:String>
    </ComboBox>

    <Rectangle x:Name="colorRectangle" Height="30" Width="100"
               Margin="0,8,0,0" HorizontalAlignment="Left"/>

    <TextBlock Text="{x:Bind colorComboBox.SelectedIndex, Mode=OneWay}"/>
    <TextBlock Text="{x:Bind colorComboBox.SelectedItem, Mode=OneWay}"/>
</StackPanel>
private void ColorComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    string colorName = e.AddedItems[0].ToString();
    Color color;
    switch (colorName)
    {
        case "Yellow":
            color = Colors.Yellow;
            break;
        case "Green":
            color = Colors.Green;
            break;
        case "Blue":
            color = Colors.Blue;
            break;
        case "Red":
            color = Colors.Red;
            break;
    }
    colorRectangle.Fill = new SolidColorBrush(color);
}

SelectionChanged 和键盘导航

默认情况下,当用户单击、点击列表中的项或对其按 Enter 以提交所做的选择时,就会发生 SelectionChanged 事件,然后组合框会关闭。 当用户使用键盘箭头键导航打开的组合框列表时,不会改变所做的选择。

要创建可在用户使用箭头键导航打开的列表时实时更新的组合框(如字体选择下拉列表),请将 SelectionChangedTrigger 设置为 Always。 这样,当焦点转到开放列表中的另一项时,就会发生 SelectionChanged 事件。

所选项行为变化

在 Windows 10 版本 1809 (SDK 17763) 或更高版本中,选定项的行为已更新,支持可编辑的组合框。

在 SDK 17763 之前,SelectedItem 属性(以及相应的 SelectedValue 和 SelectedIndex)的值必须位于组合框的项集中。 使用上一示例时,设置 colorComboBox.SelectedItem = "Pink" 会导致:

  • SelectedItem = null
  • SelectedValue = null
  • SelectedIndex = -1

在 SDK 17763 及更高版本中,SelectedItem 属性(以及相应的 SelectedValue 和 SelectedIndex)的值不需位于组合框的项集中。 使用上一示例时,设置 colorComboBox.SelectedItem = "Pink" 会导致:

  • SelectedItem = Pink
  • SelectedValue = Pink
  • SelectedIndex = -1

组合框自动支持在其集合内进行搜索。 当用户在物理键盘上键入字符,同时关注一个打开或关闭的组合框时,与用户字符串相匹配的候选字符就会出现。 此功能在浏览长列表时尤其有用。 例如,当与包含状态列表的下拉列表交互时,用户可以按“w”键来将“Washington”引入视图,以供快速选择。 文本搜索不区分大小写。

可以将 IsTextSearchEnabled 属性设置为 false 以禁用此功能。

使组合框变得可编辑

重要

此功能需要 Windows 10 版本 1809 (SDK 17763) 或更高版本。

默认情况下,组合框允许用户从预定义的选项列表中进行选择。 但有时候,列表仅包含一部分有效值,因此应该允许用户输入未列出的其他值。 为了支持该功能,可以让组合框变得可编辑。

要让组合框变得可编辑,请将 IsEditable 属性设置为 true。 然后处理 TextSubmitted 事件,以便处理用户输入的值。

默认情况下,当用户提交自定义文本时,SelectedItem 值就会更新。 可以在 TextSubmitted 事件参数中将 Handled 设置为 true,以便覆盖此行为。 将事件标记为“已处理”后,组合框就不会在事件之后执行进一步的操作,会停留在“正在编辑”状态。 SelectedItem 将不会更新。

此示例显示了一个简单的可编辑组合框。 此列表包含简单的字符串,用户输入的任何值都会用作已输入值。

“最近使用的名称”选择器允许用户输入自定义字符串。 “RecentlyUsedNames”列表包含可供用户选择的一些值,但用户也可添加新的自定义值。 “CurrentName”属性表示当前输入的名称。

<ComboBox IsEditable="true"
          ItemsSource="{x:Bind RecentlyUsedNames}"
          SelectedItem="{x:Bind CurrentName, Mode=TwoWay}"/>

提交的文本

可以处理 TextSubmitted 事件,以便处理用户输入的值。 在事件处理程序中,通常需验证用户输入的值是否有效,然后即可在应用中使用该值。 也可根据情况将值添加到组合框的选项列表中供将来使用。

当以下条件满足时,会发生 TextSubmitted 事件:

  • IsEditable 属性为 true
  • 用户输入的文本与组合框列表中的现有条目不匹配
  • 用户按了 Enter,或已将焦点从组合框中移开。

如果用户在输入文本后又通过列表进行上下导航,则不会发生 TextSubmitted 事件。

示例 - 验证输入并在本地使用

在此示例中,字体大小选择器包含与字体大小渐变相对应的一组值,但用户可输入不在列表中的字体大小。

当用户添加不在列表中的值时,字体大小会更新,但值不会添加到字体大小列表中。

如果新输入的值无效,则请使用 SelectedValue 将 Text 属性还原为上一个已知有效的值。

<ComboBox x:Name="fontSizeComboBox"
          IsEditable="true"
          ItemsSource="{x:Bind ListOfFontSizes}"
          TextSubmitted="FontSizeComboBox_TextSubmitted"/>
private void FontSizeComboBox_TextSubmitted(ComboBox sender, ComboBoxTextSubmittedEventArgs e)
{
    if (byte.TryParse(e.Text, out double newValue))
    {
        // Update the app's font size.
        _fontSize = newValue;
    }
    else
    {
        // If the item is invalid, reject it and revert the text.
        // Mark the event as handled so the framework doesn't update the selected item.
        sender.Text = sender.SelectedValue.ToString();
        e.Handled = true;
    }
}

示例 - 验证输入并将其添加到列表

在这里,“最喜爱颜色选择器”包含通常情况下人们最喜爱的颜色(红、蓝、绿、橙),但用户可以输入不在列表中的最喜爱的颜色。 当用户添加有效颜色(例如粉红色)时,新输入的颜色会添加到列表中,并被设置为有效的“最喜爱颜色”。

<ComboBox x:Name="favoriteColorComboBox"
          IsEditable="true"
          ItemsSource="{x:Bind ListOfColors}"
          TextSubmitted="FavoriteColorComboBox_TextSubmitted"/>
private void FavoriteColorComboBox_TextSubmitted(ComboBox sender, ComboBoxTextSubmittedEventArgs e)
{
    if (IsValid(e.Text))
    {
        FavoriteColor newColor = new FavoriteColor()
        {
            ColorName = e.Text,
            Color = ColorFromStringConverter(e.Text)
        }
        ListOfColors.Add(newColor);
    }
    else
    {
        // If the item is invalid, reject it but do not revert the text.
        // Mark the event as handled so the framework doesn't update the selected item.
        e.Handled = true;
    }
}

bool IsValid(string Text)
{
    // Validate that the string is: not empty; a color.
}

获取示例代码