Конвертеры значений

Последнее обновление: 17.12.2022

Привязка позоляет связать два свойства, которые совпадают по типу данных. Например, свойство 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;
        }
    }
}
Конверторы значений привязки в .NET MAUI и C#

Это не очень удобный формат. Возможно, мы захотим использовать совсем другие форматы.

Для преобразования одного значения к другому в процессе привязки используются специальные классы - конвертеры значений. К примеру, добавим в наш проект новый класс конвертера значений:

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;
        }
    }
}
Конвертер значений Value Converter в .NET MAUI и C#

Аналогичный пример с объектом 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>
Преобразование значений привязки в другой тип в .NET MAUI и С#

Аналогичный пример в коде 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;
        }
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850