Parte 1. Introduzione a XAML
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:
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:
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 :
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:
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:
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 ContentPage
ed è 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 Title
ContentPage
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 String
e (che è true
per impostazione predefinita e IsVisible
viene impostato qui solo per illustrazione) è di tipo Double
Boolean
.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 laVerticalOptions
proprietàFontSizeConverter
per laFontSize
proprietàColorTypeConverter
per laTextColor
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.
Struttura di navigazione pagine
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 su iPhone, Android e UWP:
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="“Hello, XAML!”" … />
Di seguito è riportata un'immagine di tale finestra:
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:
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:
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 XamlPlusCodePage
valueLabel
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 StackLayout
o 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.