.NET MAUI Shell 搜索

浏览示例。 浏览示例

.NET Multi-platform App UI (.NET MAUI) Shell 包括 SearchHandler 类提供的集成搜索功能。 通过将 Shell.SearchHandler 附加属性设置为子类化的 SearchHandler 对象,可将搜索功能添加到页面。 这会将搜索框添加到页面顶部:

Shell SearchHandler 的屏幕截图。

将查询输入到搜索框时,Query 属性将更新,每次更新时均将执行 OnQueryChanged 方法。 可以重写此方法来使用数据填充搜索建议区:

Shell SearchHandler 中搜索结果的屏幕截图。

然后,从搜索建议区选择一个结果后,将执行 OnItemSelected 方法。 可以重写此方法来相应地进行响应,例如通过导航到详细信息页。

创建 SearchHandler

可创建 SearchHandler 类的子类,然后重写 OnQueryChangedOnItemSelected 方法,将搜索功能添加到 Shell 应用:

public class AnimalSearchHandler : SearchHandler
{
    public IList<Animal> Animals { get; set; }
    public Type SelectedItemNavigationTarget { get; set; }

    protected override void OnQueryChanged(string oldValue, string newValue)
    {
        base.OnQueryChanged(oldValue, newValue);

        if (string.IsNullOrWhiteSpace(newValue))
        {
            ItemsSource = null;
        }
        else
        {
            ItemsSource = Animals
                .Where(animal => animal.Name.ToLower().Contains(newValue.ToLower()))
                .ToList<Animal>();
        }
    }

    protected override async void OnItemSelected(object item)
    {
        base.OnItemSelected(item);

        Animal animal = item as Animal;
        string navigationTarget = GetNavigationTarget();

        if (navigationTarget.Equals("catdetails") || navigationTarget.Equals("dogdetails"))
        {
            // Navigate, passing a string
            await Shell.Current.GoToAsync($"{navigationTarget}?name={((Animal)item).Name}");
        }
        else
        {
            string lowerCasePropertyName = navigationTarget.Replace("details", string.Empty);
            // Capitalise the property name
            string propertyName = char.ToUpper(lowerCasePropertyName[0]) + lowerCasePropertyName.Substring(1);

            var navigationParameters = new Dictionary<string, object>
            {
                { propertyName, animal }
            };

            // Navigate, passing an object
            await Shell.Current.GoToAsync($"{navigationTarget}", navigationParameters);
        }
    }

    string GetNavigationTarget()
    {
        return (Shell.Current as AppShell).Routes.FirstOrDefault(route => route.Value.Equals(SelectedItemNavigationTarget)).Key;
    }
}

OnQueryChanged 重写包含两个参数:包含旧搜索查询的 oldValue,以及包含当前搜索查询的 newValue。 通过将 SearchHandler.ItemsSource 属性设置为 IEnumerable 集合(其中包含与当前搜索查询匹配的项),可以更新搜索建议区。

用户选择一个搜索结果后,将执行 OnItemSelected 重写,并设置 SelectedItem 属性。 在此示例中,此方法导航到另一个显示选定的 Animal 相关数据的页面。 有关导航的详细信息,请参阅 Shell 导航

注意

可设置其他的 SearchHandler 属性以控制搜索框的外观。

使用 SearchHandler

通过在“使用”页上将 Shell.SearchHandler 附加属性设置为子类类型对象,可以使用子类化的 SearchHandler

<ContentPage ...
             xmlns:controls="clr-namespace:Xaminals.Controls">
    <Shell.SearchHandler>
        <controls:AnimalSearchHandler Placeholder="Enter search term"
                                      ShowsResults="true"
                                      DisplayMemberName="Name" />
    </Shell.SearchHandler>
    ...
</ContentPage>

等效 C# 代码如下:

Shell.SetSearchHandler(this, new AnimalSearchHandler
{
    Placeholder = "Enter search term",
    ShowsResults = true,
    DisplayMemberName = "Name"
});

AnimalSearchHandler.OnQueryChanged 方法返回 Animal 对象的 List。 将 DisplayMemberName 属性设置为各个 Animal 对象的 Name 属性,这样建议区所显示的数据将为各个动物的名称。

警告

SearchHandler.DisplayMemberName 不是安全的剪裁,不应与完整修整或 NativeAOT 一起使用。 相反,应提供 ItemTemplate 来定义 SearchHandler 结果的外观。 有关详细信息,请参阅 定义搜索结果项外观剪裁 .NET MAUI 应用本机 AOT 部署

ShowsResults 属性设置为 true,这样当用户输入搜索查询时即可显示搜索建议:

Shell SearchHandler 中搜索结果的屏幕截图,其中包含部分字符串 M 的结果。

搜索查询更改时,将更新搜索建议区:

Shell SearchHandler 中搜索结果的屏幕截图,其中包含部分字符串 M o n 的结果。

选择某个搜索结果后,将导航到 MonkeyDetailPage,并显示有关所选猴子的详细信息页面:

猴子详细信息的屏幕截图。

定义搜索结果项外观

除了在搜索结果中显示 string 数据外,还可以通过将 SearchHandler.ItemTemplate 属性设置为 DataTemplate 来定义每个搜索结果项的外观:

<ContentPage ...
             xmlns:controls="clr-namespace:Xaminals.Controls">    
    <Shell.SearchHandler>
        <controls:AnimalSearchHandler Placeholder="Enter search term"
                                      ShowsResults="true">
            <controls:AnimalSearchHandler.ItemTemplate>
                <DataTemplate>
                    <Grid Padding="10"
                          ColumnDefinitions="0.15*,0.85*">
                        <Image Source="{Binding ImageUrl}"
                               HeightRequest="40"
                               WidthRequest="40" />
                        <Label Grid.Column="1"
                               Text="{Binding Name}"
                               FontAttributes="Bold"
                               VerticalOptions="Center" />
                    </Grid>
                </DataTemplate>
            </controls:AnimalSearchHandler.ItemTemplate>
       </controls:AnimalSearchHandler>
    </Shell.SearchHandler>
    ...
</ContentPage>

DataTemplate 中指定的元素定义建议区各个项的外观。 在此示例中,由 Grid 管理 DataTemplate 内的布局。 Grid 包含 Image 对象和 Label 对象,两者均绑定到各个 Monkey 对象的属性。

下面的屏幕截图显示建议区内各个项模板化后的结果:

Shell SearchHandler 中模板化搜索结果的屏幕截图。

有关数据模板的详细信息,请参阅数据模板

搜索框可见性

默认情况下,将 SearchHandler 添加到页面顶部后,将显示并完全展开该搜索框。 但是,可以通过将 SearchHandler.SearchBoxVisibility 属性设置为 SearchBoxVisibility 枚举成员之一来更改此行为:

  • Hidden – 搜索框不可见或不可访问。
  • Collapsible – 隐藏搜索框,直到用户执行操作来显示搜索框。 在 iOS 上,通过纵向弹跳页面内容来显示搜索框;在 Android 上,通过点击问号图标显示搜索框。
  • Expanded – 搜索框可见,并且完全展开。 这是 SearchBoxVisibility 属性的默认值。

重要

在 iOS 上,可折叠搜索框需要 iOS 11 或更高版本。

下面的示例演示了如何隐藏搜索框:

<ContentPage ...
             xmlns:controls="clr-namespace:Xaminals.Controls">
    <Shell.SearchHandler>
        <controls:AnimalSearchHandler SearchBoxVisibility="Hidden"
                                      ... />
    </Shell.SearchHandler>
    ...
</ContentPage>

搜索框焦点

点击搜索框可调用屏幕键盘,使搜索框获得输入焦点。 也可以通过调用 Focus 方法(尝试在搜索框上设置输入焦点,并在成功时返回 true)来以编程方式实现。 当搜索框获得焦点时,会触发 Focused 事件并调用可重写的 OnFocused 方法。

当搜索框具有输入焦点时,点击屏幕上的其他位置可关闭屏幕键盘,并且搜索框失去输入焦点。 也可以通过调用 Unfocus 方法来以编程方式实现。 当搜索框失去焦点时,会触发 Unfocused 事件并调用可重写的 OnUnfocus 方法。

可以通过 IsFocused 属性检索搜索框的焦点状态,如果 SearchHandler 当前具有输入焦点,则会返回 true

SearchHandler 键盘

用户与 SearchHandler 交互时显示的键盘可以通过 Keyboard 属性以编程方式设置为 Keyboard 类中的以下属性之一:

  • Chat – 用于可使用表情符号的文本和位置。
  • Default – 默认键盘。
  • Email – 输入电子邮件地址时使用。
  • Numeric – 输入数字时使用。
  • Plain – 输入文本时使用,无需指定任何 KeyboardFlags
  • Telephone – 输入电话号码时使用。
  • Text – 输入文本时使用。
  • Url – 用于输入文件路径和 Web 地址。

这可以通过以下操作以 XAML 实现:

<SearchHandler Keyboard="Email" />

Keyboard 类还具有 Create 工厂方法,可用于通过指定大小写、拼写检查和建议行为来自定义键盘。 KeyboardFlags 枚举值指定为方法的参数,并返回自定义的 KeyboardKeyboardFlags 枚举包含以下值:

  • None – 无功能添加到键盘。
  • CapitalizeSentence – 指示自动大写输入的每句话的第一个词的首字母。
  • Spellcheck – 指示对输入的文本执行拼写检查。
  • Suggestions – 指示对输入的文本执行单词自动完成。
  • CapitalizeWord – 指示自动大写每个词的首字母。
  • CapitalizeCharacter – 指示自动大写每个字符。
  • CapitalizeNone – 指示不执行自动大写。
  • All – 指示对输入的文本执行拼写检查、单词自动完成和句子首字母大写。

以下 XAML 代码示例演示如何自定义默认 Keyboard 来执行单词自动完成并将输入的每个字符的首字母大写:

<SearchHandler Placeholder="Enter search terms">
    <SearchHandler.Keyboard>
        <Keyboard x:FactoryMethod="Create">
            <x:Arguments>
                <KeyboardFlags>Suggestions,CapitalizeCharacter</KeyboardFlags>
            </x:Arguments>
        </Keyboard>
    </SearchHandler.Keyboard>
</SearchHandler>