Disporre le visualizzazioni con Grid

Completato

Supponiamo di voler creare una pagina che visualizzi le immagini in una griglia 7 x 5. È possibile creare questa pagina con più contenitori StackLayout orizzontali e verticali. Tuttavia, compilare il codice sarebbe un'operazione noiosa che potrebbe provocare problemi di prestazioni a causa dei requisiti di memoria ed elaborazione di più pannelli di layout. Il pannello di layout Grid è una scelta migliore per le interfacce utente che necessitano sia di righe che di colonne. In questa unità si apprende come definire un layout Grid e posizionare le visualizzazioni all'interno delle relative celle.

Che cos'è una Grid?

Grid è un pannello di layout costituito da righe e colonne. La figura seguente mostra una visualizzazione concettuale di una griglia.

Illustrazione che mostra una griglia di esempio con righe e colonne di caselle, con una casella che si estende su più righe e colonne.

Le visualizzazioni vengono inserite nelle celle create dall'intersezione tra le righe e le colonne. Ad esempio, se si crea un layout Grid costituito da tre colonne e due righe, sono disponibili sei celle per le visualizzazioni. Le righe e le colonne possono avere dimensioni diverse oppure possono essere impostate in modo da adattarsi automaticamente alle dimensioni degli elementi figlio posizionati al loro interno. Le visualizzazioni figlio possono occupare una sola cella o estendersi su più celle. Questa flessibilità fa di Grid una buona scelta per il pannello di layout radice di molte app.

Come specificare le righe e le colonne di una griglia

Quando si crea un oggetto Grid, è possibile definire ogni riga e colonna singolarmente. Questo sistema offre controllo completo sull'altezza di ogni riga e la larghezza di ogni colonna. Ogni Grid dispone di una raccolta di oggetti RowDefinition e ColumnDefinition che definiscono la forma della griglia. L'utente popola queste raccolte con istanze di RowDefinition e ColumnDefinition, ognuna delle quali rappresenta una riga o una colonna nell'interfaccia utente.

Ecco due frammenti di codice che mostrano le definizioni di classe per RowDefinition e ColumnDefinition:

public sealed class RowDefinition : ...
{
    ...
    public GridLength Height { get; set; }
}
public sealed class ColumnDefinition : ...
{
    ...
    public GridLength Width { get; set; }
}

Si noti che RowDefinition ha una proprietà denominata Height e ColumnDefinition ha una proprietà denominata Width. Usare queste proprietà per impostare l'altezza di una riga e la larghezza di una colonna, come descritto nelle sezioni seguenti.

Che cos'è GridLength?

Il tipo di dati per le proprietà Width e Height è GridLength. Questo tipo contiene due proprietà: GridUnitType e Value. Ecco un frammento di codice che mostra una parte della definizione del tipo.

public struct GridLength
{
    ...
    public GridUnitType GridUnitType { get; }
    public double Value { get; }
}

È possibile impostare la proprietà GridUnitType su uno di questi valori:

  • Absolute
  • Auto
  • Star

Esaminiamo in maggiore dettaglio ognuno di questi valori.

GridUnitType Absolute

Absolute specifica che le dimensioni della riga o della colonna devono essere fisse. Utilizzare la proprietà Value per indicare le dimensioni. Ecco un esempio che illustra come impostare l'altezza di una riga su una dimensione fissa di 100 unità dispositivo in C#. Si osservi come deve essere usato il costruttore GridLength, che accetta un valore numerico. Questo costruttore imposta automaticamente GridUnitType su Absolute.

var row = new RowDefinition() { Height = new GridLength(100) };

In XAML (Extensible Application Markup Language) è sufficiente fornire un valore numerico. Il parser XAML richiama un convertitore di tipi per creare l'istanza GridLength. Ecco un esempio che illustra la stessa operazione in XAML:

<RowDefinition Height="100" />

GridUnitType Auto

