痕迹栏

BreadcrumbBar 提供页面或文件夹当前位置的直接路径。 该控件通常用于这样的情况:用户的导航轨迹(在文件系统或菜单系统中)需要持续可见,并且用户可能需要返回到前一位置。

带节点的痕迹导航栏:Home、Documents、Design、Northwind、Images、Folder1、Folder2、Folder3。应用调整大小,使痕迹导航崩溃,省略号将替换最左侧的节点。然后,单击省略号将打开带有崩溃节点的弹出项目

这是正确的控件吗?

痕迹导航栏让用户可以在浏览应用或文件夹时跟踪他们的位置,并可快速跳回到路径中的前一位置。

如果用于跳转到当前位置的路径是相关的,请使用 BreadcrumbBar。 在文件夹管理器中,以及在用户可以在应用中深入导航多个级别时,经常使用此 UI。

痕迹导航栏在水平行中显示每个节点,各个节点用“>”符号分隔。

带节点的痕迹导航栏:Home、Documents、Design、Northwind、Images、Folder1、Folder2、Folder3。

如果调整应用大小后没有足够的空间可用于显示所有节点,则痕迹导航将会折叠并用省略号来代替最左侧的节点。 单击省略号会打开一个浮出窗口以显示折叠的节点。

调整了痕迹导航栏的大小,以便省略号替换最左侧的节点。省略号打开一个弹出项目,其中显示了折叠的节点

结构

下图显示了 BreadcrumbBar 控件的各个部件。 可以使用轻型样式设置修改某些部件的外观。

带标签的部件的痕迹导航栏的图像:省略号、V 形图、痕迹导航栏项目、当前项目、省略号弹出项目、省略号下拉项目

建议

  • 如果你有多个导航级别并希望用户能够返回到任何前一级别,请使用痕迹导航栏。
  • 如果你只有 2 个可能的导航级别,请不要使用痕迹导航栏。 使用简单的后退导航便已足够。
  • 将当前位置显示为痕迹导航栏中的最后一个项。 但是,如果用户单击当前项,你通常不希望执行任何导航。 (要让用户重新加载当前页面或数据,请考虑提供专用的“重新加载”选项。)

UWP 和 WinUI 2

重要

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

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

UWP 应用的痕迹导航栏需要 WinUI 2。 有关详细信息(包括安装说明),请参阅 WinUI 2。 此控件的 API 存在于 Microsoft.UI.Xaml.Controls 命名空间中。

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

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

<muxc:BreadcrumbBar />

创建痕迹导航栏

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

此示例演示如何使用默认样式创建痕迹导航栏。 可将痕迹导航栏放置在应用 UI 中的任何位置。 通过设置 ItemsSource 属性来填充痕迹导航。 在此处,该属性设置为痕迹导航栏中显示的字符串数组。

<BreadcrumbBar x:Name="BreadcrumbBar1"/>
BreadcrumbBar1.ItemsSource = 
   new string[] { "Home", "Documents", "Design", "Northwind", "Images", "Folder1", "Folder2", "Folder3" };

ItemsSource

痕迹导航栏没有 Items 属性,而只有 ItemsSource 属性。 这意味着,无法在 XAML 中填充痕迹导航,也无法通过在代码中将痕迹导航直接添加到 Items 集合来填充痕迹导航。 为此,应该创建一个集合,并在代码中或使用数据绑定将 ItemsSource 属性连接到该集合。

可将 ItemsSource 设置为任何数据类型的集合,以满足应用的需求。 集合中的数据项既用于在栏中显示痕迹导航,也用于在单击痕迹导航栏中的项时进行导航。 在本页面上的示例中,我们将创建一个简单的 struct(名为 Crumb),其中包含一个显示在痕迹导航栏中的标签,以及一个数据对象,该对象保存了用于导航的信息。

public readonly struct Crumb
{
    public Crumb(String label, object data)
    {
        Label = label;
        Data = data;
    }
    public string Label { get; }
    public object Data { get; }
    public override string ToString() => Label;
}

ItemTemplate

默认情况下,痕迹导航栏显示集合中每个项的字符串表示形式。 如果集合中的数据项没有相应的 ToString 重写,你可以使用 ItemTemplate 属性指定一个数据模板,用于定义这些项在痕迹导航栏中的显示方式。

例如,如果痕迹导航集合是 StorageFolder 对象的列表,则你可以提供一个数据模板并如下所示将其绑定到 DisplayName 属性。

ObservableCollection<StorageFolder> Breadcrumbs = 
    new ObservableCollection<StorageFolder>();
