Udostępnij za pośrednictwem


Część 1. Część 1. Wprowadzenie do języka XAML

Xamarin.Forms W aplikacji język XAML jest najczęściej używany do definiowania zawartości wizualnej strony i współpracuje z plikiem kodu w języku C#.

Plik związany z kodem zapewnia obsługę kodu dla znaczników. Te dwa pliki współtworzyją nową definicję klasy, która obejmuje widoki podrzędne i inicjowanie właściwości. W pliku XAML klasy i właściwości odwołują się do elementów i atrybutów XML, a linki między znacznikami i kodem są ustanawiane.

Tworzenie rozwiązania

Aby rozpocząć edytowanie pierwszego pliku XAML, użyj programu Visual Studio lub Visual Studio dla komputerów Mac, aby utworzyć nowe Xamarin.Forms rozwiązanie. (Wybierz kartę poniżej odpowiadającą twojemu środowisku).

W systemie Windows uruchom program Visual Studio 2019, a w oknie uruchamiania kliknij pozycję Utwórz nowy projekt, aby utworzyć nowy projekt :

Okno nowego rozwiązania

W oknie Tworzenie nowego projektu wybierz pozycję Mobile na liście rozwijanej Typ projektu, wybierz szablon Aplikacja mobilna (Xamarin.Forms) i kliknij przycisk Dalej:

Okno nowego projektu

W oknie Konfigurowanie nowego projektu ustaw nazwę projektu na XamlSamples (lub cokolwiek innego), a następnie kliknij przycisk Utwórz.

W oknie dialogowym Nowa aplikacja międzyplatformowa kliknij pozycję Puste, a następnie kliknij przycisk OK:

Okno dialogowe Nowa aplikacja

W rozwiązaniu są tworzone cztery projekty: biblioteka XamlSamples .NET Standard, XamlSamples.Android, XamlSamples.iOS oraz rozwiązanie platforma uniwersalna systemu Windows XamlSamples.UWP.

Po utworzeniu rozwiązania XamlSamples możesz przetestować środowisko projektowe, wybierając różne projekty platform jako projekt startowy rozwiązania oraz kompilując i wdrażając prostą aplikację utworzoną przez szablon projektu na emulatorach telefonu lub na rzeczywistych urządzeniach.

Jeśli nie musisz pisać kodu specyficznego dla platformy, udostępniony projekt biblioteki XamlSamples platformy .NET Standard to miejsce, w którym będziesz spędzać praktycznie cały czas programowania. Te artykuły nie będą ryzykować poza tym projektem.

Anatomia pliku XAML

W bibliotece XamlSamples platformy .NET Standard znajdują się pary plików o następujących nazwach:

  • App.xaml, plik XAML; i
  • App.xaml.cs plik kodu w języku C# skojarzony z plikiem XAML.

Musisz kliknąć strzałkę obok pliku App.xaml , aby wyświetlić plik za kodem.

Zarówno App.xaml , jak i App.xaml.cs współtworzyć klasę o nazwie App , która pochodzi z Applicationklasy . Większość innych klas z plikami XAML współtworzy klasę pochodzącą z ContentPageklasy ; te pliki używają języka XAML do definiowania zawartości wizualnej całej strony. Dotyczy to dwóch pozostałych plików w projekcie XamlSamples :

  • MainPage.xaml, plik XAML; i
  • MainPage.xaml.cs pliku kodu w języku C#.

Plik MainPage.xaml wygląda następująco (chociaż formatowanie może być nieco inne):

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             x:Class="XamlSamples.MainPage">

    <StackLayout>
        <!-- Place new controls here -->
        <Label Text="Welcome to Xamarin Forms!"
               VerticalOptions="Center"
               HorizontalOptions="Center" />
    </StackLayout>

</ContentPage>

