Parte 1. Introduzione a XAML

Download Sample Scaricare l'esempio

In un'applicazione Xamarin.Forms , XAML viene usato principalmente per definire il contenuto visivo di una pagina e funziona insieme a un file code-behind C#.

Il file code-behind fornisce il supporto del codice per il markup. Insieme, questi due file contribuiscono a una nuova definizione di classe che include visualizzazioni figlio e inizializzazione delle proprietà. All'interno del file XAML, alle classi e alle proprietà viene fatto riferimento con elementi e attributi XML e vengono stabiliti collegamenti tra markup e codice.

Creazione della soluzione

Per iniziare a modificare il primo file XAML, usa Visual Studio o Visual Studio per Mac per creare una nuova Xamarin.Forms soluzione. Selezionare la scheda seguente corrispondente all'ambiente in uso.

In Windows avviare Visual Studio 2019 e nella finestra iniziale fare clic su Crea un nuovo progetto per creare un nuovo progetto:

New Solution Window

Nella finestra Crea un nuovo progetto selezionare Mobile nell'elenco a discesa Tipo di progetto, selezionare il modello App per dispositivi mobili (Xamarin.Forms) e fare clic sul pulsante Avanti:

New Project Window

Nella finestra Configura il nuovo progetto impostare Project name (Nome progetto) su XamlSamples (o su qualsiasi elemento preferito) e fare clic sul pulsante Crea.

Nella finestra di dialogo Nuova app multipiattaforma fare clic su Vuoto e fare clic sul pulsante OK :

New App Dialog

Nella soluzione vengono creati quattro progetti: la libreria XamlSamples .NET Standard, XamlSamples.Android, XamlSamples.iOS e la soluzione piattaforma UWP (Universal Windows Platform), XamlSamples.UWP.

Dopo aver creato la soluzione XamlSamples , è possibile testare l'ambiente di sviluppo selezionando i vari progetti di piattaforma come progetto di avvio della soluzione e compilando e distribuendo la semplice applicazione creata dal modello di progetto in emulatori di telefono o dispositivi reali.

A meno che non sia necessario scrivere codice specifico della piattaforma, il progetto di libreria .NET Standard XamlSamples condiviso è il punto in cui si spenderà praticamente tutto il tempo di programmazione. Questi articoli non si avventurano al di fuori di tale progetto.

Anatomia di un file XAML

All'interno della libreria .NET Standard XamlSamples è presente una coppia di file con i nomi seguenti:

  • App.xaml, il file XAML e
  • App.xaml.cs un file code-behind C# associato al file XAML.

Dovrai fare clic sulla freccia accanto ad App.xaml per visualizzare il file code-behind.

Sia App.xaml che App.xaml.cs contribuiscono a una classe denominata App che deriva da Application. La maggior parte delle altre classi con file XAML contribuisce a una classe che deriva da ContentPage. Tali file usano XAML per definire il contenuto visivo di un'intera pagina. Questo vale per gli altri due file nel progetto XamlSamples :

  • MainPage.xaml, il file XAML e
  • MainPage.xaml.cs, il file code-behind C#.

Il file MainPage.xaml è simile al seguente (anche se la formattazione potrebbe essere leggermente diversa):

<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>

Le due dichiarazioni dello spazio dei nomi XML (xmlns) fanno riferimento agli URI, il primo apparentemente nel sito Web di Xamarin e il secondo di Microsoft. Non disturbare il controllo degli URI a cui puntano gli URI. Non c'è niente. Sono semplicemente URI di proprietà di Xamarin e Microsoft e funzionano fondamentalmente come identificatori di versione.

La prima dichiarazione dello spazio dei nomi XML indica che i tag definiti all'interno del file XAML senza prefisso fanno riferimento alle classi in Xamarin.Forms, ad esempio ContentPage. La seconda dichiarazione dello spazio dei nomi definisce un prefisso di x. Viene usato per diversi elementi e attributi intrinseci di XAML e supportati da altre implementazioni di XAML. Tuttavia, questi elementi e attributi sono leggermente diversi a seconda dell'anno incorporato nell'URI. Xamarin.Forms supporta la specifica XAML 2009, ma non tutte.

La local dichiarazione dello spazio dei nomi consente di accedere ad altre classi dal progetto di libreria .NET Standard.

Alla fine del primo tag, il x prefisso viene usato per un attributo denominato Class. Poiché l'uso di questo x prefisso è praticamente universale per lo spazio dei nomi XAML, gli attributi XAML come Class sono quasi sempre definiti .x:Class

L'attributo x:Class specifica un nome di classe .NET completo: la MainPage classe nello spazio dei XamlSamples nomi . Questo significa che questo file XAML definisce una nuova classe denominata MainPage nello XamlSamples spazio dei nomi che deriva da ContentPage, ovvero il tag in cui viene visualizzato l'attributo x:Class .

