Содержание
Класс Shell позволяет нам использовать интегрированный обработчик поиска в приложении, используя который, мы можем организовать поиск любых данных в нашем приложении. В этой части мы разберемся с тем, как организовать поиск в нашем приложении с использованием наследников класса SearchHandler.
Организация поиска в приложении
Создание обработчика (наследника класса SearchHandler)
Чтобы задействовать систему поиска в приложении .NET MAUI мы должны создать свой класс-наследник класса SearchHandler. Этот класс содержит достаточно много различных свойств и методов, поэтому имеет смысл разобраться с его работой последовательно, начав с главного — организации поиска в приложении.
Итак создайте новое приложение .NET MAUI или воспользуйтесь исходным кодом приложения, которое мы используем на протяжении всего этого раздела. Создадим в проекте новую папку с названием Controls и разместим в ней класс PageSearchHandler:
namespace AppShellEx.Controls
{
class PageSearchHandler: SearchHandler
{
public List<string> Pages { get; set; }
protected override void OnQueryChanged(string oldValue, string newValue)
{
base.OnQueryChanged(oldValue, newValue);
if (string.IsNullOrWhiteSpace(newValue))
{
ItemsSource = null;
}
else
{
ItemsSource = Pages.Where(page => page.ToLower().Contains(newValue.ToLower()))
.ToList<string>();
}
}
protected override async void OnItemSelected(object item)
{
base.OnItemSelected(item);
await Shell.Current.GoToAsync($"///{page}");
}
}
}
Рассмотрим этот класс подробно. Итак, класс PageSearchHandler является наследником класса SearchHandler. Свойство Pages будет содержать маршруты (свойство ShellContent.Route страниц приложения). По этому списку мы будем проводить поиск.
Далее мы переопределили у базового класса метод OnQueryChanged(). Этот метод вызывается каждый раз при изменении поискового запроса и содержит два параметра:
oldValue— предыдущее значение, заданное пользователем в поисковой строкеnewValue— новое значение
В этом методе мы производим поиск по списку Page текущего значения из строки поиска и присваиваем полученную коллекцию свойству ItemsSource, которое должно содержать все найденные элементы:
ItemsSource = Pages.Where(page => page.ToLower().Contains(newValue.ToLower()))
.ToList<string>();
если поисковая строка не содержит никаких элементов, то свойству ItemSource присваивается значение null.
Второй переопределенный метод OnItemSelected() вызывается каждый раз, когда пользователь выбирает какой-либо элемент в списке найденных элементов. При этом параметр item содержит выбранный пользователем элемент. В этом методе мы осуществляем переход на найденную страницу, используя метод GoToAsync() класса Shell. Об этом и других методах навигации мы поговорим позднее, когда будем разбирать вопросы, связанные с навигацией в приложениях .NET MAUI.
Использование обработчика в приложении
Теперь нам необходимо использовать созданный обработчик поиска в тех местах приложения где необходимо организовать поиск. Например, добавим его на главную страницу приложения. Изменим код страницы MainPage следующим образом:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AppShellEx.MainPage"
Title="MainPage"
xmlns:controls="clr-namespace:AppShellEx.Controls">
<Shell.SearchHandler>
<controls:PageSearchHandler x:Name="Search">
</controls:PageSearchHandler>
</Shell.SearchHandler>
....
</ContentPage>
Первое, что мы здесь сделали — это подключили новое пространство имен в котором расположен обработчик:
xmlns:controls="clr-namespace:AppShellEx.Controls"
Далее мы, используя свойство Shell.SearchHandler добавили на страницу наш обработчик, присвоив ему через атрибут x:Name имя Search (имя можно задавать любое). Теперь нам необходимо определить в обработчике значение свойства Pages, чтобы поиск заработал.
Откроем файл отдельного кода MainPage.xaml.cs и изменим его следующим образом:
namespace AppShellEx
{
public partial class MainPage : ContentPage
{
public List<string> Pages = ["MainPage", "DetailPage"];
int count = 0;
public MainPage()
{
InitializeComponent();
Search.Pages = Pages;
}
....
}
}
То есть мы передаем в свойство Pages нашего обработчика поиска список Pages непосредственно в конструкторе класса. Следующий шаг — это определить маршруты страниц. Для этого откроем файл AppShell.xaml и изменим его следующим образом:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="AppShellEx.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:AppShellEx"
Title="AppShellEx"
BackgroundColor ="Coral"
TitleColor ="Red">
<ShellContent Title="1"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage"/>
<ShellContent Title="2"
ContentTemplate="{DataTemplate local:DetailPage}"
Route="DetailPage"/>
</Shell>
Обратите внимание на то, что значения свойств Route у нас полностью совпадает со значениями из переданного в PageSearchHandler списка. Теперь можно проверить работу поиска в нашем приложении. Запустите приложение и попробуйте набрать в строке поиска, например, символ «D»:
Вы увидите, что под строкой поиска открывается список, но без какого-либо текста. При этом, если вы выберите в этом списке пустой элемент, то вы действительно будете перемещены на страницу DetailPage. То есть сам по себе поиск работает и нам остается только разобраться с тем как отобразить результаты поиска.
Отображение результатов поиска
Чтобы в списке появлялись данные о найденных элементах, нам необходимо определить в нашем обработчике поиска свойство ItemTemplate — шаблон найденных элементов. Здесь нам снова придется немного «забежать вперед». Изменим XAML-код обработчика поиска следующим образом:
<Shell.SearchHandler>
<controls:PageSearchHandler x:Name="Search">
<controls:PageSearchHandler.ItemTemplate>
<DataTemplate x:DataType="x:String">
<Label Text="{Binding}"
FontAttributes="Bold"
VerticalOptions="Center" />
</DataTemplate>
</controls:PageSearchHandler.ItemTemplate>
</controls:PageSearchHandler>
</Shell.SearchHandler>
Рассмотрим этот код с последнего элемента. Итак, для отображения результатов поиска мы задействуем элемента Label:
<Label Text="{Binding}" FontAttributes="Bold" VerticalOptions="Center" />
У этого элемента в качестве значения для свойства Text указано {Binding}. Это, проще говоря, означает, что свойству Text будет присваиваться весь объект, который мы привязываем. А привязываем мы то, что нашел наш обработчик поиска.
Элемент Label «обернут» в DataTemplate (шаблон данных), который определяет как привязанный объект должен быть отображен. У DataTemplate мы определили атрибут x:DataType="x:String", который говорит, что в качестве данных для отображения выступает обычная строка.
И, наконец, вся эта конструкция из DataTemplate и Label выступает в качестве шаблона для элемента списка поиска — значения для свойства ItemTemplate. Таким образом, наша система поиска будет работать следующим образом: после того, как получены данные в ItemSource, каждый элемент этого свойства будет использоваться в качестве значения для Label и отображаться в списке.
Запустим приложение и снова проверим его работу:
Как можно видеть по рисунку, теперь наша система поиска заработала так, как и должна — в списке отображаются найденные элементы, а выбор очередного элемента позволяет перейти на страницу приложения. Теперь можно украсть наш поиск. Для этого разберемся с другими свойствами класса SearchHandler
Итого
Для организации поиска в приложении мы должны создать класс-наследник для класса SearchHandler, у которого переопределить методы OnQueryChanged() и OnItemSelected(). Чтобы результаты поиска корректно отображались в списке найденных элементов, у компонента поиска необходимо определить свойство ItemTemplate.


