Множественные привязки Xamarin.Forms
Множественные привязки позволяют присоединять коллекцию объектов Binding
к одному свойству целевого объекта привязки. Они создаются с помощью класса MultiBinding
, который вычисляет все объекты Binding
и возвращает одно значение через экземпляр IMultiValueConverter
, предоставляемый приложением. Кроме того, MultiBinding
повторно вычисляет все объекты Binding
при изменении каких-либо привязанных данных.
Класс MultiBinding
определяет следующие свойства:
Bindings
типаIList<BindingBase>
— представление коллекции объектовBinding
в экземпляреMultiBinding
.Converter
типаIMultiValueConverter
— представление преобразователя исходных значений в целевое значение или из целевого значения.ConverterParameter
типаobject
— представление необязательного параметра для передачи вConverter
.
Bindings
— это свойство содержимого класса MultiBinding
. Поэтому его не нужно явно задавать из XAML.
Кроме того, класс MultiBinding
наследует следующие свойства от класса BindingBase
:
FallbackValue
типаobject
— представление значения, используемого, когда множественная привязка не может вернуть значение.Mode
типаBindingMode
— указатель направления потока данных множественной привязки.StringFormat
типаstring
— определение способа форматирования результата множественной привязки, если он отображается в виде строки.TargetNullValue
типаobject
— представление значения, используемого в целевом объекте, когда значение источника равноnull
.
Класс MultiBinding
должен использовать IMultiValueConverter
, чтобы создать значение для целевого объекта привязки на основе значений привязок в коллекции Bindings
. Например, Color
можно вычислить на основе значений красного, синего и зеленого цветов (все они могут быть значениями одних и тех же или разных объектов источника привязки). Когда значение перемещается из целевого объекта в источники, значение целевого свойства преобразуется в набор значений, которые передаются обратно в привязки.
Внимание
Отдельные привязки в коллекции Bindings
могут иметь собственные преобразователи величин.
Значение свойства Mode
определяет возможности MultiBinding
и используется в качестве режима привязки для всех привязок в коллекции, если только отдельная привязка не переопределяет свойство. Например, если для свойства Mode
объекта MultiBinding
задано значение TwoWay
, все привязки в коллекции считаются TwoWay
, если только для одной из привязок явно не задано другое значение Mode
.
Определение IMultiValueConverter
Интерфейс IMultiValueConverter
позволяет применять пользовательскую логику к MultiBinding
. Чтобы связать преобразователь с MultiBinding
, создайте класс, реализующий интерфейс IMultiValueConverter
, а затем реализуйте методы Convert
и ConvertBack
.
public class AllTrueMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || !targetType.IsAssignableFrom(typeof(bool)))
{
return false;
// Alternatively, return BindableProperty.UnsetValue to use the binding FallbackValue
}
foreach (var value in values)
{
if (!(value is bool b))
{
return false;
// Alternatively, return BindableProperty.UnsetValue to use the binding FallbackValue
}
else if (!b)
{
return false;
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
if (!(value is bool b) || targetTypes.Any(t => !t.IsAssignableFrom(typeof(bool))))
{
// Return null to indicate conversion back is not possible
return null;
}
if (b)
{
return targetTypes.Select(t => (object)true).ToArray();
}
else
{
// Can't convert back from false because of ambiguity
return null;
}
}
}
Метод Convert
преобразует исходные значения в значение для целевого объекта привязки. Xamarin.Forms вызывает этот метод при распространении значений от исходных привязок в целевой объект привязки. Этот метод принимает четыре аргумента:
values
типаobject[]
— массив значений, создаваемый исходными привязками вMultiBinding
.targetType
типаType
— тип целевого свойства привязки.parameter
типаobject
— используемый параметр преобразователя.culture
типаCultureInfo
— язык и региональные параметры, используемые в преобразователе.
Метод Convert
возвращает object
— представление преобразованного значения. Этот метод должен возвращать следующее:
BindableProperty.UnsetValue
— указывает, что преобразователь не создал значение и что привязка будет использоватьFallbackValue
.Binding.DoNothing
— указывает Xamarin.Forms не выполнять никаких действий, например не передавать значение в целевой объект привязки или не использоватьFallbackValue
.null
— указывает, что преобразователь не может выполнить преобразование и что привязка будет использоватьTargetNullValue
.
Внимание
Объект MultiBinding
, принимающий BindableProperty.UnsetValue
из метода Convert
, должен определять его свойство FallbackValue
. Точно так же объект MultiBinding
, принимающий null
из метода Convert
, должен определять его свойство TargetNullValue
.
Метод ConvertBack
преобразует целевой объект привязки в значения привязки к источнику. Этот метод принимает четыре аргумента:
value
типаobject
— значение, созданное целевым объектом привязки.targetTypes
типаType[]
— массив типов для преобразования. Длина массива указывает количество и типы значений, которые, как предполагается, метод будет возвращать.parameter
типаobject
— используемый параметр преобразователя.culture
типаCultureInfo
— язык и региональные параметры, используемые в преобразователе.
Метод ConvertBack
возвращает массив значений типа object[]
, преобразованных из целевых в исходные. Этот метод должен возвращать следующее:
BindableProperty.UnsetValue
в позицииi
— указывает, что преобразователь не может предоставить значение для исходной привязки по индексуi
и что для него не задано значение.Binding.DoNothing
в позицииi
— указывает, что для исходной привязки не должно быть задано значение в индексеi
.null
— указывает, что преобразователь не может выполнить преобразование или что он не поддерживает преобразование в этом направлении.
Использование IMultiValueConverter
IMultiValueConverter
используется путем создания экземпляра в словаре ресурсов. Затем на него добавляется ссылка с помощью расширения разметки StaticResource
для установки свойства MultiBinding.Converter
.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.MultiBindingConverterPage"
Title="MultiBinding Converter demo">
<ContentPage.Resources>
<local:AllTrueMultiConverter x:Key="AllTrueConverter" />
<local:InverterConverter x:Key="InverterConverter" />
</ContentPage.Resources>
<CheckBox>
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource AllTrueConverter}">
<Binding Path="Employee.IsOver16" />
<Binding Path="Employee.HasPassedTest" />
<Binding Path="Employee.IsSuspended"
Converter="{StaticResource InverterConverter}" />
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</ContentPage>
В этом примере объект MultiBinding
использует экземпляр AllTrueMultiConverter
, чтобы задать для свойства CheckBox.IsChecked
значение true
, если трем объектам Binding
присваивается значение true
. В противном случае свойству CheckBox.IsChecked
присваивается значение false
.
По умолчанию свойство CheckBox.IsChecked
использует привязку TwoWay
. Таким образом, метод ConvertBack
экземпляра AllTrueMultiConverter
выполняется, когда пользователь не использует CheckBox
, задавая для значений привязки к источнику значение свойства CheckBox.IsChecked
.
Ниже приведен эквивалентный код на C#:
public class MultiBindingConverterCodePage : ContentPage
{
public MultiBindingConverterCodePage()
{
BindingContext = new GroupViewModel();
CheckBox checkBox = new CheckBox();
checkBox.SetBinding(CheckBox.IsCheckedProperty, new MultiBinding
{
Bindings = new Collection<BindingBase>
{
new Binding("Employee1.IsOver16"),
new Binding("Employee1.HasPassedTest"),
new Binding("Employee1.IsSuspended", converter: new InverterConverter())
},
Converter = new AllTrueMultiConverter()
});
Title = "MultiBinding converter demo";
Content = checkBox;
}
}
Строки формата
MultiBinding
может форматировать результат множественной привязки, отображаемый в виде строки, со свойством StringFormat
. Для этого свойства можно задать стандартную строку форматирования .NET с заполнителями, которая определяет способ форматирования результата множественной привязки.
<Label>
<Label.Text>
<MultiBinding StringFormat="{}{0} {1} {2}">
<Binding Path="Employee1.Forename" />
<Binding Path="Employee1.MiddleName" />
<Binding Path="Employee1.Surname" />
</MultiBinding>
</Label.Text>
</Label>
В этом примере свойство StringFormat
объединяет три привязанных значения в одну строку, отображаемую Label
.
Ниже приведен эквивалентный код на C#:
Label label = new Label();
label.SetBinding(Label.TextProperty, new MultiBinding
{
Bindings = new Collection<BindingBase>
{
new Binding("Employee1.Forename"),
new Binding("Employee1.MiddleName"),
new Binding("Employee1.Surname")
},
StringFormat = "{0} {1} {2}"
});
Внимание
Число параметров в формате составной строки не должно превышать число дочерних Binding
объектов в MultiBinding
.
При установке свойств Converter
и StringFormat
сначала к значению данных применяется преобразователь, а затем применяется StringFormat
.
См. сведения в статье Форматирование строк Xamarin.Forms.
Предоставление резервных значений
Повысить надежность привязок данных можно, определив резервные значения, которые будут использоваться в случае сбоя привязки. Для этого при необходимости можно определить свойства FallbackValue
и TargetNullValue
в объекте MultiBinding
.
MultiBinding
будет использовать FallbackValue
, когда метод Convert
экземпляра IMultiValueConverter
возвращает BindableProperty.UnsetValue
. Это означает, что преобразователь не создал значение. MultiBinding
будет использовать TargetNullValue
, когда метод Convert
экземпляра IMultiValueConverter
возвращает null
. Это означает, что преобразователь не может выполнить преобразование.
См. сведения в статье Резервные значения привязок Xamarin.Forms.
Вложение объектов Nest MultiBinding
MultiBinding
объекты могут быть вложенными, чтобы при вычислении нескольких объектов MultiBinding
значение возвращалось через экземпляр IMultiValueConverter
.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.NestedMultiBindingPage"
Title="Nested MultiBinding demo">
<ContentPage.Resources>
<local:AllTrueMultiConverter x:Key="AllTrueConverter" />
<local:AnyTrueMultiConverter x:Key="AnyTrueConverter" />
<local:InverterConverter x:Key="InverterConverter" />
</ContentPage.Resources>
<CheckBox>
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource AnyTrueConverter}">
<MultiBinding Converter="{StaticResource AllTrueConverter}">
<Binding Path="Employee.IsOver16" />
<Binding Path="Employee.HasPassedTest" />
<Binding Path="Employee.IsSuspended" Converter="{StaticResource InverterConverter}" />
</MultiBinding>
<Binding Path="Employee.IsMonarch" />
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</ContentPage>
В этом примере объект MultiBinding
использует свой экземпляр AnyTrueMultiConverter
, чтобы задать для свойства CheckBox.IsChecked
значение true
, если всем объектам Binding
во внутреннем объекте MultiBinding
присваивается значение true
или если объекту Binding
во внешнем объекте MultiBinding
присваивается значение true
. В противном случае свойству CheckBox.IsChecked
присваивается значение false
.
Использование привязки RelativeSource в MultiBinding
Объект MultiBinding
поддерживает относительные привязки, которые позволяют задать источник привязки относительно положения целевого объекта привязки.
<ContentPage ...
xmlns:local="clr-namespace:DataBindingDemos"
xmlns:xct="clr-namespace:Xamarin.CommunityToolkit.UI.Views;assembly=Xamarin.CommunityToolkit">
<ContentPage.Resources>
<local:AllTrueMultiConverter x:Key="AllTrueConverter" />
<ControlTemplate x:Key="CardViewExpanderControlTemplate">
<xct:Expander BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
IsExpanded="{Binding IsExpanded, Source={RelativeSource TemplatedParent}}"
BackgroundColor="{Binding CardColor}">
<xct:Expander.IsVisible>
<MultiBinding Converter="{StaticResource AllTrueConverter}">
<Binding Path="IsExpanded" />
<Binding Path="IsEnabled" />
</MultiBinding>
</xct:Expander.IsVisible>
<xct:Expander.Header>
<Grid>
<!-- XAML that defines Expander header goes here -->
</Grid>
</xct:Expander.Header>
<Grid>
<!-- XAML that defines Expander content goes here -->
</Grid>
</xct:Expander>
</ControlTemplate>
</ContentPage.Resources>
<StackLayout>
<controls:CardViewExpander BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewExpanderControlTemplate}"
IsEnabled="True"
IsExpanded="True" />
</StackLayout>
</ContentPage>
Примечание.
Элемент управления Expander
теперь входит в набор инструментов Xamarin Community Toolkit.
В этом примере режим относительной привязки TemplatedParent
используется для привязки из шаблона элемента управления к экземпляру объекта среды выполнения, к которому применяется шаблон. Expander
— это корневой элемент ControlTemplate
, у которого есть BindingContext
с заданным экземпляром объекта среды выполнения, к которому применяется шаблон. Следовательно, Expander
с дочерними элементами разрешают свои выражения привязки и объекты Binding
для свойств объекта CardViewExpander
. MultiBinding
использует экземпляр AllTrueMultiConverter
, чтобы задать для свойства Expander.IsVisible
значение true
, если двум объектам Binding
присваивается значение true
. В противном случае свойству Expander.IsVisible
присваивается значение false
.
Дополнительные сведения об относительных привязках Xamarin.Forms см. в этой статье. Дополнительные сведения о шаблонах элементов управления см. в разделе Шаблоны элементов управления Xamarin.Forms.