Udostępnij za pośrednictwem


Część 2. Podstawowa składnia języka XAML

Język XAML jest przeznaczony głównie do tworzenia wystąpień i inicjowania obiektów. Jednak często właściwości muszą być ustawione na obiekty złożone, których nie można łatwo przedstawić jako ciągów XML, a czasami właściwości zdefiniowane przez jedną klasę muszą być ustawione w klasie podrzędnej. Te dwa potrzeby wymagają podstawowych funkcji składni XAML elementów właściwości i dołączonych właściwości.

Elementy właściwości

W języku XAML właściwości klas są zwykle ustawiane jako atrybuty XML:

<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large"
       TextColor="Aqua" />

Istnieje jednak alternatywny sposób ustawiania właściwości w języku XAML. Aby wypróbować tę alternatywę za pomocą TextColorpolecenia , najpierw usuń istniejące TextColor ustawienie:

<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large" />

Otwórz tag empty-element Label , oddzielając go do tagów początkowych i końcowych:

<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large">

</Label>

W tych tagach dodaj tagi początkowe i końcowe składające się z nazwy klasy i nazwy właściwości rozdzielone kropką:

<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large">
    <Label.TextColor>

    </Label.TextColor>
</Label>

Ustaw wartość właściwości jako zawartość tych nowych tagów, w następujący sposób:

<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large">
    <Label.TextColor>
        Aqua
    </Label.TextColor>
</Label>

Te dwa sposoby określania TextColor właściwości są funkcjonalnie równoważne, ale nie należy używać dwóch sposobów dla tej samej właściwości, ponieważ w rzeczywistości byłoby to ustawienie właściwości dwa razy i może być niejednoznaczne.

Dzięki tej nowej składni można wprowadzić przydatną terminologię:

  • Labeljest elementem obiektu. Jest to obiekt wyrażony Xamarin.Forms jako element XML.
  • Text, VerticalOptionsi FontSizeatrybutami właściwości. FontAttributes Są to Xamarin.Forms właściwości wyrażone jako atrybuty XML.
  • W tym ostatnim fragmencie TextColor kodu stał się elementem właściwości. Jest Xamarin.Forms to właściwość, ale jest teraz elementem XML.

Definicja elementów właściwości może początkowo wydawać się naruszeniem składni XML, ale nie jest. Kropka nie ma specjalnego znaczenia w formacie XML. Do dekodera Label.TextColor XML jest po prostu normalnym elementem podrzędnym.

Jednak w języku XAML ta składnia jest bardzo wyjątkowa. Jedną z reguł dotyczących elementów właściwości jest to, że nic innego nie może pojawić się w tagu Label.TextColor . Wartość właściwości jest zawsze definiowana jako zawartość między tagami start-element-property i end.

Składnia właściwości-elementu może być używana w więcej niż jednej właściwości:

<Label Text="Hello, XAML!"
       VerticalOptions="Center">
    <Label.FontAttributes>
        Bold
    </Label.FontAttributes>
    <Label.FontSize>
        Large
    </Label.FontSize>
    <Label.TextColor>
        Aqua
    </Label.TextColor>
</Label>

Możesz też użyć składni property-element dla wszystkich właściwości:

<Label>
    <Label.Text>
        Hello, XAML!
    </Label.Text>
    <Label.FontAttributes>
        Bold
    </Label.FontAttributes>
    <Label.FontSize>
        Large
    </Label.FontSize>
    <Label.TextColor>
        Aqua
    </Label.TextColor>
    <Label.VerticalOptions>
        Center
    </Label.VerticalOptions>
</Label>

Na początku składnia właściwości-elementu może wydawać się niepotrzebnym długotrwałym zastąpieniem czegoś stosunkowo prostego, a w tych przykładach z pewnością tak jest.

Jednak składnia właściwości-elementu staje się niezbędna, gdy wartość właściwości jest zbyt złożona, aby można było je wyrazić jako prosty ciąg. W tagach property-element można utworzyć wystąpienie innego obiektu i ustawić jego właściwości. Można na przykład jawnie ustawić LayoutOptions właściwość, taką jak VerticalOptions wartość z ustawieniami właściwości:

<Label>
    ...
    <Label.VerticalOptions>
        <LayoutOptions Alignment="Center" />
    </Label.VerticalOptions>
</Label>

Inny przykład: Element Grid ma dwie właściwości o nazwie RowDefinitions i ColumnDefinitions. Te dwie właściwości są typu RowDefinitionCollection i ColumnDefinitionCollection, które są kolekcjami RowDefinition obiektów i ColumnDefinition . Aby ustawić te kolekcje, należy użyć składni elementu właściwości.

Oto początek pliku XAML dla GridDemoPage klasy z wyświetlonymi tagami elementów właściwości dla RowDefinitions kolekcji i ColumnDefinitions :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.GridDemoPage"
             Title="Grid Demo Page">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        ...
    </Grid>
</ContentPage>

Zwróć uwagę na skróconą składnię definiującą komórki o automatycznym rozmiarze, komórki szerokości i wysokości pikseli oraz ustawienia gwiazdki.

Właściwości dołączone

Wiesz już, że właściwość Grid wymaga elementów właściwości dla RowDefinitions kolekcji i ColumnDefinitions do zdefiniowania wierszy i kolumn. Jednak musi istnieć pewien sposób, aby programista wskazywał wiersz i kolumnę, w której znajduje się każde dziecko Grid .

W tagu dla każdego elementu podrzędnego określ wiersz i kolumnę tego elementu podrzędnego Grid przy użyciu następujących atrybutów:

  • Grid.Row
  • Grid.Column

Wartości domyślne tych atrybutów to 0. Można również wskazać, czy element podrzędny obejmuje więcej niż jeden wiersz lub kolumnę z następującymi atrybutami:

  • Grid.RowSpan
  • Grid.ColumnSpan

Te dwa atrybuty mają wartości domyślne 1.

Oto kompletny plik GridDemoPage.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.GridDemoPage"
             Title="Grid Demo Page">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>

        <Label Text="Autosized cell"
               Grid.Row="0" Grid.Column="0"
               TextColor="White"
               BackgroundColor="Blue" />

        <BoxView Color="Silver"
                 HeightRequest="0"
                 Grid.Row="0" Grid.Column="1" />

        <BoxView Color="Teal"
                 Grid.Row="1" Grid.Column="0" />

        <Label Text="Leftover space"
               Grid.Row="1" Grid.Column="1"
               TextColor="Purple"
               BackgroundColor="Aqua"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

        <Label Text="Span two rows (or more if you want)"
               Grid.Row="0" Grid.Column="2" Grid.RowSpan="2"
               TextColor="Yellow"
               BackgroundColor="Blue"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

        <Label Text="Span two columns"
               Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
               TextColor="Blue"
               BackgroundColor="Yellow"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

        <Label Text="Fixed 100x100"
               Grid.Row="2" Grid.Column="2"
               TextColor="Aqua"
               BackgroundColor="Red"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

    </Grid>
</ContentPage>

Ustawienia Grid.Row i Grid.Column 0 nie są wymagane, ale są ogólnie uwzględniane w celu zachowania przejrzystości.

Oto jak wygląda:

Układ siatki

Sądząc wyłącznie ze składni, te Grid.Rowatrybuty , Grid.RowSpanGrid.Column, i Grid.ColumnSpan wydają się być statyczne pola lub właściwości Grid, ale co ciekawe, Grid nie definiuje żadnych elementów o nazwie Row, Column, , RowSpanlub ColumnSpan.

Grid Zamiast tego definiuje cztery właściwości możliwe do powiązania o nazwach RowProperty, ColumnProperty, RowSpanPropertyi ColumnSpanProperty. Są to specjalne typy właściwości, które można powiązać, znane jako dołączone właściwości. Są one definiowane przez klasę Grid , ale ustawiane dla elementów podrzędnych klasy Grid.

Jeśli chcesz użyć tych dołączonych właściwości w kodzie, Grid klasa udostępnia metody statyczne o nazwie SetRow, GetColumni tak dalej. Jednak w języku XAML te dołączone właściwości są ustawiane jako atrybuty w elementach podrzędnych przy użyciu prostych Grid nazw właściwości.

Dołączone właściwości są zawsze rozpoznawalne w plikach XAML jako atrybuty zawierające zarówno klasę, jak i nazwę właściwości oddzieloną kropką. Są one nazywane dołączonymi właściwościami , ponieważ są definiowane przez jedną klasę (w tym przypadku Grid), ale dołączone do innych obiektów (w tym przypadku elementów podrzędnych klasy Grid). Podczas układu program może przesłuchić wartości tych dołączonych właściwości, Grid aby wiedzieć, gdzie umieścić poszczególne elementy podrzędne.

Klasa AbsoluteLayout definiuje dwie dołączone właściwości o nazwie LayoutBounds i LayoutFlags. Oto wzorzec tablicy kontrolnej zrealizowany przy użyciu proporcjonalnych funkcji pozycjonowania i określania rozmiaru elementu AbsoluteLayout:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.AbsoluteDemoPage"
             Title="Absolute Demo Page">

    <AbsoluteLayout BackgroundColor="#FF8080">
        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0.33, 0, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="1, 0, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0, 0.33, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0.67, 0.33, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0.33, 0.67, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="1, 0.67, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0, 1, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

        <BoxView Color="#8080FF"
                 AbsoluteLayout.LayoutBounds="0.67, 1, 0.25, 0.25"
                 AbsoluteLayout.LayoutFlags="All" />

  </AbsoluteLayout>
</ContentPage>

A oto:

Układ bezwzględny

W przypadku czegoś takiego możesz kwestionować mądrość używania języka XAML. Z pewnością powtórzenie i regularność prostokąta LayoutBounds sugeruje, że może być lepiej zrealizowany w kodzie.

To z pewnością uzasadnione obawy i nie ma problemu z równoważeniem użycia kodu i znaczników podczas definiowania interfejsów użytkownika. Można łatwo zdefiniować niektóre wizualizacje w języku XAML, a następnie użyć konstruktora pliku za pomocą kodu, aby dodać więcej wizualizacji, które mogą być lepiej generowane w pętlach.

Właściwości zawartości

W poprzednich przykładach StackLayoutobiekty , Gridi AbsoluteLayout są ustawione na Content właściwość ContentPage, a elementy podrzędne tych układów są rzeczywiście elementami w Children kolekcji. Jednak te Content właściwości i Children nie znajdują się nigdzie w pliku XAML.

Z pewnością można uwzględnić Content właściwości i Children jako elementy właściwości, takie jak w przykładzie XamlPlusCode :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <ContentPage.Content>
        <StackLayout>
            <StackLayout.Children>
                <Slider VerticalOptions="CenterAndExpand"
                        ValueChanged="OnSliderValueChanged" />

                <Label x:Name="valueLabel"
                       Text="A simple Label"
                       FontSize="Large"
                       HorizontalOptions="Center"
                       VerticalOptions="CenterAndExpand" />

                <Button Text="Click Me!"
                      HorizontalOptions="Center"
                      VerticalOptions="CenterAndExpand"
                      Clicked="OnButtonClicked" />
            </StackLayout.Children>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Prawdziwe pytanie brzmi: Dlaczego te elementy właściwości nie są wymagane w pliku XAML?

Elementy zdefiniowane w Xamarin.Forms pliku do użycia w języku XAML mogą mieć jedną właściwość oflagowaną w atrybucie ContentProperty w klasie. Jeśli wyszukasz klasę ContentPage w dokumentacji online Xamarin.Forms , zobaczysz ten atrybut:

[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage

Oznacza to, że Content tagi property-element nie są wymagane. Przyjmuje się, że do właściwości zostanie przypisana dowolna zawartość XML wyświetlana między tagami początkowymi i końcowymi ContentPage Content .

StackLayout, , AbsoluteLayoutGrid, i RelativeLayout wszystkie pochodzą z Layout<View>, a jeśli wyszukasz Layout<T> w Xamarin.Forms dokumentacji, zobaczysz inny ContentProperty atrybut:

[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...

Umożliwia to automatyczne dodawanie zawartości układu do Children kolekcji bez jawnych Children tagów właściwości-element.

Inne klasy mają ContentProperty również definicje atrybutów. Na przykład właściwość content obiektu Label to Text. Zapoznaj się z dokumentacją interfejsu API dla innych osób.

Różnice między platformami przy użyciu platformy OnPlatform

W aplikacjach jednostronicowych często ustawia Padding się właściwość na stronie, aby uniknąć zastępowania paska stanu systemu iOS. W kodzie możesz użyć Device.RuntimePlatform właściwości w tym celu:

if (Device.RuntimePlatform == Device.iOS)
{
    Padding = new Thickness(0, 20, 0, 0);
}

Możesz również zrobić coś podobnego w języku XAML przy użyciu OnPlatform klas i On . Najpierw dołącz elementy właściwości dla Padding właściwości w górnej części strony:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>

    </ContentPage.Padding>
    ...
</ContentPage>

W tych tagach dołącz OnPlatform tag. OnPlatform jest klasą ogólną. Należy określić argument typu ogólnego, w tym przypadku Thickness, który jest typem Padding właściwości. Na szczęście istnieje atrybut XAML przeznaczony specjalnie do definiowania ogólnych argumentów o nazwie x:TypeArguments. Powinno to być zgodne z typem ustawianej właściwości:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">

        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>

OnPlatform ma właściwość o nazwie Platforms , która jest obiektami IList On . Użyj tagów elementów właściwości dla tej właściwości:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <OnPlatform.Platforms>

            </OnPlatform.Platforms>
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>

Teraz dodaj On elementy. Dla każdego z nich ustaw Platform właściwość i Value właściwość na znaczniki dla Thickness właściwości:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <OnPlatform.Platforms>
                <On Platform="iOS" Value="0, 20, 0, 0" />
                <On Platform="Android" Value="0, 0, 0, 0" />
                <On Platform="UWP" Value="0, 0, 0, 0" />
            </OnPlatform.Platforms>
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>

Ten znacznik można uprościć. Właściwość content obiektu OnPlatform to Platforms, więc można usunąć te tagi elementu właściwości:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0, 20, 0, 0" />
            <On Platform="Android" Value="0, 0, 0, 0" />
            <On Platform="UWP" Value="0, 0, 0, 0" />
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>

Właściwość Platform On jest typu IList<string>, więc można uwzględnić wiele platform, jeśli wartości są takie same:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0, 20, 0, 0" />
            <On Platform="Android, UWP" Value="0, 0, 0, 0" />
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>

Ponieważ system Android i platforma UWP są ustawione na wartość Paddingdomyślną , można usunąć ten tag:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0, 20, 0, 0" />
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>

Jest to standardowy sposób ustawiania właściwości zależnej od Padding platformy w języku XAML. Value Jeśli ustawienie nie może być reprezentowane przez pojedynczy ciąg, możesz zdefiniować dla niego elementy właściwości:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">

    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS">
                <On.Value>
                    0, 20, 0, 0
                </On.Value>
            </On>
        </OnPlatform>
    </ContentPage.Padding>
  ...
</ContentPage>

Uwaga

Rozszerzenie OnPlatform znaczników może być również używane w języku XAML do dostosowywania wyglądu interfejsu użytkownika dla poszczególnych platform. Zapewnia tę samą funkcjonalność co OnPlatform klasy i On , ale z bardziej zwięzłą reprezentacją. Aby uzyskać więcej informacji, zobacz OnPlatform Markup Extension (Rozszerzenie znaczników OnPlatform).

Podsumowanie

W przypadku elementów właściwości i dołączonych właściwości ustanowiono znaczną część podstawowej składni XAML. Jednak czasami należy ustawić właściwości na obiekty w sposób pośredni, na przykład ze słownika zasobów. To podejście zostało omówione w następnej części, część 3. Rozszerzenia znaczników XAML.