Привязка в .NET MAUI. Форматирование строк и конвертеры значений (IValueConverter и IMultiValueConverter)

Не всегда бывает удобным (и возможным) отображать в элементе управления или передавать в свойство целевого объекта текущее значение свойства источника привязки. Например, нам может потребоваться каким-либо образом форматировать строку со значением из источника прежде, чем вывести её в тексте метки. Или привязываемые свойства вообще не совпадают по типу — одно свойство имеет тип Double, а второе, скажем Color и нам необходимо «вытащить» из Color, например, только значение яркости и так далее. В этом случае мы можем использовать при привязке данных форматирование строк или написать свой конвертер значений и применить его в привязке.

Форматирование строк в привязке

Форматирование строк производится с использованием метода string.Format(), а для использования этого метода у расширения разметки Binding имеется параметр StringFormat. Этот параметр стоит использовать в том случае, если целевое свойство является строкой. Например, создадим новое приложение .NET MAUI и напишем следующий код страницы MainPage.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"
             x:Class="MauiApp13.MainPage">

    <ScrollView>
        <VerticalStackLayout
            <Label Text="{Binding Source={x:Reference RValue}, 
                Path=Value, 
                StringFormat='Красный {0:F0}'}"/>
            
            <Slider x:Name="RValue" Maximum="255" Minimum="0"/>
            
            <Label Text="{Binding Source={x:Reference GValue}, 
                Path=Value, 
                StringFormat='Зеленый {0:F0}'}"/>
            
            <Slider x:Name="GValue" Maximum="255" Minimum="0"/>
            
            <Label Text="{Binding Source={x:Reference BValue}, 
                Path=Value, 
                StringFormat='Синий {0:F0}'}"/>
           
            <Slider x:Name="BValue" Maximum="255" Minimum="0"/>
        </VerticalStackLayout>
    </ScrollView>

</ContentPage>

 

Здесь метки Label привязываются к свойствам Value трех элементов Slider. При этом, для Binding задано форматирование строк, например:

StringFormat='Зеленый {0:F0}'}"

Таким образом, при выводе текста, строка будет отформатирована и на экране мы увидим, например, вот такой результат:Теперь попробуем ответить на вопрос: каким образом мы можем использовать значения из трех Slider, чтобы сформировать из них цвет Color и передать это значение, например, в качестве фона страницы? Для выполнения такой задачи нам пригодятся конвертеры значений.

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

Привязка свойств в .NET MAUI производится, если оба свойства совпадают по типу. При этом, для примитивных типов инфраструктура .NET MAUI может сама конвертировать значение свойства из одного типа в другой. Например, выше мы без лишних проблем привязываем свойство Text у метки к свойству Value у Slider, несмотря на то, что целевое свойство имеет тип string, а исходное — double. Однако, возможностей инфраструктуры .NET MAUI не всегда достаточно и может потребоваться написать свой собственный конвертер значений.

В .NET MAUI можно выделить два типа конвертеров значений:

  1. Конвертеры, которые преобразуют одно значение. Классы таких конвертеров должны реализовывать интерфейс IValueConverter
  2. Конвертеры, которые преобразуют несколько значений. Классы таких конвертеров должны реализовывать интерфейс IMultiValueConverter 

Изучим эти типы конвертеров на нашем примере.

IValueConverter

Пользовательский конвертер, реализующий интерфейс IValueConverter используется в том случае, когда необходимо конвертировать одно значение в другое. Например, наши элементы Slider используют тип double для свойства Value. Но нам может потребоваться, чтобы в метке выводилось, например, HEX-значение. Для этого мы можем реализовать свой конвертер значений.

Добавим в проект новый класс DoubleToHexConverter

public class DoubleToHexConverter : IValueConverter
{
    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        if (value == null) return null;
        var data = System.Convert.ToInt32(value);
        return data.ToString("X");
    }

    public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        if (value == null) return null;
        return (double)int.Parse((string)value, NumberStyles.HexNumber);
    }
}

