Содержание
Не всегда бывает удобным (и возможным) отображать в элементе управления или передавать в свойство целевого объекта текущее значение свойства источника привязки. Например, нам может потребоваться каким-либо образом форматировать строку со значением из источника прежде, чем вывести её в тексте метки. Или привязываемые свойства вообще не совпадают по типу — одно свойство имеет тип 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 можно выделить два типа конвертеров значений:
- Конвертеры, которые преобразуют одно значение. Классы таких конвертеров должны реализовывать интерфейс
IValueConverter
- Конвертеры, которые преобразуют несколько значений. Классы таких конвертеров должны реализовывать интерфейс
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
. Таким образом, мы решаем задачу по передаче нескольких значений свойств в одно целевое свойство. Проверим работу нашего приложения:Фон страницы приложения меняется по мере изменения того или иного значения в слайдерах.
Итого
Конвертеры значений используются для преобразования одного типа значения свойства в другой тип. При этом, конвертеры могут преобразовывать значения как «один-к-одному», то есть одно значение в другое значение, так и «многие-к-одному» — когда нам необходимо несколько значений свойств преобразовать в одно. Второй способ работы конвертеров используется при множественной привязке — когда нам необходимо одному свойству привязать несколько значений свойств из источника (или из нескольких источников).