<BreadcrumbBar x:Name="FolderBreadcrumbBar"
            ItemsSource="{x:Bind Breadcrumbs}">
    <BreadcrumbBar.ItemTemplate>
        <DataTemplate x:DataType="StorageFolder">
            <TextBlock Text="{x:Bind DisplayName}"/>
        </DataTemplate>
    </BreadcrumbBar.ItemTemplate>
</BreadcrumbBar>

ItemClicked

处理 ItemClicked 事件,以导航到用户在痕迹导航栏中单击的项。 当前位置通常显示为痕迹导航栏中的最后一个项,因此,如果你不想要重新加载当前位置,应在事件处理程序中包含一项检查。

此示例检查 Index,以确定单击的 Item 是否是集合中的最后一个项,即当前位置。 如果是,则不发生导航。

// Breadcrumbs is set as BreadcrumbBar1.ItemsSource.
List<Crumb> Breadcrumbs = new List<Crumb>();

...

private void BreadcrumbBar1_ItemClicked(muxc.BreadcrumbBar sender, muxc.BreadcrumbBarItemClickedEventArgs args)
{
    if (args.Index < Breadcrumbs.Count - 1)
    {
        var crumb = (Crumb)args.Item;
        Frame.Navigate((Type)crumb.Data);
    }
}

轻型样式

可以修改默认 Style 和 ControlTemplate 以使控件具有唯一的外观。 请参阅 BreadcrumbBar API 文档的“控件样式和模板”部分,以查看可用主题资源的列表。 有关详细信息,请参阅设置控件样式一文中的轻量级样式设置部分

代码示例

此示例演示如何在简单的文件资源管理器方案中使用痕迹导航栏。 列表视图显示所选图片或音乐库的内容,并让用户深入到子文件夹。 痕迹导航栏放置在列表视图的标题中,显示当前文件夹的路径。

包含痕迹导航栏的文件列表的图像,其中显示了当前文件夹的路径

<Grid>
   <ListView x:Name="FolderListView" Margin="24,0"
             IsItemClickEnabled="True" 
             ItemClick="FolderListView_ItemClick">
      <ListView.Header>
         <BreadcrumbBar x:Name="FolderBreadcrumbBar"
                             ItemsSource="{x:Bind Breadcrumbs}"
                             ItemClicked="FolderBreadcrumbBar_ItemClicked">
         </BreadcrumbBar>
      </ListView.Header>
      <ListView.ItemTemplate>
         <DataTemplate>
            <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
      </ListView.ItemTemplate>
   </ListView>
</Grid>
public sealed partial class MainPage : Page
{
    List<IStorageItem> Items;
    ObservableCollection<object> Breadcrumbs = 
        new ObservableCollection<object>();

    public MainPage()
    {
        this.InitializeComponent();
        InitializeView();
    }

    private void InitializeView()
    {
        // Start with Pictures and Music libraries.
        Items = new List<IStorageItem>();
        Items.Add(KnownFolders.PicturesLibrary);
        Items.Add(KnownFolders.MusicLibrary);
        FolderListView.ItemsSource = Items;

        Breadcrumbs.Clear();
        Breadcrumbs.Add(new Crumb("Home", null));
    }

    private async void FolderBreadcrumbBar_ItemClicked(muxc.BreadcrumbBar sender, muxc.BreadcrumbBarItemClickedEventArgs args)
    {
        // Don't process last index (current location)
        if (args.Index < Breadcrumbs.Count - 1)
        {
            // Home is special case.
            if (args.Index == 0)
            {
                InitializeView();
            }
            // Go back to the clicked item.
            else
            {
                var crumb = (Crumb)args.Item;
                await GetFolderItems((StorageFolder)crumb.Data);

                // Remove breadcrumbs at the end until 
                // you get to the one that was clicked.
                while (Breadcrumbs.Count > args.Index + 1)
                {
                    Breadcrumbs.RemoveAt(Breadcrumbs.Count - 1);
                }
            }
        }
    }

    private async void FolderListView_ItemClick(object sender, ItemClickEventArgs e)
    {
        // Ignore if a file is clicked.
        // If a folder is clicked, drill down into it.
        if (e.ClickedItem is StorageFolder)
        {
            StorageFolder folder = e.ClickedItem as StorageFolder;
            await GetFolderItems(folder);
            Breadcrumbs.Add(new Crumb(folder.DisplayName, folder));
        }
    }

    private async Task GetFolderItems(StorageFolder folder)
    {
        IReadOnlyList<IStorageItem> itemsList = await folder.GetItemsAsync();
        FolderListView.ItemsSource = itemsList;
    }
}

public readonly struct Crumb
{
    public Crumb(String label, object data)
    {
        Label = label;
        Data = data;
    }
    public string Label { get; }
    public object Data { get; }
    public override string ToString() => Label;
}