Dwie deklaracje przestrzeni nazw XML (xmlns) odnoszą się do identyfikatorów URI, pierwszy pozornie w witrynie internetowej platformy Xamarin, a drugi w witrynie firmy Microsoft. Nie przejmuj się sprawdzaniem, na co wskazują te identyfikatory URI. Nie ma tam nic. Są to po prostu identyfikatory URI należące do platformY Xamarin i firmy Microsoft, które zasadniczo działają jako identyfikatory wersji.

Pierwsza deklaracja przestrzeni nazw XML oznacza, że tagi zdefiniowane w pliku XAML bez prefiksu odwołują się do klas w pliku Xamarin.Forms, na przykład ContentPage. Druga deklaracja przestrzeni nazw definiuje prefiks .x Jest to używane w przypadku kilku elementów i atrybutów, które są wewnętrzne dla samego języka XAML i które są obsługiwane przez inne implementacje języka XAML. Jednak te elementy i atrybuty różnią się nieco w zależności od roku osadzonego w identyfikatorze URI. Xamarin.Forms obsługuje specyfikację XAML 2009, ale nie wszystkie.

Deklaracja local przestrzeni nazw umożliwia dostęp do innych klas z projektu biblioteki .NET Standard.

Na końcu tego pierwszego tagu x prefiks jest używany dla atrybutu o nazwie Class. Ponieważ użycie tego x prefiksu jest praktycznie uniwersalne dla przestrzeni nazw XAML, atrybuty XAML, takie jak Class są prawie zawsze określane jako x:Class.

Atrybut x:Class określa w pełni kwalifikowaną nazwę klasy .NET: klasę MainPageXamlSamples w przestrzeni nazw. Oznacza to, że ten plik XAML definiuje nową klasę o nazwie MainPage w XamlSamples przestrzeni nazw pochodzącej z ContentPage— tagu x:Class , w którym pojawia się atrybut.

Atrybut x:Class może być wyświetlany tylko w elemecie głównym pliku XAML w celu zdefiniowania pochodnej klasy języka C#. Jest to jedyna nowa klasa zdefiniowana w pliku XAML. Wszystkie inne elementy wyświetlane w pliku XAML są po prostu tworzone z istniejących klas i inicjowane.

Plik MainPage.xaml.cs wygląda następująco (oprócz nieużywanych using dyrektyw):

using Xamarin.Forms;

namespace XamlSamples
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    }
}

Klasa MainPage pochodzi z ContentPageklasy , ale zwróć uwagę na definicję partial klasy. Sugeruje to, że powinna istnieć inna definicja klasy częściowej dla MainPageklasy , ale gdzie jest? A co to jest ta InitializeComponent metoda?

Gdy program Visual Studio skompiluje projekt, analizuje plik XAML w celu wygenerowania pliku kodu C#. Jeśli spojrzysz na katalog XamlSamples\XamlSamples\obj\Debug , znajdziesz plik o nazwie XamlSamples.MainPage.xaml.g.cs. 'g' oznacza wygenerowany. Jest to druga częściowa definicja MainPage klasy, która zawiera definicję InitializeComponent metody wywoływanej z konstruktora MainPage . Te dwie częściowe MainPage definicje klas można następnie skompilować razem. W zależności od tego, czy kod XAML jest kompilowany, czy nie, plik XAML lub postać binarna pliku XAML jest osadzona w pliku wykonywalnym.

W czasie wykonywania kod w konkretnym projekcie platformy wywołuje metodę LoadApplication , przekazując do niej nowe wystąpienie App klasy w bibliotece .NET Standard. Konstruktor App klasy tworzy wystąpienie MainPageklasy . Konstruktor tej klasy wywołuje InitializeComponentmetodę , która następnie wywołuje LoadFromXaml metodę, która wyodrębnia plik XAML (lub skompilowany plik binarny) z biblioteki .NET Standard. LoadFromXaml Inicjuje wszystkie obiekty zdefiniowane w pliku XAML, łączy je wszystkie razem w relacjach nadrzędny-podrzędny, dołącza programy obsługi zdarzeń zdefiniowane w kodzie do zdarzeń ustawionych w pliku XAML i ustawia wynikowe drzewo obiektów jako zawartość strony.