L'attributo x:Class può essere visualizzato solo nell'elemento radice di un file XAML per definire una classe C# derivata. Questa è l'unica nuova classe definita nel file XAML. Tutto il resto visualizzato nel file XAML viene invece semplicemente creata un'istanza da classi esistenti e inizializzata.

Il file MainPage.xaml.cs è simile al seguente (a parte le direttive inutilizzate using ):

using Xamarin.Forms;

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

La MainPage classe deriva da ContentPage, ma si noti la definizione della partial classe . Ciò suggerisce che dovrebbe essere presente un'altra definizione di classe parziale per MainPage, ma dove è? E che cos'è questo InitializeComponent metodo?

Quando Visual Studio compila il progetto, analizza il file XAML per generare un file di codice C#. Se guardi nella directory XamlSamples\XamlSamples\obj\Debug , troverai un file denominato XamlSamples.MainPage.xaml.g.cs. 'g' è l'acronimo di generated. Questa è l'altra definizione parziale della classe che MainPage contiene la definizione del InitializeComponent metodo chiamato dal MainPage costruttore. Queste due definizioni di classi parziali MainPage possono quindi essere compilate insieme. A seconda che xaml sia compilato o meno, il file XAML o un formato binario del file XAML viene incorporato nel file eseguibile.

In fase di esecuzione, il codice nel progetto di piattaforma specifico chiama un LoadApplication metodo, passando una nuova istanza della App classe nella libreria .NET Standard. Il App costruttore della classe crea un'istanza di MainPage. Il costruttore di tale classe chiama InitializeComponent, che chiama quindi il metodo che estrae il LoadFromXaml file XAML (o il relativo file binario compilato) dalla libreria .NET Standard. LoadFromXaml inizializza tutti gli oggetti definiti nel file XAML, li connette tutti insieme nelle relazioni padre-figlio, associa i gestori eventi definiti nel codice agli eventi impostati nel file XAML e imposta l'albero risultante degli oggetti come contenuto della pagina.

Anche se in genere non è necessario dedicare molto tempo ai file di codice generati, a volte le eccezioni di runtime vengono generate nel codice nei file generati, quindi è consigliabile acquisire familiarità con tali file.

Quando si compila ed esegue questo programma, l'elemento Label viene visualizzato al centro della pagina come suggerisce il codice XAML:

Default Xamarin.Forms display

Per gli oggetti visivi più interessanti, tutto ciò di cui hai bisogno è più interessante XAML.

Aggiunta di nuove pagine XAML

Per aggiungere altre classi basate su ContentPage XAML al progetto, selezionare il progetto libreria .NET Standard XamlSamples, fare clic con il pulsante destro del mouse e scegliere Aggiungi > nuovo elemento.... Nella finestra di dialogo Aggiungi nuovo elemento selezionare Pagina contenuto elementi >>Xamarin.Formsvisual C# (non pagina contenuto (C#), che crea una pagina di sola codice o visualizzazione contenuto, che non è una pagina. Assegnare alla pagina un nome, ad esempio HelloXamlPage:

Add New Item Dialog

Al progetto vengono aggiunti due file, HelloXamlPage.xaml e il file code-behind HelloXamlPage.xaml.cs.

Impostazione del contenuto della pagina

Modificare il file HelloXamlPage.xaml in modo che gli unici tag siano quelli per ContentPage e 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>

I ContentPage.Content tag fanno parte della sintassi univoca di XAML. All'inizio, potrebbero sembrare XML non validi, ma sono legali. Il punto non è un carattere speciale in XML.

I ContentPage.Content tag sono denominati tag dell'elemento di proprietà. Content è una proprietà di ContentPageed è in genere impostata su una singola visualizzazione o un layout con visualizzazioni figlio. In genere le proprietà diventano attributi in XAML, ma sarebbe difficile impostare un Content attributo su un oggetto complesso. Per questo motivo, la proprietà viene espressa come elemento XML costituito dal nome della classe e dal nome della proprietà separati da un punto. Ora la Content proprietà può essere impostata tra i ContentPage.Content tag, come illustrato di seguito:

<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>

Si noti anche che un Title attributo è stato impostato sul tag radice.

A questo punto, la relazione tra classi, proprietà e XML deve essere evidente: una Xamarin.Forms classe (ad esempio ContentPage o Label) viene visualizzata nel file XAML come elemento XML. Le proprietà di tale classe, incluse su TitleContentPage e sette proprietà di Label, in genere vengono visualizzate come attributi XML.

Esistono molti collegamenti per impostare i valori di queste proprietà. Alcune proprietà sono tipi di dati di base: ad esempio, le proprietà e Text sono di tipo , Rotation è di tipo Stringe (che è true per impostazione predefinita e IsVisible viene impostato qui solo per illustrazione) è di tipo DoubleBoolean.Title

