Xamarin.Forms 多重系結
多重系結可讓您將 物件的集合 Binding
附加至單一系結目標屬性。 它們會使用 MultiBinding
類別來建立,其會評估其 Binding
所有物件,並透過 IMultiValueConverter
應用程式提供的實例傳回單一值。 此外,當任何系結的數據變更時, MultiBinding
會重新評估其 Binding
所有物件。
類別 MultiBinding
會定義下列屬性:
Bindings
型IList<BindingBase>
別為 的 ,表示 實例內的MultiBinding
物件集合Binding
。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
,則除非您在其中一個系結上明確設定不同的Mode
值,否則會考慮TwoWay
集合中的所有系結。
定義 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 不要執行任何動作。 例如,若要指示 Xamarin.Forms 不要將值傳送至系結目標,或不要使用FallbackValue
。null
表示轉換子無法執行轉換,而且系結將使用TargetNullValue
。
重要
MultiBinding
從方法接收BindableProperty.UnsetValue
的 Convert
,必須定義其 FallbackValue
屬性。 同樣地, MultiBinding
從方法接收 null
的 Convert
必須定義其 TargetNullValue
propety。
方法 ConvertBack
會將系結目標轉換為來源系結值。 此方法接受四個自變數:
value
型object
別為 的 ,是系結目標所產生的值。targetTypes
型Type[]
別為 的 ,是要轉換成的類型數位。 陣列長度表示方法要傳回之建議值的數目和類型。parameter
類型object
為 的 ,是要使用的轉換器參數。culture
型CultureInfo
別為 的 ,是轉換子中使用的文化特性。
方法 ConvertBack
會傳回類型 object[]
為的值陣列,其已從目標值轉換回來源值。 此方法應該會傳回:
BindableProperty.UnsetValue
位於i
,表示轉換子無法在索引i
上提供來源系結的值,而且不會設定任何值。Binding.DoNothing
在 位置i
,表示在索引i
的來源系結上不會設定任何值。null
表示轉換子無法執行轉換,或不支援以這個方向進行轉換。
取用 IMultiValueConverter
IMultiValueConverter
藉由在資源字典中具現化它,然後使用標記延伸來參考它,以設定 MultiBinding.Converter
屬性來取用StaticResource
它:
<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
當使用者取消核取 時CheckBox
,會執行 實例的 AllTrueMultiConverter
方法,這會將來源系結值設定為 屬性的值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}"
});
重要
複合字串格式中的參數數目不能超過 中的MultiBinding
子Binding
物件數目。
設定 Converter
與 StringFormat
屬性時,轉換器會先套用至資料值,然後 StringFormat
套用 。
如需 Xamarin.Forms 中字串格式設定的詳細資訊,請參閱 Xamarin.Forms 字串格式設定。
提供後援值
定義系結程序失敗時要使用的後援值,即可讓數據系結更加健全。 這可藉由選擇性地定義 FallbackValue
物件上的 MultiBinding
和 TargetNullValue
屬性來完成。
MultiBinding
當實例的 IMultiValueConverter
方法傳回 BindableProperty.UnsetValue
時Convert
,會使用 ,FallbackValue
表示轉換子未產生值。 MultiBinding
當實例的 IMultiValueConverter
方法傳回 null
時Convert
,會使用 ,TargetNullValue
表示轉換子無法執行轉換。
如需系結後援的詳細資訊,請參閱 Xamarin.Forms 系結後援。
巢狀 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
,前提是內部MultiBinding
物件中的所有Binding
物件都評估為 true
,或前提是Binding
外部MultiBinding
物件中的物件評估為 true
。 否則,屬性 CheckBox.IsChecked
會設定為 false
。
在 MultiBinding 中使用 RelativeSource 系結
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
及其子系會針對 對象的屬性CardViewExpander
解析其系結表達式和 Binding
物件。 MultiBinding
會AllTrueMultiConverter
使用 實體來設定 Expander.IsVisible
屬性,true
前提是兩Binding
個物件評估為 true
。 否則,屬性 Expander.IsVisible
會設定為 false
。
如需相對繫結的詳細資訊,請參閱 Xamarin.Forms 相對繫結。 如需控件範本的詳細資訊,請參閱 Xamarin.Forms 控件範本。