Chociaż zwykle nie trzeba poświęcać dużo czasu na wygenerowane pliki kodu, czasami wyjątki środowiska uruchomieniowego są wywoływane w kodzie w wygenerowanych plikach, więc należy zapoznać się z nimi.

Podczas kompilowania i uruchamiania tego programu Label element pojawia się w środku strony, co sugeruje kod XAML:

Wyświetlanie domyślne Xamarin.Forms

Aby uzyskać bardziej interesujące wizualizacje, wszystko, czego potrzebujesz, to bardziej interesujące XAML.

Dodawanie nowych stron XAML

Aby dodać inne klasy oparte na ContentPage języku XAML do projektu, wybierz projekt biblioteki XamlSamples platformy .NET Standard, kliknij prawym przyciskiem myszy i wybierz polecenie Dodaj > nowy element.... W oknie dialogowym Dodawanie nowego elementu wybierz pozycję Strona zawartości elementów >>Xamarin.Formsvisual C# (nie strona zawartości (C#), która tworzy stronę tylko do kodu lub Widok zawartości, który nie jest stroną. Nadaj stronie nazwę, na przykład HelloXamlPage:

Okno dialogowe Dodawanie nowego elementu

Dwa pliki są dodawane do projektu, HelloXamlPage.xaml i plik za kodem HelloXamlPage.xaml.cs.

Ustawianie zawartości strony

Zmodyfikuj plik HelloXamlPage.xaml, aby jedynymi tagami były te dla ContentPage i :ContentPage.Content

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

    </ContentPage.Content>
</ContentPage>

Tagi ContentPage.Content są częścią unikatowej składni języka XAML. Na początku mogą wydawać się nieprawidłowe xml, ale są one legalne. Kropka nie jest znakiem specjalnym w formacie XML.

Tagi ContentPage.Content są nazywane tagami elementów właściwości. Content jest właściwością ContentPage, a zazwyczaj jest ustawiona na pojedynczy widok lub układ z widokami podrzędnymi. Zwykle właściwości stają się atrybutami w języku XAML, ale trudno byłoby ustawić Content atrybut na obiekt złożony. Z tego powodu właściwość jest wyrażana jako element XML składający się z nazwy klasy i nazwy właściwości oddzielonej kropką. Content Teraz właściwość można ustawić między tagami ContentPage.Content w następujący sposób:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage"
             Title="Hello XAML Page">
    <ContentPage.Content>

        <Label Text="Hello, XAML!"
               VerticalOptions="Center"
               HorizontalTextAlignment="Center"
               Rotation="-15"
               IsVisible="true"
               FontSize="Large"
               FontAttributes="Bold"
               TextColor="Blue" />

    </ContentPage.Content>
</ContentPage>

Zwróć również uwagę, że Title atrybut został ustawiony na tagu głównym.

W tej chwili relacja między klasami, właściwościami i kodem XML powinna być widoczna: Xamarin.Forms klasa (taka jak ContentPage lub Label) pojawia się w pliku XAML jako element XML. Właściwości tej klasy — w tym Title właściwości na ContentPage i siedmiu — Labelzwykle są wyświetlane jako atrybuty XML.

Istnieje wiele skrótów, aby ustawić wartości tych właściwości. Niektóre właściwości są podstawowymi typami danych: na przykład właściwości i Text są typu , Rotation jest typu StringDouble, i IsVisible (domyślnie true i jest ustawiane tylko dla ilustracji) jest typu Boolean.Title

Właściwość HorizontalTextAlignment jest typu TextAlignment, który jest wyliczeniem. W przypadku właściwości dowolnego typu wyliczenia wystarczy podać nazwę elementu członkowskiego.