La HorizontalTextAlignment proprietà è di tipo TextAlignment, che è un'enumerazione . Per una proprietà di qualsiasi tipo di enumerazione, è sufficiente specificare un nome membro.

Per le proprietà di tipi più complessi, tuttavia, i convertitori vengono usati per l'analisi del codice XAML. Si tratta di classi in Xamarin.Forms che derivano da TypeConverter. Molti sono classi pubbliche, ma alcuni no. Per questo particolare file XAML, diverse di queste classi svolgono un ruolo dietro le quinte:

  • LayoutOptionsConverter per la VerticalOptions proprietà
  • FontSizeConverter per la FontSize proprietà
  • ColorTypeConverter per la TextColor proprietà

Questi convertitori regolano la sintassi consentita delle impostazioni delle proprietà.

ThicknessTypeConverter Può gestire uno, due o quattro numeri separati da virgole. Se viene fornito un numero, si applica a tutti e quattro i lati. Con due numeri, il primo è il riempimento sinistro e destro e il secondo è superiore e inferiore. Quattro numeri sono nell'ordine sinistro, superiore, destro e inferiore.

LayoutOptionsConverter può convertire i nomi dei campi statici pubblici della LayoutOptions struttura in valori di tipo LayoutOptions.

FontSizeConverter Può gestire un NamedSize membro o una dimensione numerica del carattere.

ColorTypeConverter accetta i nomi dei campi statici pubblici della Color struttura o dei valori RGB esadecimali, con o senza un canale alfa, preceduto da un segno di numero (#). Ecco la sintassi senza un canale alfa:

TextColor="#rrggbb"

Ognuna delle piccole lettere è una cifra esadecimale. Ecco come è incluso un canale alfa:

TextColor="#aarrggbb">

Per il canale alfa, tenere presente che FF è completamente opaco e 00 è completamente trasparente.

Altri due formati consentono di specificare solo una singola cifra esadecimale per ogni canale:

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

In questi casi, la cifra viene ripetuta per formare il valore. Ad esempio, #CF3 è il colore RGB CC-FF-33.

Quando esegui il programma XamlSamples, viene visualizzato .MainPage Per visualizzare il nuovo HelloXamlPage file, è possibile impostarlo come nuova pagina di avvio nel file App.xaml.cs oppure passare alla nuova pagina da MainPage.

Per implementare la navigazione, modificare innanzitutto il codice nel costruttore App.xaml.cs in modo che venga creato un NavigationPage oggetto :

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

Nel costruttore MainPage.xaml.cs è possibile creare un gestore eventi semplice Button e usare il gestore eventi per passare a HelloXamlPage:

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;
}

L'impostazione della Content proprietà della pagina sostituisce l'impostazione della Content proprietà nel file XAML. Quando si compila e si distribuisce la nuova versione di questo programma, viene visualizzato un pulsante sullo schermo. Premendo si passa a HelloXamlPage. Ecco la pagina risultante in i Telefono, Android e UWP:

Rotated Label Text

Puoi tornare a MainPage usando il < pulsante Indietro in iOS, usando la freccia sinistra nella parte superiore della pagina o nella parte inferiore del telefono in Android oppure usando la freccia sinistra nella parte superiore della pagina in Windows 10.

È possibile sperimentare il codice XAML per diversi modi per eseguire il rendering di Label. Se è necessario incorporare caratteri Unicode nel testo, è possibile usare la sintassi XML standard. Ad esempio, per inserire il messaggio di saluto tra virgolette intelligenti, usare:

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

Di seguito è riportato l'aspetto seguente:

Rotated Label Text with Unicode Characters

Interazioni con XAML e codice

L'esempio HelloXamlPage contiene solo un singolo Label elemento nella pagina, ma questo è molto insolito. La maggior parte dei ContentPage derivati imposta la Content proprietà su un layout di qualche tipo, ad esempio un oggetto StackLayout. La Children proprietà di StackLayout è definita come di tipo IList<View> , ma è in realtà un oggetto di tipo ElementCollection<View>e tale raccolta può essere popolata con più visualizzazioni o altri layout. In XAML queste relazioni padre-figlio vengono stabilite con una normale gerarchia XML. Ecco un file XAML per una nuova pagina denominata 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>

Questo file XAML è sintatticamente completo ed è simile al seguente:

Multiple Controls on a Page

Tuttavia, è probabile che si consideri che questo programma sia carente dal livello funzionale. Forse il Slider dovrebbe causare la Label visualizzazione del valore corrente, e probabilmente Button è destinato a fare qualcosa all'interno del programma.

