.NET Multi-platform App UI (.NET MAUI) Shell 包括 SearchHandler 类提供的集成搜索功能。 通过将 Shell.SearchHandler 附加属性设置为子类化的 SearchHandler 对象,可将搜索功能添加到页面。 这会将搜索框添加到页面顶部:
将查询输入到搜索框时,Query 属性将更新,每次更新时均将执行 OnQueryChanged 方法。 可以重写此方法来使用数据填充搜索建议区:
然后,从搜索建议区选择一个结果后,将执行 OnItemSelected 方法。 可以重写此方法来相应地进行响应,例如通过导航到详细信息页。
创建 SearchHandler
可创建 SearchHandler 类的子类,然后重写 OnQueryChanged 和 OnItemSelected 方法,将搜索功能添加到 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
通过在“使用”页上将 SearchHandler 附加属性设置为子类类型对象,可以使用子类化的 Shell.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 方法返回 List 对象的 Animal。 将 DisplayMemberName 属性设置为各个 Name 对象的 Animal 属性,这样建议区所显示的数据将为各个动物的名称。
警告
SearchHandler.DisplayMemberName 不是安全的剪裁,不应与完整修整或 NativeAOT 一起使用。 相反,应提供 ItemTemplate 来定义 SearchHandler 结果的外观。 有关详细信息,请参阅 定义搜索结果项外观、 剪裁 .NET MAUI 应用 和 本机 AOT 部署。
小窍门
在 .NET 10 中,启用完全修整或本机 AOT 时,将忽略剪裁默认值和功能开关平均值 SearchHandler.DisplayMemberName 。 首选用于 ItemTemplate 结果,这是剪裁安全的,并且跨平台受支持。 如果必须在部分剪裁方案中使用DisplayMemberName,可以通过将功能开关设置为MauiShellSearchResultsRendererDisplayMemberNameSupportedtrue项目文件中来选择重新加入。 有关详细信息和权衡,请参阅 剪裁功能开关。
将 ShowsResults 属性设置为 true,这样当用户输入搜索查询时即可显示搜索建议:
搜索查询更改时,将更新搜索建议区:
选择某个搜索结果后,将导航到 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 x:DataType="models:Animal">
<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 中指定的元素定义建议区各个项的外观。 在此示例中,由 DataTemplate 管理 Grid 内的布局。
Grid 包含 Image 对象和 Label 对象,两者均绑定到各个 Monkey 对象的属性。
下面的屏幕截图显示建议区内各个项模板化后的结果:
有关数据模板的详细信息,请参阅数据模板。
搜索框可见性
默认情况下,将 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 属性检索搜索框的焦点状态,如果 true 当前具有输入焦点,则会返回 SearchHandler。
SearchHandler 键盘
用户与 SearchHandler 交互时显示的键盘可以通过 Keyboard 属性以编程方式设置为 Keyboard 类中的以下属性之一:
-
Chat– 用于可使用表情符号的文本和位置。 -
Default– 默认键盘。 -
Email– 输入电子邮件地址时使用。 -
Numeric– 输入数字时使用。 -
Plain– 输入文本时使用,无需指定任何KeyboardFlags。 -
Telephone– 输入电话号码时使用。 -
Text– 输入文本时使用。 -
Url– 用于输入文件路径和 Web 地址。
这可以通过以下操作以 XAML 实现:
<SearchHandler Keyboard="Email" />
Keyboard 类还具有 Create 工厂方法,可用于通过指定大小写、拼写检查和建议行为来自定义键盘。
KeyboardFlags 枚举值指定为方法的参数,并返回自定义的 Keyboard。
KeyboardFlags 枚举包含以下值:
-
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>
隐藏并显示软输入键盘
在 .NET 10 中, SearchHandler 获取以编程方式控制软输入键盘的方法:
当用户导航到具有搜索的页面时,可以使用这些方法打开键盘,并在选择结果后将其消除,而无需依赖焦点更改。
例如,当页面出现时,可以自动打开键盘:
// In a ContentPage code-behind
protected override void OnAppearing()
{
base.OnAppearing();
var handler = Shell.GetSearchHandler(this);
handler?.ShowSoftInputAsync();
}
在自定义 SearchHandler 中选定内容后,你可以隐藏键盘:
public class AnimalSearchHandler : SearchHandler
{
protected override async void OnItemSelected(object item)
{
base.OnItemSelected(item);
// Dismiss the soft input keyboard
await HideSoftInputAsync();
// Perform navigation or other actions
await Shell.Current.GoToAsync("monkeydetails", new Dictionary<string, object>
{
{ "Monkey", item }
});
}
}
Notes:
浏览示例