Jednak w przypadku właściwości bardziej złożonych typów konwertery są używane do analizowania kodu XAML. Są to klasy, które Xamarin.Forms pochodzą z klasy TypeConverter. Wiele z nich to klasy publiczne, ale niektóre nie. W przypadku tego konkretnego pliku XAML kilka z tych klas odgrywa rolę w tle:

  • LayoutOptionsConverterVerticalOptions dla właściwości
  • FontSizeConverterFontSize dla właściwości
  • ColorTypeConverterTextColor dla właściwości

Te konwertery określają dozwoloną składnię ustawień właściwości.

Może ThicknessTypeConverter obsłużyć jedną, dwie lub cztery liczby oddzielone przecinkami. Jeśli podano jedną liczbę, ma zastosowanie do wszystkich czterech stron. Z dwoma liczbami pierwszy jest w lewym i prawym dopełnieniu, a drugi jest górny i dolny. Cztery liczby są w kolejności lewej, górnej, prawej i dolnej.

Obiekt LayoutOptionsConverter może przekonwertować nazwy publicznych pól LayoutOptions statycznych struktury na wartości typu LayoutOptions.

Może FontSizeConverter obsługiwać element członkowski NamedSize lub rozmiar czcionki liczbowej.

Obiekt ColorTypeConverter akceptuje nazwy publicznych pól Color statycznych struktury lub wartości szesnastkowe RGB z kanałem alfa lub bez niego poprzedzone znakiem numeru (#). Oto składnia bez kanału alfa:

TextColor="#rrggbb"

Każda z małych liter jest cyfrą szesnastkową. Poniżej przedstawiono sposób dołączania kanału alfa:

TextColor="#aarrggbb">

W przypadku kanału alfa należy pamiętać, że FF jest w pełni nieprzezroczyste, a 00 jest w pełni przezroczyste.

Dwa inne formaty umożliwiają określenie tylko jednej cyfry szesnastkowej dla każdego kanału:

TextColor="#rgb" TextColor="#argb"

W takich przypadkach cyfra jest powtarzana w celu utworzenia wartości. Na przykład #CF3 jest kolorem RGB CC-FF-33.

Po uruchomieniu programu MainPage XamlSamples zostanie wyświetlony element . Aby wyświetlić nowe HelloXamlPage , możesz ustawić to jako nową stronę uruchamiania w pliku App.xaml.cs lub przejść do nowej strony z witryny MainPage.

Aby zaimplementować nawigację, najpierw zmień kod w konstruktorze App.xaml.cs , NavigationPage aby obiekt został utworzony:

public App()
{
    InitializeComponent();
    MainPage = new NavigationPage(new MainPage());
}

W konstruktorze MainPage.xaml.cs można utworzyć prosty Button program obsługi zdarzeń i użyć go do przejścia do HelloXamlPageelementu :

public MainPage()
{
    InitializeComponent();

    Button button = new Button
    {
        Text = "Navigate!",
        HorizontalOptions = LayoutOptions.Center,
        VerticalOptions = LayoutOptions.Center
    };

    button.Clicked += async (sender, args) =>
    {
        await Navigation.PushAsync(new HelloXamlPage());
    };

    Content = button;
}

Content Ustawienie właściwości strony zastępuje ustawienie Content właściwości w pliku XAML. Po skompilowaniu i wdrożeniu nowej wersji tego programu zostanie wyświetlony przycisk na ekranie. Naciśnięcie klawisza powoduje przejście do .HelloXamlPage Oto wynikowa strona w systemach i Telefon, Android i UWP:

Tekst obróconej etykiety

Możesz wrócić do MainPage korzystania z < przycisku Wstecz w systemie iOS, używając strzałki w lewo w górnej części strony lub w dolnej części telefonu w systemie Android lub przy użyciu strzałki w lewo w górnej części strony w systemie Windows 10.

Możesz eksperymentować z językiem XAML na różne sposoby renderowania elementu Label. Jeśli musisz osadzić znaki Unicode w tekście, możesz użyć standardowej składni XML. Aby na przykład umieścić powitanie w inteligentnych cudzysłowach, użyj:

<Label Text="&#x201C;Hello, XAML!&#x201D;" … />

Oto jak wygląda:

Obrócony tekst etykiety z znakami Unicode

Interakcje xAML i kodu

Przykład HelloXamlPage zawiera tylko jeden Label element na stronie, ale jest to bardzo nietypowe. Większość ContentPage pochodnych ustawia Content właściwość na układ pewnego rodzaju, taki jak StackLayout. Właściwość Children obiektu StackLayout jest zdefiniowana jako typ IList<View> , ale w rzeczywistości jest obiektem typu ElementCollection<View>, a kolekcja może być wypełniona wieloma widokami lub innymi układami. W języku XAML te relacje nadrzędny-podrzędny są ustanawiane z normalną hierarchią XML. Oto plik XAML nowej strony o nazwie XamlPlusCodePage:

<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">
    <StackLayout>
        <Slider VerticalOptions="CenterAndExpand" />

        <Label Text="A simple Label"
               Font="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

Ten plik XAML jest syntaktycznie kompletny i wygląda następująco:

Wiele kontrolek na stronie

Można jednak rozważyć, że ten program będzie funkcjonalnie niedociągliwy. Slider Być może element ma spowodować Label wyświetlenie bieżącej wartości, a Button element prawdopodobnie ma zrobić coś w programie.

Jak zobaczysz w części 4. Podstawy powiązań danych— zadanie wyświetlania Slider wartości przy użyciu elementu Label można obsłużyć w całości w języku XAML za pomocą powiązania danych. Warto jednak najpierw zobaczyć rozwiązanie kodu. Mimo to obsługa Button kliknięcia zdecydowanie wymaga kodu. Oznacza to, że plik związany z kodem musi XamlPlusCodePage zawierać programy obsługi dla ValueChanged zdarzenia Slider i Clicked zdarzenia Button. Dodajmy je:

namespace XamlSamples
{
    public partial class XamlPlusCodePage
    {
        public XamlPlusCodePage()
        {
            InitializeComponent();
        }

        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {

        }

        void OnButtonClicked(object sender, EventArgs args)
        {

        }
    }
}

Te programy obsługi zdarzeń nie muszą być publiczne.

W pliku Slider XAML tagi i Button muszą zawierać atrybuty dla ValueChanged zdarzeń i Clicked odwołujących się do tych procedur obsługi:

<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">
    <StackLayout>
        <Slider VerticalOptions="CenterAndExpand"
                ValueChanged="OnSliderValueChanged" />

        <Label Text="A simple Label"
               Font="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

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

Zwróć uwagę, że przypisanie procedury obsługi do zdarzenia ma taką samą składnię, jak przypisanie wartości do właściwości.

Jeśli procedura obsługi zdarzenia ValueChangedSlider będzie używać Label elementu , aby wyświetlić bieżącą wartość, program obsługi musi odwoływać się do tego obiektu z kodu. Wymaga Label nazwy, która jest określona z atrybutem x:Name .

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

Prefiks x atrybutu x:Name wskazuje, że ten atrybut jest wewnętrzny dla języka XAML.

Nazwa przypisana do atrybutu x:Name ma te same reguły co nazwy zmiennych języka C#. Na przykład musi zaczynać się od litery lub podkreślenia i nie zawierać osadzonych spacji.

Teraz program obsługi zdarzeń ValueChanged może ustawić Label wartość , aby wyświetlić nową Slider wartość. Nowa wartość jest dostępna z argumentów zdarzeń:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = args.NewValue.ToString("F3");
}