Come si vedrà nella parte 4. Nozioni di base sul data binding, il processo di visualizzazione di un Slider valore usando un Label oggetto può essere gestito interamente in XAML con un data binding. Ma è utile vedere prima la soluzione di codice. Anche in questo caso, la gestione del Button clic richiede sicuramente il codice. Ciò significa che il file code-behind per XamlPlusCodePage deve contenere gestori per l'evento ValueChanged di Slider e l'evento Clicked di Button. Aggiungiamoli:

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

        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {

        }

        void OnButtonClicked(object sender, EventArgs args)
        {

        }
    }
}

Questi gestori eventi non devono essere pubblici.

Nel file XAML i Slider tag e Button devono includere attributi per gli ValueChanged eventi e Clicked che fanno riferimento a questi gestori:

<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>

Si noti che l'assegnazione di un gestore a un evento ha la stessa sintassi dell'assegnazione di un valore a una proprietà.

Se il gestore per l'evento ValueChanged di Slider verrà utilizzato Label per visualizzare il valore corrente, il gestore deve fare riferimento a tale oggetto dal codice. È Label necessario un nome, specificato con l'attributo x:Name .

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

Il x prefisso dell'attributo x:Name indica che questo attributo è intrinseco a XAML.

Il nome assegnato all'attributo x:Name ha le stesse regole dei nomi delle variabili C#. Ad esempio, deve iniziare con una lettera o un carattere di sottolineatura e non contenere spazi incorporati.

Ora il ValueChanged gestore eventi può impostare per Label visualizzare il nuovo Slider valore. Il nuovo valore è disponibile negli argomenti dell'evento:

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

In alternativa, il gestore potrebbe ottenere l'oggetto Slider che genera questo evento dall'argomento sender e ottenere la Value proprietà da tale oggetto:

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

Quando si esegue il programma per la prima volta, non Label viene visualizzato il Slider valore perché l'evento ValueChanged non è ancora stato attivato. Tuttavia, qualsiasi modifica dell'oggetto Slider determina la visualizzazione del valore:

Slider Value Displayed

A questo momento per .Button Simulare una risposta a un Clicked evento visualizzando un avviso con il Text pulsante . Il gestore eventi può eseguire il cast sicuro dell'argomento sender a e Button quindi accedere alle relative proprietà:

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

Il metodo viene definito come async perché il DisplayAlert metodo è asincrono e deve essere preceduto dall'operatore await , che restituisce al termine del metodo . Poiché questo metodo ottiene la generazione dell'evento Button dall'argomento sender , lo stesso gestore può essere usato per più pulsanti.

Si è visto che un oggetto definito in XAML può generare un evento gestito nel file code-behind e che il file code-behind può accedere a un oggetto definito in XAML usando il nome assegnato all'oggetto con l'attributo x:Name . Questi sono i due modi fondamentali in cui il codice e XAML interagiscono.

Alcune informazioni aggiuntive sul funzionamento di XAML possono essere ottenute esaminando il file XamlPlusCode.xaml.g.cs appena generato, che ora include qualsiasi nome assegnato a qualsiasi x:Name attributo come campo privato. Ecco una versione semplificata del file:

public partial class XamlPlusCodePage : ContentPage {

    private Label valueLabel;

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

La dichiarazione di questo campo consente di usare liberamente la variabile ovunque all'interno del XamlPlusCodePage file di classe parziale nella giurisdizione. In fase di esecuzione, il campo viene assegnato dopo l'analisi del codice XAML. Ciò significa che il campo è null quando il XamlPlusCodePagevalueLabel costruttore inizia ma è valido dopo InitializeComponent la chiamata.

Dopo InitializeComponent aver restituito il controllo al costruttore, gli oggetti visivi della pagina sono stati costruiti esattamente come se fossero state create un'istanza e inizializzate nel codice. Il file XAML non svolge più alcun ruolo nella classe . È possibile modificare questi oggetti nella pagina in qualsiasi modo desiderato, ad esempio aggiungendo visualizzazioni a StackLayouto impostando la Content proprietà della pagina su qualcos'altro. È possibile "camminare l'albero" esaminando la Content proprietà della pagina e gli elementi nelle Children raccolte di layout. È possibile impostare proprietà sulle visualizzazioni a cui si accede in questo modo o assegnare gestori eventi a tali visualizzazioni in modo dinamico.

Sentitevi liberi. È la tua pagina e XAML è solo uno strumento per compilarne il contenuto.

Riepilogo

Con questa introduzione si è visto come un file XAML e un file di codice contribuiscono a una definizione di classe e come interagiscono i file XAML e di codice. Ma XAML ha anche caratteristiche sintattiche uniche che consentono di usarlo in modo molto flessibile. È possibile iniziare a esplorarli nella parte 2. Sintassi XAML essenziale.