Привязка позоляет связать два свойства, которые совпадают по типу данных. Например, свойство Text у класса Entry и свойство Text класса Label представляют тип string. Поэтому тут привязка проходит без проблем. Но в других случаях тип связанных свойств может отличаться. В большинстве случаев инфраструктра .NET MAUI сама знает, как конвертировать данные простейших типов. Однако в каких-то ситуациях этого оказывается недостаточно, особенно когда необходимо применить к значению привязки дополнительное форматирование.
Например, пусть у нас элемент Label привязан к элементу DatePicker и выводит выбранную дату. По умолчанию дата выводится в формате "MM/dd/yyyy hh:mm:ss":
namespace HelloApp { class StartPage : ContentPage { public StartPage() { Label label = new Label(); DatePicker datePicker = new DatePicker(); label.BindingContext= datePicker; label.SetBinding(Label.TextProperty, "Date"); StackLayout stackLayout = new StackLayout() { Children = { label, datePicker}, Padding = 20 }; Content = stackLayout; } } }
Это не очень удобный формат. Возможно, мы захотим использовать совсем другие форматы.
Для преобразования одного значения к другому в процессе привязки используются специальные классы - конвертеры значений. К примеру, добавим в наш проект новый класс конвертера значений:
using System.Globalization; namespace HelloApp { public class DateTimeToLocalDateConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return ((DateTime)value).ToString("dd.MM.yyyy"); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return DateTime.Parse(value.ToString()); } } }
Прежде всего класс конвертера значений должен реализовать интерфейс IValueConverter. Этот интерфейс определяет два
метода: Convert()
, который преобразует пришедшее от привязки значение в тот тип, который понимается приемником привязки, и
ConvertBack()
, который выполняет противоположную операцию.
Оба метода принимают четыре параметра:
object value
: значение, которое надо преобразовать
Type targetType
: тип, к которому надо преобразовать значение value
object parameter
: вспомогательный параметр
CultureInfo culture
: текущая культура приложения
Метод Convert
вызывается при передаче данных от источника привязки к цели, когда действуют режимы привязки OneWay и TwoWay.
Параметр value
представляет значение, которое пришло от источника. Метод должен возвратить значение к типу привязанного свойства цели.
Метод ConvertBack()
вызывается, когда данные передаются от цели привязки к источнику при режимах привязки TwoWay и OneWayToSource.
ConvertBack
выполняет обратное преобразование к типу привязанного свойства источника.
В примере выше метод Convert возвращает дату в виде строки в формате "dd.MM.yyyy". То есть мы ожидаем, что в качесве параметра value будет передаваться объект DateTime.
Метод ConvertBack в данном случае не имеет значения, и поэтому он просто возвращает строковое представление текущей даты.
Для установки конвертере значений есть два способа: либо в методе SetBinding()
устанавливается параметр converter
, либо у
объекта Binding устанавливается свойство :
Используем метод SetBinding()
:
namespace HelloApp { class StartPage : ContentPage { public StartPage() { Label label = new Label(); DatePicker datePicker = new DatePicker(); label.BindingContext= datePicker; label.SetBinding(Label.TextProperty, "Date", converter: new DateTimeToLocalDateConverter()); StackLayout stackLayout = new StackLayout() { Children = { label, datePicker}, Padding = 20 }; Content = stackLayout; } } }
Аналогичный пример с объектом Binding:
namespace HelloApp { class StartPage : ContentPage { public StartPage() { Label label = new Label(); DatePicker datePicker = new DatePicker(); Binding binding = new Binding { Source = datePicker, Path = "Date", Converter = new DateTimeToLocalDateConverter()}; label.SetBinding(Label.TextProperty, binding); StackLayout stackLayout = new StackLayout() { Children = { label, datePicker}, Padding = 20 }; Content = stackLayout; } } }
Аналогичный пример в xaml:
<?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" xmlns:local="clr-namespace:HelloApp" x:Class="HelloApp.MainPage"> <ContentPage.Resources> <ResourceDictionary> <local:DateTimeToLocalDateConverter x:Key="dateConverter" /> </ResourceDictionary> </ContentPage.Resources> <StackLayout Padding="20"> <Label Text="{Binding Source={x:Reference Name=datePicker}, Path=Date, Converter={StaticResource dateConverter}}" /> <DatePicker x:Name="datePicker" /> </StackLayout> </ContentPage>
Так как класс конвертера располагается в пространстве имен текущего проекта, то, чтобы класс был доступен в xaml, надо подключить текущее пространство имен.
xmlns:local="clr-namespace:HelloApp"
В моем случае пространством имен является HelloApp, и оно проецируется на суффикс local
Затем в ресурсах создается объект привязки с ключом dateConverter
.
И далее в самом выражении привязки мы подключем данный ресурс в качестве конвертера:
Converter={StaticResource dateConverter}
Возьмем другой случай. Допустим, нам надо привязать цвет метки к вводимому в текстовое поле значение. Для этого определим следующий конвертер:
using System.Globalization; namespace HelloApp { public class StringToColorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string colorStr = value?.ToString().Trim().ToLower(); switch (colorStr) { case "red": return Colors.Red; case "green": return Colors.Green; case "blue": return Colors.Blue; default: return Colors.Gray; } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var color = value as Color; var colorHex = color.ToHex(); switch (colorHex) { case "#FF0000": return "red"; case "#00FF00": return "green"; case "#0000FF": return "blue"; default: return "gray"; } } } }
Если вводится определенная строка, то конвертер возвращает определенный цвет. Теперь применим этот конвертер в XAML:
<?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" xmlns:local="clr-namespace:HelloApp" x:Class="HelloApp.MainPage"> <ContentPage.Resources> <ResourceDictionary> <local:StringToColorConverter x:Key="colorConverter" /> </ResourceDictionary> </ContentPage.Resources> <StackLayout Padding="20"> <Entry x:Name="entry" /> <Label Text="Hello METANIT.COM" TextColor="{Binding Source={x:Reference Name=entry}, Converter={StaticResource colorConverter}, Path=Text}" /> </StackLayout> </ContentPage>
Аналогичный пример в коде C#:
namespace HelloApp { class StartPage : ContentPage { public StartPage() { Label label = new Label { Text = "Hello METANIT.COM" }; Entry entry= new Entry(); Binding binding = new Binding { Source = entry, Path = "Text", Converter = new StringToColorConverter()}; label.SetBinding(Label.TextColorProperty, binding); StackLayout stackLayout = new StackLayout() { Children = { entry, label}, Padding = 20 }; Content = stackLayout; } } }