Lub program obsługi może uzyskać Slider obiekt, który generuje to zdarzenie z argumentu sender i uzyskać Value właściwość z tego:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}

Po pierwszym uruchomieniu programu wartość nie jest wyświetlanaSlider, Label ponieważ ValueChanged zdarzenie nie zostało jeszcze wyzwolone. Ale każda manipulacja Slider przyczyną wyświetlania wartości:

Wyświetlona wartość suwaka

Teraz dla elementu Button. Symulujemy odpowiedź na Clicked zdarzenie, wyświetlając alert za pomocą Text przycisku . Procedura obsługi zdarzeń może bezpiecznie rzutować sender argument na element , Button a następnie uzyskać dostęp do jego właściwości:

async void OnButtonClicked(object sender, EventArgs args)
{
    Button button = (Button)sender;
    await DisplayAlert("Clicked!",
        "The button labeled '" + button.Text + "' has been clicked",
        "OK");
}

Metoda jest definiowana jako async , ponieważ DisplayAlert metoda jest asynchroniczna i powinna być poprzedzona operatorem await , który zwraca wartość po zakończeniu metody. Ponieważ ta metoda uzyskuje Button wyzwalanie zdarzenia z argumentu sender , można użyć tej samej procedury obsługi dla wielu przycisków.