Auto ridimensiona automaticamente la riga o la colonna per adattarla alle viste figlio. Grid analizza tutte le viste figlio in tale riga o colonna, seleziona la vista più grande e quindi aumenta le dimensioni della riga o della colonna quanto basta per contenere quella vista. Quando si crea una definizione di riga nel codice, il valore numerico viene ignorato. È possibile usare qualsiasi valore. Ecco un esempio che illustra come impostare l'altezza di una riga in modo che venga ridimensionata automaticamente in C#. Si noti che è stato arbitrariamente scelto 1 come valore.

var row = new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) };

In XAML si usa il valore Auto. Ecco un esempio che illustra la stessa operazione in XAML.

<RowDefinition Height="Auto" />

GridUnitType Star

Star consente il ridimensionamento proporzionale. Nel dimensionamento proporzionale, le dimensioni sono determinate dallo spazio totale disponibile e dalla proporzione richiesta da ogni riga o colonna. Nelle conversazioni si parla spesso di ridimensionamento proporzionale (Star) invece che di ridimensionamento proporzionale.

Vediamo nel dettaglio il processo di ridimensionamento proporzionale delle righe in una griglia.

  1. Determinare lo spazio disponibile: Grid analizza tutte le righe che non usano il ridimensionamento proporzionale (Star). Somma l'altezza di tutte queste righe e sottrae il totale dall'altezza del Grid stesso. Questo calcolo fornisce la quantità di spazio disponibile per tutte le righe con ridimensionamento proporzionale (Star).

  2. Dividere lo spazio disponibile: Grid divide quindi lo spazio disponibile tra tutte le righe con ridimensionamento proporzionale (Star) in base all'impostazione Value di ogni riga. La proprietà Value può essere considerata come un moltiplicatore che determina il rapporto fra tutte le righe a cui è applicato il ridimensionamento proporzionale (Star). Ad esempio, se avessimo due righe con ridimensionamento proporzionale (Star), entrambe con 1 come moltiplicatore, lo spazio disponibile verrebbe diviso equamente tra di esse. Se invece una delle righe avesse 2 come valore, otterrebbe il doppio dello spazio dell'altra riga.

Ecco un esempio che illustra come impostare l'altezza di una riga su 2 Star in C#:

var row = new RowDefinition() { Height = new GridLength(2, GridUnitType.Star) };

In XAML si usa il simbolo * per rappresentare il ridimensionamento proporzionale (Star). Dopo aver unito il valore e il simbolo * in una singola stringa, un convertitore di tipi crea GridLength automaticamente. Ecco lo stesso esempio in XAML.

<RowDefinition Height="2*" />

Raccolte di Grid

Dopo aver definito le righe e le colonne usando RowDefinition e ColumnDefinition, è possibile aggiungerle a Grid. Usare le proprietà della raccolta RowDefinitions e ColumnDefinitions di Grid. Il popolamento di queste raccolte avviene in genere in XAML.

Questo esempio illustra come definire quattro righe e aggiungerle a una Grid usando la proprietà RowDefinitions:

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

Questa definizione può essere abbreviata in:

<Grid RowDefinitions="100, Auto, 1*, 2*">
    ...
</Grid>

Il codice XAML per la definizione delle colonne è analogo al codice XAML precedente, ad eccezione del fatto che viene usato ColumnDefinitions e impostato Width.

In fase di esecuzione, questo codice XAML produce una Grid con quattro righe. La prima riga ha un'altezza fissa di 100 unità dispositivo. La seconda riga ha l'altezza corrispondente alla vista più alta nella riga. La terza e la quarta riga usano il ridimensionamento proporzionale, il che significa che lo spazio disponibile rimanente viene diviso in modo proporzionale in base al relativo moltiplicatore Value. Poiché il valore della terza riga è 1* e quello della quarta è 2*, la quarta riga è alta il doppio della terza riga.

Dimensioni predefinite di righe e colonne

Il valore predefinito per le dimensioni di righe e colonne è 1*. Ad esempio, osservare il codice XAML seguente:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    ...
</Grid>

Questa definizione può essere abbreviata in:

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">
    ...
</Grid>

