Содержание
Класс 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
.