Здесь у конвертера реализованы два метода интерфейса IValueConverter:

  • Convert(), который преобразует значение свойства источника в тип, который понимается целью (в нашем случае — из double в hex). Метод Convert() вызывается при использовании режимов привязки OneWay или TwoWay.
  • ConvertBack(), который выполняет противоположную операцию — из hex в double. Этот метод вызывается при использовании режимов привязок TwoWay или OneWayToSource

Оба эти метода содержат по четыре параметра:

Параметр Тип Описание
value object значение, которое надо преобразовать
targetType Type тип, к которому надо преобразовать значение value
parameter object  дополнительный параметр, который может использовать при конвертировании
culture CultureInfo текущая культура в приложении

В нашем случае мы реализовали два оба метода, хотя, было бы достаточно и одного Convert(), так как мы не передаем никаких данных от цели к источнику.

Воспользуемся конвертером в нашем приложении.

Использование конвертеров значений XAML

Чтобы воспользоваться конвертером значений в XAML мы должны зарегистрировать этот конвертер как ресурс и передать этот ресурс в параметр Converter расширения Binding.

Изменим код страницы следующим образом:

<?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:converter="clr-namespace:MauiApp13"
             x:Class="MauiApp13.MainPage">

    <ContentPage.Resources>
        <ResourceDictionary>
            <converter:DoubleToHexConverter x:Key="DoubleToHexConverter"/>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ScrollView>
        <VerticalStackLayout>
            <Label Text="{Binding Source={x:Reference RValue}, Path=Value, StringFormat='Красный {0}', Converter={x:StaticResource DoubleToHexConverter}}"/>
            <Slider x:Name="RValue" Maximum="255" Minimum="0"/>

            <Label Text="{Binding Source={x:Reference GValue}, Path=Value, StringFormat='Зеленый {0:F0}', Converter={x:StaticResource DoubleToHexConverter}}"/>
            <Slider x:Name="GValue" Maximum="255" Minimum="0"/>

            <Label Text="{Binding Source={x:Reference BValue}, Path=Value, StringFormat='Синий {0:F0}', Converter={x:StaticResource DoubleToHexConverter}}"/>
            <Slider x:Name="BValue" Maximum="255" Minimum="0"/>
        </VerticalStackLayout>
    </ScrollView>

</ContentPage>

Первое, что мы сделали — это добавили пространство имен в котором содержится конвертер:

xmlns:converter="clr-namespace:MauiApp13"

Далее, мы зарегистрировали наш конвертер, как ресурс:

<ContentPage.Resources>
    <ResourceDictionary>
        <converter:DoubleToHexConverter x:Key="DoubleToHexConverter"/>
    </ResourceDictionary>
</ContentPage.Resources>

и, наконец, использовали этот ресурс в расширении Binding

<Label Text="{Binding Source={x:Reference RValue}, Path=Value, StringFormat='Красный {0}', Converter={x:StaticResource DoubleToHexConverter}}"/>

Так как мы используем и параметр StringFormat и параметр Converter, то стоит отметить, что вначале сработает конвертер и только потом строка будет отформатирована. То есть приложение будет выглядеть как показано на рисунке ниже:

Теперь вернемся к нашему основному вопросу: как преобразовать сразу три значения Value в одно — Color? Здесь нам пригодится второй тип конвертера — IMultiValueConverter

IMultiValueConverter и MultiBinding

Иногда нам необходимо привязать сразу несколько значений свойств к одному целевому. Например, как в нашем случае — мы должны каким-то образом обработать три значения Value, чтобы получить одно — Color. В .NET MAUI и XAML для таких задач может использоваться множественная привязка или MultiBinding. Расширение MultiBinding работает также как и уже известное нам Binding, за одним различием — в это расширение мы должны передавать список привязок, то есть список объектов класса BindingBase. Чтобы воспользоваться MultiBinding в нашем приложении мы также должны создать свой класс конвертера, который реализует интерфейс IMultiValueConverter.