Wiesz już, że obiekt zdefiniowany w języku XAML może wyzwalać zdarzenie obsługiwane w pliku za pomocą kodu i że plik za pomocą kodu może uzyskać dostęp do obiektu zdefiniowanego w języku XAML przy użyciu przypisanej do niego nazwy z atrybutem x:Name . Są to dwa podstawowe sposoby interakcji kodu i XAML.

Dodatkowe szczegółowe informacje na temat działania języka XAML można uzyskać, sprawdzając nowo wygenerowany plik XamlPlusCode.xaml.g.cs, który zawiera teraz dowolną nazwę przypisaną do dowolnego x:Name atrybutu jako pola prywatnego. Oto uproszczona wersja tego pliku:

public partial class XamlPlusCodePage : ContentPage {

    private Label valueLabel;

    private void InitializeComponent() {
        this.LoadFromXaml(typeof(XamlPlusCodePage));
        valueLabel = this.FindByName<Label>("valueLabel");
    }
}

Deklaracja tego pola umożliwia swobodne używanie zmiennej w dowolnym miejscu w pliku klasy częściowej XamlPlusCodePage w ramach jurysdykcji. W czasie wykonywania pole jest przypisywane po przeanalizowaniu kodu XAML. Oznacza to, że pole jest null wtedy, valueLabel gdy XamlPlusCodePage konstruktor zaczyna się, ale jest prawidłowy po InitializeComponent wywołaniu.

Po InitializeComponent powrocie kontrolki z powrotem do konstruktora wizualizacje strony zostały skonstruowane tak, jakby zostały utworzone i zainicjowane w kodzie. Plik XAML nie odgrywa już żadnej roli w klasie. Możesz manipulować tymi obiektami na stronie w dowolny sposób, na przykład przez dodanie widoków do obiektu lub ustawienie Content właściwości strony na StackLayoutcoś innego całkowicie. Możesz "chodzić po drzewie", sprawdzając Content właściwość strony i elementy w Children kolekcjach układów. Właściwości widoków dostępnych w ten sposób można ustawić lub dynamicznie przypisywać do nich programy obsługi zdarzeń.

Zapraszam. Jest to strona, a kod XAML jest tylko narzędziem do kompilowania zawartości.

Podsumowanie

W tym wprowadzeniu pokazano, jak plik I plik kodu XAML współtworzy definicję klasy oraz sposób interakcji plików XAML i kodu. Jednak XAML ma również własne unikatowe funkcje składniowe, które pozwalają na ich używanie w bardzo elastyczny sposób. Możesz rozpocząć eksplorowanie ich w części 2. Podstawowa składnia XAML.