Poiché non sono specificate dimensioni per nessuna delle righe o delle colonne, il valore 1* viene applicato a tutte. In fase di esecuzione, questa configurazione crea una Grid uniforme, con tutte le righe della stessa altezza e tutte le colonne della stessa larghezza.

Come aggiungere visualizzazioni a una griglia

Quando si aggiunge una visualizzazione a un oggetto Grid, la si aggiunge a una cella specifica. Le celle vengono create in corrispondenza delle posizioni di intersezione tra righe e colonne. Per posizionare una visualizzazione in una cella, è necessario conoscere la posizione della cella. Per identificare una cella si usa una combinazione di numero di riga e numero di colonna.

Numerazione di righe e colonne

La numerazione delle righe e delle colonne inizia da zero. L'origine è l'angolo superiore sinistro. L'illustrazione seguente mostra la numerazione di una Grid con quattro righe e due colonne.

Illustrazione che mostra una griglia con quattro righe e due colonne. La numerazione viene visualizzata per ogni riga e colonna. A partire dalla casella in alto a sinistra, in corrispondenza della colonna zero e della riga zero, alla casella in basso a destra in corrispondenza della colonna 1 e della riga 3.

Se, ad esempio, si vuole aggiungere una visualizzazione nella cella inferiore destra, indicare la posizione della visualizzazione come row 3 column 1.

Aggiungere una visualizzazione a una griglia con le proprietà associate

Serve un modo per specificare il numero di colonna e di riga di una visualizzazione quando la si aggiunge a una griglia. Una soluzione è quella di definire le proprietà Row e Column nella classe di base View in modo da poter specificare la posizione direttamente nella visualizzazione. Questa tecnica funziona, ma non è l'approccio più efficiente. Le visualizzazioni non vengono sempre inserite in una Grid, quindi a volte queste proprietà non sono necessarie. Un approccio migliore consiste nell'usare le proprietà associate.

Una proprietà associata è una proprietà definita in una classe ma impostata su oggetti di altri tipi.

Una proprietà associata può essere paragonata a una raccolta di coppie chiave-valore che fa parte di una visualizzazione. Quando si aggiunge una visualizzazione a un oggetto Grid, è necessario specificare la riga e la colonna. Usando le proprietà associate, è possibile aggiungere una coppia chiave-valore con la chiave Grid.Row e un valore che specifica il numero di riga. Quando la Grid è pronta per posizionare la vista, verifica se nella raccolta è presente una chiave denominata Grid.Row. Se è presente, la Grid usa il valore per posizionare la vista.

Questo esempio illustra come creare una Grid e aggiungere una visualizzazione usando le proprietà associate:

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">

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

In questo esempio Grid.Row=1 e Grid.Column=0 sono coppie chiave-valore che vengono aggiunte a una raccolta interna di BoxView. La Grid usa questi valori per determinare dove deve essere posizionata la vista. Ecco l'aspetto che avrebbe questa Grid se si eseguisse l'applicazione in un dispositivo.

Illustrazione che mostra una griglia con tre righe e due colonne. Nella seconda riga della prima colonna è visualizzato u controllo BoxView.

Come impostare una visualizzazione in modo che si estenda su più righe o colonne

Esistono altre due proprietà associate che è opportuno conoscere: Grid.RowSpan e Grid.ColumnSpan. Queste proprietà specificano il numero di righe o colonne che devono essere occupate dalla visualizzazione. Ad esempio, osservare il codice XAML seguente:

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">

    <BoxView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Color="Navy" />
    
</Grid>

Si noti che questo esempio imposta ColumnSpan su 2. Questa vista occupa due colonne a partire da Column 0. Ecco l'aspetto che avrebbe questa Grid se si eseguisse l'applicazione in un dispositivo.

Illustrazione che mostra una griglia con tre righe e due colonne. Un controllo BoxView è posizionato nella seconda riga della prima colonna e si estende su entrambe le colonne.

Verifica delle conoscenze

1.

Qual è lo scopo di Star GridUnitType?