Итак, добавим в наш проект новый класс RgbConverter:

public class RgbConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var r = System.Convert.ToByte(values[0]);
        var g = System.Convert.ToByte(values[1]);
        var b = System.Convert.ToByte(values[2]);
        return Color.FromRgb(r, g, b);
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Единственное отличие этого конвертера от предыдущего заключается в том, что в качестве первого параметра в методе Convert() мы принимаем не одно, а массив значений, а в методе ConvertBack() мы должны, наоборот — вернуть массив значений из одного полученного. В нашем случае, нам достаточно реализовать для работы только метод Convert(), что мы и сделали. Теперь вернемся к нашему приложению и воспользуемся конвертером:

<?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:converter="clr-namespace:MauiApp13"
             x:Class="MauiApp13.MainPage">

    <ContentPage.Resources>
        <ResourceDictionary>
            <converter:RgbConverter x:Key="RgbConverter"/>
            <converter:DoubleToHexConverter x:Key="DoubleToHexConverter"/>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Background>
        <MultiBinding Converter="{StaticResource RgbConverter}">
            <MultiBinding.Bindings>
                <Binding Path="Value" Source="{x:Reference RValue}" />
                <Binding Path="Value" Source="{x:Reference GValue}" />
                <Binding Path="Value" Source="{x:Reference BValue}" />
            </MultiBinding.Bindings>
        </MultiBinding>
    </ContentPage.Background>
    
    <ScrollView>
        
        
        <VerticalStackLayout>
            <Label Text="{Binding Source={x:Reference RValue}, Path=Value, StringFormat='Красный {0}', Converter={x:StaticResource DoubleToHexConverter}}"/>

            <Slider x:Name="RValue" Maximum="255" Minimum="0"/>

            <Label Text="{Binding Source={x:Reference GValue}, Path=Value, StringFormat='Зеленый {0:F0}', Converter={x:StaticResource DoubleToHexConverter}}"/>
            <Slider x:Name="GValue" Maximum="255" Minimum="0"/>

            <Label Text="{Binding Source={x:Reference BValue}, Path=Value, StringFormat='Синий {0:F0}', Converter={x:StaticResource DoubleToHexConverter}}"/>
            <Slider x:Name="BValue" Maximum="255" Minimum="0"/>
        </VerticalStackLayout>
    </ScrollView>

</ContentPage>

Мы также зарегистрировали конвертер, как ресурс и обратите внимание, как он был использован в коде:

<ContentPage.Background>
    <MultiBinding Converter="{StaticResource RgbConverter}">
        <MultiBinding.Bindings>
            <Binding Path="Value" Source="{x:Reference RValue}" />
            <Binding Path="Value" Source="{x:Reference GValue}" />
            <Binding Path="Value" Source="{x:Reference BValue}" />
        </MultiBinding.Bindings>
    </MultiBinding>
</ContentPage.Background>

Здесь, для свойства страницы Background мы используем множественную привязку, указав в параметре Converter у MultiBinding наш конвертер. Далее мы создаем список привязок:

<MultiBinding.Bindings>
    <Binding Path="Value" Source="{x:Reference RValue}" />
    <Binding Path="Value" Source="{x:Reference GValue}" />
    <Binding Path="Value" Source="{x:Reference BValue}" />
</MultiBinding.Bindings>

к значениям Value у элементов Slider. Таким образом, мы решаем задачу по передаче нескольких значений свойств в одно целевое свойство. Проверим работу нашего приложения:Фон страницы приложения меняется по мере изменения того или иного значения в слайдерах.

Итого

Конвертеры значений используются для преобразования одного типа значения свойства в другой тип. При этом, конвертеры могут преобразовывать значения как «один-к-одному», то есть одно значение в другое значение, так и «многие-к-одному» — когда нам необходимо несколько значений свойств преобразовать в одно. Второй способ работы конвертеров используется при множественной привязке — когда нам необходимо одному свойству привязать несколько значений свойств из источника (или из нескольких источников).

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии