Xamarin Community Toolkit C# Markup

Beispiel herunterladen. Xamarin.CommunityToolkit.MarkupSample herunterladen

C#-Markup ist eine Reihe von Fluent-Hilfsmethoden und -klassen, um den Prozess des Erstellens deklarativer Xamarin.Forms-Benutzeroberflächen in C# zu vereinfachen. Die fluent-API, die Xamarin.CommunityToolkit.Markup von C#-Markup bereitgestellt wird, ist im Namespace verfügbar.

Ebenso wie bei XAML ermöglicht C#-Markup eine saubere Trennung zwischen UI-Markup und UI-Logik. Dies kann erreicht werden, indem Ui-Markup- und UI-Logik in verschiedene Teilklassendateien getrennt werden. Für eine Anmeldeseite würde sich das UI-Markup beispielsweise in einer Datei namens LoginPage.cs befinden, während sich die UI-Logik in einer Datei namens "LoginPage.logic.cs" befindet.

Die neueste Version von C#-Markup erfordert Xamarin.Forms 5 und ist im Xamarin.CommunityToolkit.Markup NuGet-Paket verfügbar.

C#-Markup ist auf allen Plattformen verfügbar, die von Xamarin.Forms unterstützt werden.

Hinweis

Die Vorschauversion des C#-Markups ist in Xamarin.Forms 4.6 bis 4.8 als experimentelles Feature verfügbar.

So migrieren Sie von der C#-Markupvorschauversion zu XCT C#-Markup:

  1. Aktualisieren auf Xamarin.Forms Forms 5.
  2. Installieren Sie das Xamarin.CommunityToolkit.Markup NuGet-Paket.
  3. Ändern Sie alle Verweise auf den Xamarin.Forms.Markup Namespace in Xamarin.CommunityToolkit.Markup, und stellen Sie sicher, dass Sie in Ihre Markupdateien einschließen using Xamarin.Forms; .
  4. Aktualisieren Sie Font bei Bedarf Hilfsaufrufe. Font Jetzt hat family es den ersten Parameter anstelle von size. Ersetzen .Font(15) Sie z. B. durch .Font(size: 15) oder .FontSize(15).

Wenn Sie bereits mit der Vorschauversion von C#-Markup vertraut sind, finden Sie weitere Funktionen im Xamarin Community Toolkit weiter unten.

Einfaches Beispiel

Das folgende Beispiel zeigt das Festlegen des Seiteninhalts auf eine neue Grid , die ein Label und ein Entry, in C#enthält:

Grid grid = new Grid();

Label label = new Label { Text = "Code: " };
grid.Children.Add(label, 0, 1);

Entry entry = new Entry
{
    Placeholder = "Enter number", Keyboard = Keyboard.Numeric, BackgroundColor = Color.AliceBlue, TextColor = Color.Black, FontSize = 15,
    HeightRequest = 44, Margin = fieldMargin
};
grid.Children.Add(entry, 0, 2);
Grid.SetColumnSpan(entry, 2);
entry.SetBinding(Entry.TextProperty, new Binding("RegistrationCode"));

Content = grid;

In diesem Beispiel wird ein Grid Objekt mit untergeordneten und Entry untergeordneten Label Objekten erstellt. Der Label Text wird angezeigt, und die Entry Daten werden an die RegistrationCode Eigenschaft des Viewmodels gebunden. Jede untergeordnete Ansicht ist so festgelegt, dass sie in einer bestimmten Zeile im GridBereich angezeigt wird und die Entry alle Spalten in der Grid. Darüber hinaus wird die Höhe des Entry Elements festgelegt, zusammen mit seiner Tastatur, Farben, dem Schriftgrad des Texts und dessen Margin. Schließlich wird die Page.Content Eigenschaft auf das Grid Objekt festgelegt.

Mit dem C#-Markup kann dieser Code mithilfe der Fluent-API erneut geschrieben werden:

Content = new Grid { Children =
{
    new Label { Text = "Code:" }
               .Row (BodyRow.CodeHeader) .Column (BodyCol.Header),

    new Entry { Placeholder = "Enter number", Keyboard = Keyboard.Numeric, BackgroundColor = Color.AliceBlue, TextColor = Color.Black } .FontSize (15)
               .Row (BodyRow.CodeEntry) .ColumnSpan (All<BodyCol>()) .Margin (fieldMargin) .Height (44)
               .Bind (nameof(vm.RegistrationCode))
}}};

Dieses Beispiel ist identisch mit dem vorherigen Beispiel, aber die C#-Markup fluent-API vereinfacht den Prozess der Erstellung der Benutzeroberfläche in C#.

Hinweis

C#-Markup enthält Erweiterungsmethoden, die bestimmte Ansichtseigenschaften festlegen. Diese Erweiterungsmethoden sollen nicht alle Eigenschaftssatzer ersetzen. Stattdessen sind sie so konzipiert, dass sie die Codelesbarkeit verbessern und in Kombination mit Eigenschaftensatzern verwendet werden können. Es wird empfohlen, immer eine Erweiterungsmethode zu verwenden, wenn eine für eine Eigenschaft vorhanden ist, aber Sie können Ihr bevorzugtes Gleichgewicht auswählen.

Namespace-Verwendungen

Um C#-Markup zu verwenden, schließen Sie die folgenden using Anweisungen in Ihre Markupdateien ein:

using Xamarin.Forms;
using Xamarin.CommunityToolkit.Markup;

Wenn Sie Ihr Markup für Folgendes entwerfen:

  • NUR LTR: auch einschließen using Xamarin.CommunityToolkit.Markup.LeftToRight;
  • NUR RTL: auch einschließen using Xamarin.CommunityToolkit.Markup.RightToLeft;
  • Sowohl LTR als auch RTL: Enthalten LeftToRight oder RightToLeft Namespaces nicht

Wenn Sie mit Grid Zeilen und Spalten arbeiten möchten, schließen Sie auch dies ein using static Xamarin.CommunityToolkit.Markup.GridRowsColumns;.

Datenbindung

C#-Markup enthält eine Bind Erweiterungsmethode zusammen mit Überladungen, die eine Datenbindung zwischen einer bindungsfähigen Ansichtseigenschaft und einer angegebenen Eigenschaft erstellt. Die Bind Methode kennt die Standardbindungseigenschaft für die Mehrzahl der Steuerelemente, die in Xamarin.Forms enthalten sind. Daher ist es in der Regel nicht erforderlich, die Zieleigenschaft bei Verwendung dieser Methode anzugeben. Sie können auch die Standardbindungseigenschaft für zusätzliche Steuerelemente registrieren:

DefaultBindableProperties.Register(
  HoverButton.CommandProperty,
  RadialGauge.ValueProperty
);

Die Bind Methode kann verwendet werden, um an eine bindungsfähige Eigenschaft zu binden:

new Label { Text = "No data available" }
           .Bind (Label.IsVisibleProperty, nameof(vm.Empty))

Darüber hinaus kann die BindCommand Erweiterungsmethode an die Standard Command - und CommandParameter Eigenschaften eines Steuerelements in einem einzigen Methodenaufruf binden:

new TextCell { Text = "Tap me" }
              .BindCommand (nameof(vm.TapCommand))

Standardmäßig ist die CommandParameter Bindung an den Bindungskontext gebunden. Sie können auch den Bindungspfad und die Quelle für die CommandCommandParameter Bindungen angeben:

new TextCell { Text = "Tap Me" }
              .BindCommand (nameof(vm.TapCommand), vm, nameof(Item.Id))

In diesem Beispiel ist der Bindungskontext eine Item Instanz, sodass Sie keine Quelle für die IdCommandParameter Bindung angeben müssen.

Wenn Sie nur an die Bindung binden Commandmüssen, können Sie das parameterPath Argument der BindCommand Methode übergebennull. Alternativ können Sie die Bind Methode verwenden.

Sie können auch die Standard Command - und CommandParameter Eigenschaften für zusätzliche Steuerelemente registrieren:

DefaultBindableProperties.RegisterCommand(
    (CustomViewA.CommandProperty, CustomViewA.CommandParameterProperty),
    (CustomViewB.CommandProperty, CustomViewB.CommandParameterProperty)
);

Inlinekonvertercode kann mit den convert Parametern convertBack an die Bind Methode übergeben werden:

new Label { Text = "Tree" }
           .Bind (Label.MarginProperty, nameof(TreeNode.TreeDepth),
                  convert: (int depth) => new Thickness(depth * 20, 0, 0, 0))

Typsichere Konverterparameter werden ebenfalls unterstützt:

new Label { }
           .Bind (nameof(viewModel.Text),
                  convert: (string text, int repeat) => string.Concat(Enumerable.Repeat(text, repeat)))

Darüber hinaus können Konvertercode und Instanzen mit der FuncConverter Klasse erneut verwendet werden:

FuncConverter<int, Thickness> treeMarginConverter = new FuncConverter<int, Thickness>(depth => new Thickness(depth * 20, 0, 0, 0));
new Label { Text = "Tree" }
           .Bind (Label.MarginProperty, nameof(TreeNode.TreeDepth), converter: treeMarginConverter),

Die FuncConverter Klasse unterstützt CultureInfo auch Objekte:

cultureAwareConverter = new FuncConverter<DateTimeOffset, string, int>(
    (date, daysToAdd, culture) => date.AddDays(daysToAdd).ToString(culture)
);

Es ist auch möglich, datenbindung an Span Objekte zu binden, die mit der FormattedText Eigenschaft angegeben werden:

new Label { } .FormattedText (
    new Span { Text = "Built with " },
    new Span { TextColor = Color.Blue, TextDecorations = TextDecorations.Underline }
              .BindTapGesture (nameof(vm.ContinueToCSharpForMarkupCommand))
              .Bind (nameof(vm.Title))
)

Gestenerkennung

Commandund CommandParameter Eigenschaften können datengebunden GestureElement sein und View Typen mithilfe der BindClickGestureBindSwipeGestureMethoden , und BindTapGesture Erweiterungsmethoden:

new Label { Text = "Tap Me" }
           .BindTapGesture (nameof(vm.TapCommand))

In diesem Beispiel wird eine Gesteerkennung des angegebenen Typs erstellt, und es wird der Label. Die Bind*Gesture Erweiterungsmethoden bieten dieselben Parameter wie die BindCommand Erweiterungsmethoden. Standardmäßig Bind*Gesture wird die Bindung jedoch nicht gebunden CommandParameter, während BindCommand dies der Fall ist.

Verwenden Sie die ClickGestureMethoden , SwipeGesturePanGesturePinchGestureTapGesture um eine Gestenerkennung mit Parametern zu initialisieren:

new Label { Text = "Tap Me" }
           .TapGesture (g => g.Bind(nameof(vm.DoubleTapCommand)).NumberOfTapsRequired = 2)

Da es sich bei einer Gestenerkennung um eine BindableObjectGeste handelt, können Sie die Bind Methoden und BindCommand Erweiterungsmethoden verwenden, wenn Sie sie initialisieren. Sie können auch benutzerdefinierte Gestenerkennungstypen mit der Gesture<TGestureElement, TGestureRecognizer> Erweiterungsmethode initialisieren.

Layout

C#-Markup enthält eine Reihe von Layouterweiterungsmethoden, die die Positionierung von Ansichten in Layouts und Inhalten in Ansichten unterstützen:

type Erweiterungsmethoden
FlexLayout AlignSelf, Basis, Grow, Menu, Order, Shrink
Grid Row, Column, RowSpan, ColumnSpan
Label TextLeft, TextCenterHorizontal, TextRight
TextTop, TextCenterVertical, TextBottom
TextCenter
IPaddingElement (z. B. Layout) Padding, Paddings
LayoutOptions Left, CenterHorizontal, FillHorizontal, Right
LeftExpand, CenterExpandHorizontal, FillExpandHorizontal, RightExpand
Top, Bottom, CenterVertical, FillVertical
TopExpand, BottomExpand, CenterExpandVertical, FillExpandVertical
Center, Fill, CenterExpand, FillExpand
View Margin, Margins
VisualElement Height, Width, MinHeight, MinWidth, Size, MinSize

Unterstützung von links nach rechts und rechts nach links

Für C#-Markup, das für die Unterstützung von links nach rechts (LTR) oder rechts-nach-links-Flussrichtung (RTL) ausgelegt ist, bieten die oben aufgeführten Erweiterungsmethoden den intuitivsten Satz von Namen: Left, RightTop und Bottom.

Um die richtigen Methoden für die linke und rechte Erweiterung verfügbar zu machen und im Prozess explizit festzulegen, für welche Flussrichtung das Markup ausgelegt ist, schließen Sie eine der folgenden beiden using Direktiven ein: using Xamarin.CommunityToolkit.Markup.LeftToRight;oder using Xamarin.CommunityToolkit.Markup.RightToLeft;.

Für C#-Markup, das sowohl die Richtung von links nach rechts als auch von rechts nach links unterstützt, empfiehlt es sich, die Erweiterungsmethoden in der folgenden Tabelle anstelle einer der oben genannten Namespaces zu verwenden:

type Erweiterungsmethoden
Label TextStart, TextEnd
LayoutOptions Start, End
StartExpand, EndExpand

Layoutlinienkonvention

Die empfohlene Konvention besteht darin, alle Layouterweiterungsmethoden für eine Ansicht in einer einzelnen Zeile in der folgenden Reihenfolge zu platzieren:

  1. Die Zeile und Spalte, die die Ansicht enthält.
  2. Ausrichtung innerhalb der Zeile und Spalte.
  3. Seitenränder um die Ansicht.
  4. Ansichtsgröße.
  5. Abstand innerhalb der Ansicht.
  6. Inhaltsausrichtung innerhalb des Abstands.

Der folgende Code zeigt ein Beispiel für diese Konvention:

new Label { }
           .Row (BodyRow.Prompt) .ColumnSpan (All<BodyCol>()) .FillExpandHorizontal () .CenterVertical () .Margin (fieldNameMargin) .TextCenterHorizontal () // Layout line

Durch konsistentes Folgen der Konvention können Sie C#-Markup schnell lesen und eine mentale Karte erstellen, auf der sich der Ansichtsinhalt in der Benutzeroberfläche befindet.

Zeilen und Spalten im Raster

Enumerationen können verwendet werden, um Zeilen und Spalten zu definieren Grid , anstatt Zahlen zu verwenden. Dies bietet den Vorteil, dass die Neunummerierung beim Hinzufügen oder Entfernen von Zeilen oder Spalten nicht erforderlich ist.

Wichtig

Das Definieren von Grid Zeilen und Spalten mithilfe von Enumerationen erfordert die folgende using Direktive: using static Xamarin.CommunityToolkit.Markup.GridRowsColumns;

Der folgende Code zeigt ein Beispiel für das Definieren und Verwenden Grid von Zeilen und Spalten mithilfe von Enumerationen:

using Xamarin.Forms;
using Xamarin.CommunityToolkit.Markup;
using Xamarin.CommunityToolkit.Markup.LeftToRight;
using static Xamarin.CommunityToolkit.Markup.GridRowsColumns;
// ...

enum BodyRow { Prompt, CodeHeader, CodeEntry, Button }
enum BodyCol { FieldLabel, FieldValidation }

View Build() => new Grid
{
    RowDefinitions = Rows.Define(
        (BodyRow.Prompt    , 170 ),
        (BodyRow.CodeHeader, 75  ),
        (BodyRow.CodeEntry , Auto),
        (BodyRow.Button    , Auto)
    ),

    ColumnDefinitions = Columns.Define(
        (BodyCol.FieldLabel     , Stars(0.5)),
        (BodyCol.FieldValidation, Star)
    ),

    Children =
    {
        new Label { LineBreakMode = LineBreakMode.WordWrap } .FontSize (15) .Bold ()
                   .Row (BodyRow.Prompt) .ColumnSpan (All<BodyCol>()) .FillExpandHorizontal () .CenterVertical () .Margin (fieldNameMargin) .TextCenterHorizontal ()
                   .Bind (nameof(vm.RegistrationPrompt)),

        new Label { Text = "Registration code" } .Bold ()
                   .Row (BodyRow.CodeHeader) .Column(BodyCol.FieldLabel) .Bottom () .Margin (fieldNameMargin),

        new Label { } .Italic ()
                   .Row (BodyRow.CodeHeader) .Column (BodyCol.FieldValidation) .Right () .Bottom () .Margin (fieldNameMargin)
                   .Bind (nameof(vm.RegistrationCodeValidationMessage)),

        new Entry { Placeholder = "E.g. 123456", Keyboard = Keyboard.Numeric, BackgroundColor = Color.AliceBlue, TextColor = Color.Black } .FontSize (15)
                   .Row (BodyRow.CodeEntry) .ColumnSpan (All<BodyCol>()) .Margin (fieldMargin) .Height (44)
                   .Bind (nameof(vm.RegistrationCode), BindingMode.TwoWay),

        new Button { Text = "Verify" } .Style (FilledButton)
                    .Row (BodyRow.Button) .ColumnSpan (All<BodyCol>()) .FillExpandHorizontal () .Margin (PageMarginSize)
                    .Bind (Button.IsVisibleProperty, nameof(vm.CanVerifyRegistrationCode))
                    .Bind (nameof(vm.VerifyRegistrationCodeCommand)),
    }
};

Darüber hinaus können Sie Zeilen und Spalten ohne Enumerationen präzise definieren:

new Grid
{
    RowDefinitions = Rows.Define (Auto, Star, 20),
    ColumnDefinitions = Columns.Define (Auto, Star, 20, 40)
    // ...
}

Schriftarten

Steuerelemente, die implementiert werdenIFontElement, können die BoldFontSizeMethoden , , und ItalicFont Erweiterungsmethoden aufrufen, um die Darstellung des durch das Steuerelement angezeigten Texts festzulegen, z. B.:

  • Button
  • DatePicker
  • Editor
  • Entry
  • Label
  • Picker
  • SearchBar
  • Span
  • TimePicker

Effekte

Effekte können mit der Effects Erweiterungsmethode an Steuerelemente angefügt werden:

new Button { Text = "Tap Me" }
            .Effects (new ButtonMixedCaps())

Logikintegration

Die Invoke Erweiterungsmethode kann verwendet werden, um Code-Inline in Ihrem C#-Markup auszuführen:

new ListView { } .Invoke (l => l.ItemTapped += OnListViewItemTapped)

Darüber hinaus können Sie mit der Assign Erweiterungsmethode auf ein Steuerelement außerhalb des UI-Markups (in der Ui-Logikdatei) zugreifen:

new ListView { } .Assign (out MyListView)

Stile

Im folgenden Beispiel wird gezeigt, wie implizite und explizite Formatvorlagen mithilfe von C# Markup erstellt werden:

using Xamarin.Forms;
using Xamarin.CommunityToolkit.Markup;

namespace CSharpForMarkupDemos
{
    public static class Styles
    {
        static Style<Button> buttons, filledButton;
        static Style<Label> labels;
        static Style<Span> link;

        #region Implicit styles

        public static ResourceDictionary Implicit => new ResourceDictionary { Buttons, Labels };

        public static Style<Button> Buttons => buttons ?? (buttons = new Style<Button>(
            (Button.HeightRequestProperty, 44),
            (Button.FontSizeProperty, 13),
            (Button.HorizontalOptionsProperty, LayoutOptions.Center),
            (Button.VerticalOptionsProperty, LayoutOptions.Center)
        ));

        public static Style<Label> Labels => labels ?? (labels = new Style<Label>(
            (Label.FontSizeProperty, 13),
            (Label.TextColorProperty, Color.Black)
        ));

        #endregion Implicit styles

        #region Explicit styles

        public static Style<Button> FilledButton => filledButton ?? (filledButton = new Style<Button>(
            (Button.TextColorProperty, Color.White),
            (Button.BackgroundColorProperty, Color.FromHex("#1976D2")),
            (Button.CornerRadiusProperty, 5)
        )).BasedOn(Buttons);

        public static Style<Span> Link => link ?? (link = new Style<Span>(
            (Span.TextColorProperty, Color.Blue),
            (Span.TextDecorationsProperty, TextDecorations.Underline)
        ));

        #endregion Explicit styles
    }
}

Die impliziten Formatvorlagen können verwendet werden, indem sie in das Anwendungsressourcenverzeichnis geladen werden:

public App()
{
    Resources = Styles.Implicit;
    // ...
}

Explizite Formatvorlagen können mit der Style Erweiterungsmethode verwendet werden.

using static CSharpForMarkupExample.Styles;
// ...

new Button { Text = "Tap Me" } .Style (FilledButton),

Hinweis

Zusätzlich zur Style Erweiterungsmethode gibt es auch ApplyToDerivedTypesMethoden , BasedOnAddund CanCascade Erweiterungsmethoden.

Alternativ können Sie ihre eigenen Formatierungserweiterungsmethoden erstellen:

public static TButton Filled<TButton>(this TButton button) where TButton : Button
{
    button.Buttons(); // Equivalent to Style .BasedOn (Buttons)
    button.TextColor = Color.White;
    button.BackgroundColor = Color.Red;
    return button;
}

Die Filled Erweiterungsmethode kann dann wie folgt verwendet werden:

new Button { Text = "Tap Me" } .Filled ()

Plattformeigenschaften

Die Invoke Erweiterungsmethode kann verwendet werden, um plattformspezifische Methoden anzuwenden. Um jedoch Nichtdeutigkeitsfehler zu vermeiden, enthalten using Sie keine Richtlinien für die Xamarin.Forms.PlatformConfiguration.*Specific Namespaces direkt. Erstellen Sie stattdessen einen Namespace-Alias und nutzen Sie die Plattformspezifische über den Alias:

using Xamarin.Forms;
using Xamarin.CommunityToolkit.Markup;
using PciOS = Xamarin.Forms.PlatformConfiguration.iOSSpecific;
// ...

new ListView { } .Invoke (l => PciOS.ListView.SetGroupHeaderStyle(l, PciOS.GroupHeaderStyle.Grouped))

Wenn Sie außerdem bestimmte plattformspezifische Methoden häufig nutzen, können Sie fließende Erweiterungsmethoden für sie in Ihrer eigenen Erweiterungsklasse erstellen:

public static T iOSGroupHeaderStyle<T>(this T listView, PciOS.GroupHeaderStyle style) where T : Forms.ListView
{
  PciOS.ListView.SetGroupHeaderStyle(listView, style);
  return listView;
}

Die Erweiterungsmethode kann dann wie folgt verwendet werden:

new ListView { } .iOSGroupHeaderStyle(PciOS.GroupHeaderStyle.Grouped)

Weitere Informationen zu plattformspezifischen Funktionen finden Sie unter Android-Plattformfeatures, iOS-Plattformfeatures und Windows-Plattformfeatures.

Eine empfohlene Reihenfolge und Gruppierung von Eigenschaften und Hilfsmethoden ist:

  • Zweck: Alle Eigenschaften- oder Hilfsmethoden, deren Wert den Zweck des Steuerelements (z. B. Text, Placeholder.Assign) identifiziert.
  • Andere: Alle Eigenschaften oder Hilfsmethoden, die nicht Layout oder Bindung sind, auf derselben Linie oder mehreren Zeilen.
  • Layout: Layout wird nach innen angeordnet: Zeilen und Spalten, Layoutoptionen, Rand, Größe, Abstand und Inhaltsausrichtung.
  • Bindung: Die Datenbindung wird am Ende der Methodenkette mit einer gebundenen Eigenschaft pro Zeile ausgeführt. Wenn die Standardbindungseigenschaft gebunden ist, sollte es sich am Ende der Methodenkette befinden.

Der folgende Code zeigt ein Beispiel für die folgenden Konventionen:

new Button { Text = "Verify" /* purpose */ } .Style (FilledButton) // other
            .Row (BodyRow.Button) .ColumnSpan (All<BodyCol>()) .FillExpandHorizontal () .Margin (10) // layout
            .Bind (Button.IsVisibleProperty, nameof(vm.CanVerifyRegistrationCode)) // bind
            .Bind (nameof(vm.VerifyRegistrationCodeCommand)), // bind default

new Label { }
           .Assign (out animatedMessageLabel) // purpose
           .Invoke (label => label.SizeChanged += MessageLabel_SizeChanged) // other
           .Row (BodyRow.Message) .ColumnSpan (All<BodyCol>()) // layout
           .Bind (nameof(vm.Message)), // bind default

Durch die konsistente Anwendung dieser Konvention können Sie Ihr C#-Markup schnell scannen und ein mentales Bild des UI-Layouts erstellen.

Zusätzliche Funktionalität im Xamarin Community Toolkit

Im Xamarin Community Toolkit fügt C# Markup Unterstützung für:

  • MultiBinding
  • MultiConverter
  • BindableLayout
  • RelativeLayout
  • DynamicResource

Multi-Binding-Hilfser

Neue Überladungen des Bind Hilfsgebers bieten Unterstützung für multibindung.

Es gibt Überladungen, die 2, 3 oder 4 Bindungen mit einem typsicheren Inlinekonverter unterstützen:

new Label { }
    .Bind (Label.TextProperty,
        new Binding (nameof(vm.Name)),
        new Binding (nameof(vm.Score)),
        ((string name, bool score) v) => $"{v.name} Score: { v.score }"
    )

Der Wert für alle Bindungen werden als ValueTuple typgeschützte Elemente übergeben.

Sie können auch einen typsicheren Konverterparameter übergeben:

new Label { }
    .Bind (Label.TextProperty,
        new Binding (nameof(vm.Name)),
        new Binding (nameof(vm.Score)),
        ((string name, int Score) v, bool winner) => $"{v.name} Score: { v.Score } Winner: { winner }",
        converterParameter: true
    )

Hier bool winner wird der Wert aus dem converterParameter.

Sie können eine Zwei-Wege-Konvertierung inline angeben:

new Entry { }
    .Bind(Entry.TextProperty,
        new Binding (nameof(vm.Emoticon)),
        new Binding (nameof(vm.Repeat)),
        ((char emoticon, int repeat) v) => new string(v.emoticon, v.repeat),
        (string emoticons) => (emoticons[0], emoticons.Length)
    );

In der Funktion geben Sie dasselbe zurückValueTuple, das Sie in der convertBackconvert Funktion erhalten.

Sie können mehr als 4 Bindungen angeben, indem Sie einen Mehrwertkonverter übergeben:

new Label { }
    .Bind(Label.TextProperty,
        new List<BindingBase> {
            new Binding(nameof(vm.Name)),
            new Binding(nameof(vm.Score))
        },
        new FuncMultiConverter<string, bool>(
            (object[] values, bool winner) => $"{values[0]} Score: { values[1] } Winner: { winner }"
        )
    )

Dies ist nicht typsicher: Sie müssen die Werte in die convert Funktion umwandeln.

Die FuncMultiConverter Klassen implementieren IMultiValueConverter. Die klasse, die für eine beliebige Anzahl von Bindungen verwendet wird FuncMultiConverter<TDest, TParam>, die nur den Zieltyp und den Parametertyp des Konvertierungsmoduls angibt. Die Bindungswerte werden als Eine object[]übergeben.

Es gibt auch typsichere generische Überladungen für FuncMultiConverter die 2, 3 oder 4 Werte (und optional einen Konvertierungsparameter). Diese Klassen übergeben die Bindungswerte in einem typsicheren ValueTupleTyp .

Bindungsfähige Layouthilfen

Die EmptyView, , ItemsSourceEmptyViewTemplateItemTemplate , und ItemTemplateSelector Hilfser bieten Unterstützung für bindungsfähige Layouts auf allen Layout<View> Typen:

new StackLayout { }
    .ItemTemplate (() =>
        new Label { }
            .Bind (nameof(Item.Name))
        )
    .ItemsSource (vm.Items)

RelativeLayout-Hilfser

Mit den Children Hilfsern können Sie eingeschränkte untergeordnete Ansichten zu einem RelativeLayouthinzufügen.

Um eingeschränkte Ansichten aus normalen Ansichten zu erstellen, wurden vier Hilfser hinzugefügt: UnconstrainedConstraints und zwei Constrain Überladungen. Jede Überladung gibt eine entsprechende *ConstrainedView Klasse zurück, die eine Fluent-API zum Festlegen von Einschränkungen für RelativeLayout untergeordnete Ansichten bietet.

Einschränkungen für eine untergeordnete Ansicht können mit:

  • Ein einzelner Bounds-Ausdruck.
  • Separate Ausdrücke für X, Y, Width und Height.
  • Separate Constraint Instanzen für X, Y, Width und Height. Jede dieser Einschränkungsinstanzen verfügt über Überladungen für:
    • Konstante.
    • Relativ zum übergeordneten Element.
    • Relativ zur Ansicht.

Der folgende Code zeigt Beispiele für die Verwendung dieser Hilfshilfen:

new RelativeLayout { } .Children (
    new Label { } // Bounds constrained
        .Assign (out Label child0)
        .Constrain(() => new Rectangle(30, 20, layout.Height / 2, layout.Height / 4)),

    new Label { } // Expressions constrained
        .Constrain() .X      (() => 30)
                     .Y      (() => 20)
                     .Width  (() => layout.Height / 2)
                     .Height (() => layout.Height / 4),

    new Label { } // Constraints constrained - parent relative
        .Constraints() .X      (30)
                       .Y      (20)
                       .Width  (parent => parent.Height / 5)
                       .Height (parent => parent.Height / 10),

    new Label { } // Constraints constrained - view relative
        .Constraints() .X      (child0, (layout, view) => view.Bounds.Right + 10)
                       .Y      (child0, (layout, view) => view.Y)
                       .Width  (child0, (layout, view) => view.Width)
                       .Height (child0, (layout, view) => view.Height),
) .Assign (out layout)

Dynamische Ressourcenhilfen

Die Unterstützung RemoveDynamicResources für die DynamicResourceEinstellung dynamischer Ressourcen in einem Element: DynamicResources

new Label { }
    .DynamicResource (Label.TextProperty, "TextKey")

new Label { }
    .DynamicResources((Label.TextProperty     , "TextKey"),
                      (Label.TextColorProperty, "ColorKey"));