Share via


Xamarin.Forms 多重系結

多重系結可讓您將 物件的集合 Binding 附加至單一系結目標屬性。 它們會使用 MultiBinding 類別來建立,其會評估其 Binding 所有物件,並透過 IMultiValueConverter 應用程式提供的實例傳回單一值。 此外,當任何系結的數據變更時, MultiBinding 會重新評估其 Binding 所有物件。

類別 MultiBinding 會定義下列屬性:

  • BindingsIList<BindingBase>別為 的 ,表示 實例內的 MultiBinding 物件集合Binding
  • ConverterIMultiValueConverter別為 的 ,表示用來將來源值轉換為目標值或從目標值轉換的轉換子。
  • ConverterParameterobject別為 的 ,表示要傳遞至 的 Converter選擇性參數。

屬性 Bindings 是 類別的內容屬性 MultiBinding ,因此不需要從 XAML 明確設定。

此外,類別 MultiBinding 會從 BindingBase 類別繼承下列屬性:

  • FallbackValueobject別為 的 ,表示當多重系結無法傳回值時要使用的值。
  • ModeBindingMode別為 ,表示多重系結數據流的方向。
  • StringFormatstring別為 的 ,指定當多重系結結果顯示為字串時,如何格式化。
  • TargetNullValueobject別為 ,表示在目標 wen 中使用的值,來源的值為 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 會在將值從來源系結傳播至系結目標時,呼叫這個方法。 此方法接受四個自變數:

  • valuesobject[]別為 的 ,是 中來源系結 MultiBinding 所產生的值陣列。
  • targetTypeType別為 的 ,是系結目標屬性的類型。
  • parameter類型 object為 的 ,是要使用的轉換器參數。
  • cultureCultureInfo別為 的 ,是轉換子中使用的文化特性。

方法會Convertobject傳回 ,表示已轉換的值。 此方法應該會傳回:

  • BindableProperty.UnsetValue 表示轉換子未產生值,而且系結將使用 FallbackValue
  • Binding.DoNothing 指示 Xamarin.Forms 不要執行任何動作。 例如,若要指示 Xamarin.Forms 不要將值傳送至系結目標,或不要使用 FallbackValue
  • null 表示轉換子無法執行轉換,而且系結將使用 TargetNullValue

重要

MultiBinding從方法接收BindableProperty.UnsetValueConvert ,必須定義其 FallbackValue 屬性。 同樣地, MultiBinding 從方法接收 nullConvert 必須定義其 TargetNullValue propety。

方法 ConvertBack 會將系結目標轉換為來源系結值。 此方法接受四個自變數:

  • valueobject別為 的 ,是系結目標所產生的值。
  • targetTypesType[]別為 的 ,是要轉換成的類型數位。 陣列長度表示方法要傳回之建議值的數目和類型。
  • parameter類型 object為 的 ,是要使用的轉換器參數。
  • cultureCultureInfo別為 的 ,是轉換子中使用的文化特性。

方法 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.IsCheckedtrue,前提是這三 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}"
});

重要

複合字串格式中的參數數目不能超過 中的MultiBindingBinding物件數目。

設定 ConverterStringFormat 屬性時,轉換器會先套用至資料值,然後 StringFormat 套用 。

如需 Xamarin.Forms 中字串格式設定的詳細資訊,請參閱 Xamarin.Forms 字串格式設定。

提供後援值

定義系結程序失敗時要使用的後援值,即可讓數據系結更加健全。 這可藉由選擇性地定義 FallbackValue 物件上的 MultiBindingTargetNullValue 屬性來完成。

MultiBinding當實例的 IMultiValueConverter 方法傳回 BindableProperty.UnsetValueConvert,會使用 ,FallbackValue表示轉換子未產生值。 MultiBinding當實例的 IMultiValueConverter 方法傳回 nullConvert,會使用 ,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.IsCheckedtrue,前提是內部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 物件。 MultiBindingAllTrueMultiConverter使用 實體來設定 Expander.IsVisible 屬性,true前提是兩Binding個物件評估為 true。 否則,屬性 Expander.IsVisible 會設定為 false

如需相對繫結的詳細資訊,請參閱 Xamarin.Forms 相對繫結。 如需控件範本的詳細資訊,請參閱 Xamarin.Forms 控件範本