Cenni preliminari sugli elementi Panel

Aggiornamento: novembre 2007

Gli elementi Panel sono componenti che controllano il rendering degli elementi, vale a dire le dimensioni, la posizione e la disposizione del contenuto figlio. In Windows Presentation Foundation (WPF) viene fornita una serie di elementi Panel predefiniti, nonché la possibilità di costruire elementi Panel personalizzati.

Di seguito sono elencate le diverse sezioni di questo argomento.

La classe Panel

Panel è la classe base per tutti gli elementi che forniscono un supporto layout in Windows Presentation Foundation (WPF). Gli elementi Panel derivati vengono utilizzati per posizionare e disporre UIElements in Extensible Application Markup Language (XAML) e in codice.

WPF include un insieme completo di implementazioni Panel derivate che attivano numerosi layout complessi. Tali classi derivate espongono proprietà e metodi che attivano la maggior parte degli scenari interfaccia utente standard. Gli sviluppatori che non riescono a trovare un comportamento di disposizione degli elementi figlio adatto alle loro esigenze possono creare nuovi layout eseguendo l'override dei metodi ArrangeOverride e MeasureOverride. Per ulteriori informazioni sui comportamenti di layout personalizzati, vedere Elementi Panel personalizzati.

XAMLPad

XAMLPad è uno strumento che facilita lo sviluppo delle interfacce utente basate su Extensible Application Markup Language (XAML) tramite l'analisi del markup in tempo reale e la visualizzazione dei risultati in una finestra. Questo strumento risulta particolarmente utile durante la sperimentazione di diversi layout. Si consiglia di tenere aperta l'applicazione, in modo da visualizzare i risultati dei vari esempi di Extensible Application Markup Language (XAML) contenuti in questo argomento. Per ulteriori informazioni, vedere XAMLPad.

Membri comuni alla classe Panel

Tutti gli elementi Panel supportano le proprietà di ridimensionamento e posizionamento di base definite in FrameworkElement, incluse Height, Width, HorizontalAlignment, VerticalAlignment, Margin e LayoutTransform. Per ulteriori informazioni sulle proprietà di posizionamento definite in FrameworkElement, vedere Panoramica su allineamento, margini e spaziatura interna.

Panel espone delle proprietà aggiuntive di importanza cruciale per la comprensione e l'utilizzo del layout. La proprietà Background viene utilizzata per riempire l'area compresa all'interno dei limiti di un elemento Panel derivato con Brush. Children rappresenta l'insieme figlio di UIElements di cui è composto l'elemento Panel. InternalChildren rappresenta il contenuto dell'insieme Children, più i membri generati dall'associazione dati. Entrambi sono costituiti da un oggetto UIElementCollection di elementi figlio ospitati all'interno dell'elemento Panel padre.

Panel espone inoltre una proprietà ZIndex che può essere utilizzata per ottenere un ordine stratificato in un elemento Panel derivato. I membri di un insieme Children Panel con un valore di ZIndex più elevato vengono posizionati prima di quelli con un valore di ZIndex minore. Si tratta di una proprietà particolarmente utile per elementi Panel quali Canvas e Grid, che consentono agli elementi figlio di condividere lo spazio delle coordinate.

Panel definisce inoltre il metodo OnRender, che consente di eseguire l'override del comportamento di presentazione predefinito di un elemento Panel.

Proprietà associate

Gli elementi Panel derivati utilizzano in modo diffuso le proprietà associate. Una proprietà associata è un tipo specializzato di proprietà di dipendenza che non dispone della proprietà "wrapper" Common Language Runtime (CLR) convenzionale. Le proprietà associate presentano una sintassi specializzata in Extensible Application Markup Language (XAML), illustrata in molti degli esempi seguenti.

Una delle funzioni di una proprietà associata consiste nel consentire agli elementi figlio di archiviare valori univoci di una proprietà definita da un elemento padre. Dall'applicazione di questa funzionalità consegue che gli elementi figlio comunicano all'elemento padre il modo in cui devono essere presentati nell'interfaccia utente. Questa operazione risulta estremamente utile per il layout dell'applicazione. Per ulteriori informazioni, vedere Cenni preliminari sulle proprietà associate.

Elementi Panel derivati

Molti oggetti sono derivati da Panel, ma non tutti vengono utilizzati come provider di layout radice. Esistono sei classi Panel definite (Canvas, DockPanel, Grid, StackPanel, VirtualizingStackPanel e WrapPanel), progettate specificamente per la creazione dell'interfaccia utente dell'applicazione.

Ciascun elemento Panel incapsula la propria particolare funzionalità, come mostrato nella seguente tabella.

Nome elemento

Panel dell'interfaccia utente?

Descrizione

Canvas

Definisce un'area nella quale è possibile posizionare in modo esplicito gli elementi figlio utilizzando coordinate relative all'area Canvas.

DockPanel

Definisce un'area all'interno della quale è possibile disporre gli elementi figlio orizzontalmente o verticalmente l'uno rispetto all'altro.

Grid

Definisce un'area flessibile della griglia costituita da colonne e righe. Gli elementi figlio di Grid possono essere posizionati con precisione utilizzando la proprietà Margin.

StackPanel

Dispone gli elementi figlio in una singola riga che può essere orientata orizzontalmente o verticalmente.

TabPanel

No

Gestisce il layout dei pulsanti scheda di un oggetto TabControl.

ToolBarOverflowPanel

No

Dispone il contenuto all'interno di un controllo ToolBar.

UniformGrid

No

UniformGrid viene utilizzato per disporre gli elementi figlio in una griglia con tutte le celle di uguali dimensioni.

VirtualizingPanel

No

Fornisce una classe base per gli elementi Panel in grado di "virtualizzare" il relativo insieme di elementi figlio.

VirtualizingStackPanel

Dispone e virtualizza il contenuto su una singola riga orientata orizzontalmente o verticalmente.

WrapPanel

WrapPanel posiziona gli elementi figlio in sequenza da sinistra verso destra, interrompendo il contenuto quando viene raggiunto il bordo della casella contenitore e facendolo ripartire dalla riga successiva. Successivamente l'ordinamento in sequenza procede dall’alto verso il basso o da destra verso sinistra, a seconda del valore della proprietà Orientation.

Elementi Panel dell'interfaccia utente

In WPF sono disponibili sei classi Panel ottimizzate per supportare gli scenari dell'interfaccia utente: Canvas, DockPanel, Grid, StackPanel, VirtualizingStackPanel e WrapPanel. Questi elementi Panel sono semplici da utilizzare, versatili ed estendibili per la maggior parte delle applicazioni.

Ciascun elemento Panel considera i vincoli di ridimensionamento in modo diverso. La comprensione della modalità con cui un elemento Panel gestisce i vincoli in direzione sia verticale, sia orizzontale consente di prevedere con più precisione il layout.

Nome elemento Panel

Dimensione x

Dimensione y

Canvas

Vincolato al contenuto

Vincolato al contenuto

DockPanel

Vincolato

Vincolato

StackPanel (con orientamento verticale)

Vincolato

Vincolato al contenuto

StackPanel (con orientamento orizzontale)

Vincolato al contenuto

Vincolato

Grid

Vincolato

Vincolato, ad eccezione dei casi in cui si applica Auto a righe e colonne

WrapPanel

Vincolato al contenuto

Vincolato al contenuto

Di seguito vengono riportate descrizioni più dettagliate ed esempi di utilizzo di questi elementi.

Canvas

L'elemento Canvas consente il posizionamento del contenuto in base a coordinate x e y assolute. Gli elementi possono essere disegnati in una posizione univoca oppure, se occupano le stesse coordinate, l'ordine in cui verranno disegnati sarà determinato in base all'ordine di visualizzazione nel markup.

Canvas fornisce il supporto di layout più flessibile rispetto a qualsiasi altro elemento Panel. Le proprietà Height e Width vengono utilizzate per definire l'area dell'elemento Canvas e agli elementi inclusi vengono assegnate coordinate in relazione all'area dell'elemento Canvas padre. Quattro proprietà associate, Left, Top, Right e Bottom, consentono un controllo accurato sul posizionamento all'interno dell'elemento Canvas; in tal modo, lo sviluppatore può posizionare e disporre gli elementi sullo schermo in maniera precisa.

La proprietà ClipToBounds di un oggetto Canvas

Con Canvas è possibile posizionare gli elementi figlio in qualsiasi punto dello schermo, perfino in corrispondenza di coordinate esterne alle relative proprietàHeight e Width definite. Inoltre, le dimensioni degli elementi figlio non influiscono suCanvas. Pertanto, è possibile che un elemento figlio estenda altri elementi all'esterno del rettangolo di delimitazione dell'elemento Canvas padre. Il comportamento predefinito di un elemento Canvas prevede che gli elementi figlio possano essere disegnati esternamente ai limiti Canvas. Se si desidera modificare questo comportamento, è possibile impostare la proprietà ClipToBounds su true. In questo modo, Canvas viene ritagliato in base alle relative dimensioni. Canvas è l'unico elemento di layout che consente di disegnare gli elementi figlio esternamente ai propri limiti.

Questo comportamento viene illustrato graficamente in Esempio di confronto di proprietà Width.

Definizione e utilizzo di un elemento Canvas

È possibile creare un'istanza di un elemento Canvas semplicemente tramite Extensible Application Markup Language (XAML) o codice. Nell'esempio seguente viene mostrato l'utilizzo di Canvas per il posizionamento assoluto del contenuto. Questo codice produce tre quadrati da 100 pixel. Il primo di essi è rosso e la posizione (x, y) del relativo angolo superiore sinistro è specificata come (0, 0). Il secondo è verde, con la posizione dell'angolo superiore sinistro impostata su (100, 100), ossia al di sotto e a destra rispetto al primo quadrato. Il terzo è blu, con la posizione dell'angolo superiore sinistro impostata su (50, 50) e ingloba pertanto il quadrante inferiore destro del primo quadrato e quello superiore sinistro del secondo quadrato. Poiché il terzo quadrato è stato disposto per ultimo, sembra posizionato sopra agli altri due; di conseguenza, le porzioni sovrapposte assumono il colore del terzo quadrato.

WindowTitle = "Canvas Sample"
'Create a Canvas as the root Panel
Dim myParentCanvas As New Canvas()
myParentCanvas.Width = 400
myParentCanvas.Height = 400

' Define child Canvas elements
Dim myCanvas1 As New Canvas()
myCanvas1.Background = Brushes.Red
myCanvas1.Height = 100
myCanvas1.Width = 100
Canvas.SetTop(myCanvas1, 0)
Canvas.SetLeft(myCanvas1, 0)

Dim myCanvas2 As New Canvas()
myCanvas2.Background = Brushes.Green
myCanvas2.Height = 100
myCanvas2.Width = 100
Canvas.SetTop(myCanvas2, 100)
Canvas.SetLeft(myCanvas2, 100)

Dim myCanvas3 As New Canvas()
myCanvas3.Background = Brushes.Blue
myCanvas3.Height = 100
myCanvas3.Width = 100
Canvas.SetTop(myCanvas3, 50)
Canvas.SetLeft(myCanvas3, 50)

' Add child elements to the Canvas' Children collection
myParentCanvas.Children.Add(myCanvas1)
myParentCanvas.Children.Add(myCanvas2)
myParentCanvas.Children.Add(myCanvas3)

' Add the parent Canvas as the Content of the Window Object
Me.Content = myParentCanvas
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "Canvas Sample";

// Create the Canvas
myParentCanvas = new Canvas();
myParentCanvas.Width = 400;
myParentCanvas.Height = 400;

// Define child Canvas elements
myCanvas1 = new Canvas();
myCanvas1.Background = Brushes.Red;
myCanvas1.Height = 100;
myCanvas1.Width = 100;
Canvas.SetTop(myCanvas1, 0);
Canvas.SetLeft(myCanvas1, 0);

myCanvas2 = new Canvas();
myCanvas2.Background = Brushes.Green;
myCanvas2.Height = 100;
myCanvas2.Width = 100;
Canvas.SetTop(myCanvas2, 100);
Canvas.SetLeft(myCanvas2, 100);

myCanvas3 = new Canvas();
myCanvas3.Background = Brushes.Blue;
myCanvas3.Height = 100;
myCanvas3.Width = 100;
Canvas.SetTop(myCanvas3, 50);
Canvas.SetLeft(myCanvas3, 50);

// Add child elements to the Canvas' Children collection
myParentCanvas.Children.Add(myCanvas1);
myParentCanvas.Children.Add(myCanvas2);
myParentCanvas.Children.Add(myCanvas3);

// Add the parent Canvas as the Content of the Window Object
mainWindow.Content = myParentCanvas;
mainWindow.Show ();

<Page WindowTitle="Canvas Sample" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Canvas Height="400" Width="400">
    <Canvas Height="100" Width="100" Top="0" Left="0" Background="Red"/>
    <Canvas Height="100" Width="100" Top="100" Left="100" Background="Green"/>
    <Canvas Height="100" Width="100" Top="50" Left="50" Background="Blue"/>
  </Canvas>
</Page>

L'applicazione compilata produce una nuova interfaccia utente simile alla seguente.

Tipico elemento Canvas

DockPanel

L'elemento DockPanel utilizza la proprietà Dock associata per posizionare il contenuto lungo i bordi di un contenitore. Quando Dock è impostato su Top o Bottom, gli elementi figlio vengono posizionati l'uno sopra o sotto l'altro. Quando è impostato su Left o Right, gli elementi figlio vengono posizionati l'uno a destra o a sinistra dell'altro. La proprietà LastChildFill determina la posizione dell'elemento finale aggiunto come elemento figlio di DockPanel.

È possibile utilizzare DockPanel per posizionare un gruppo di controlli correlati, ad esempio una serie di pulsanti. È anche possibile utilizzarlo per creare un'interfaccia utente con riquadri, simile a quella disponibile in Microsoft Outlook.

Ridimensionamento in base al contenuto

Se le proprietà Height e Width non sono specificate, DockPanel esegue il ridimensionamento in base al contenuto. Le dimensioni possono essere aumentate o diminuite in modo da contenere quelle degli elementi figlio. Tuttavia, se tali proprietà sono impostate e lo spazio non è sufficiente a contenere il successivo elemento figlio specificato, in DockPanel quell'elemento figlio o quelli successivi non saranno visualizzati, né misurati.

Proprietà LastChildFill

Per impostazione predefinita, l'ultimo elemento figlio di un elemento DockPanel "riempie" lo spazio rimanente non allocato. Se si desidera modificare questo comportamento, è possibile impostare la proprietà LastChildFill su false.

Definizione e utilizzo di un elemento DockPanel

Nell'esempio seguente viene illustrata la partizione dello spazio tramite DockPanel. Vengono aggiunti cinque elementi Border come elementi figlio di un elemento DockPanel padre. Ciascuno utilizza una diversa proprietà di posizionamento di DockPanel per la partizione dello spazio. L'elemento finale "riempie" lo spazio rimanente non allocato.

WindowTitle = "DockPanel Sample"
'Create a DockPanel as the root Panel
Dim myDockPanel As New DockPanel()
myDockPanel.LastChildFill = True

' Define the child content
Dim myBorder1 As New Border()
myBorder1.Height = 25
myBorder1.Background = Brushes.SkyBlue
myBorder1.BorderBrush = Brushes.Black
myBorder1.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder1, Dock.Top)
Dim myTextBlock1 As New TextBlock()
myTextBlock1.Foreground = Brushes.Black
myTextBlock1.Text = "Dock = Top"
myBorder1.Child = myTextBlock1

Dim myBorder2 As New Border()
myBorder2.Height = 25
myBorder2.Background = Brushes.SkyBlue
myBorder2.BorderBrush = Brushes.Black
myBorder2.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder2, Dock.Top)
Dim myTextBlock2 As New TextBlock()
myTextBlock2.Foreground = Brushes.Black
myTextBlock2.Text = "Dock = Top"
myBorder2.Child = myTextBlock2

Dim myBorder3 As New Border()
myBorder3.Height = 25
myBorder3.Background = Brushes.LemonChiffon
myBorder3.BorderBrush = Brushes.Black
myBorder3.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder3, Dock.Bottom)
Dim myTextBlock3 As New TextBlock()
myTextBlock3.Foreground = Brushes.Black
myTextBlock3.Text = "Dock = Bottom"
myBorder3.Child = myTextBlock3

Dim myBorder4 As New Border()
myBorder4.Width = 200
myBorder4.Background = Brushes.PaleGreen
myBorder4.BorderBrush = Brushes.Black
myBorder4.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder4, Dock.Left)
Dim myTextBlock4 As New TextBlock()
myTextBlock4.Foreground = Brushes.Black
myTextBlock4.Text = "Dock = Left"
myBorder4.Child = myTextBlock4

Dim myBorder5 As New Border()
myBorder5.Background = Brushes.White
myBorder5.BorderBrush = Brushes.Black
myBorder5.BorderThickness = New Thickness(1)
Dim myTextBlock5 As New TextBlock()
myTextBlock5.Foreground = Brushes.Black
myTextBlock5.Text = "This content will Fill the remaining space"
myBorder5.Child = myTextBlock5

' Add child elements to the DockPanel Children collection
myDockPanel.Children.Add(myBorder1)
myDockPanel.Children.Add(myBorder2)
myDockPanel.Children.Add(myBorder3)
myDockPanel.Children.Add(myBorder4)
myDockPanel.Children.Add(myBorder5)
Me.Content = myDockPanel
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "DockPanel Sample";

// Create the DockPanel
DockPanel myDockPanel = new DockPanel();
myDockPanel.LastChildFill = true;

// Define the child content
Border myBorder1 = new Border();
myBorder1.Height = 25;
myBorder1.Background = Brushes.SkyBlue;
myBorder1.BorderBrush = Brushes.Black;
myBorder1.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder1, Dock.Top);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.Foreground = Brushes.Black;
myTextBlock1.Text = "Dock = Top";
myBorder1.Child = myTextBlock1;

Border myBorder2 = new Border();
myBorder2.Height = 25;
myBorder2.Background = Brushes.SkyBlue;
myBorder2.BorderBrush = Brushes.Black;
myBorder2.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder2, Dock.Top);
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Foreground = Brushes.Black;
myTextBlock2.Text = "Dock = Top";
myBorder2.Child = myTextBlock2;

Border myBorder3 = new Border();
myBorder3.Height = 25;
myBorder3.Background = Brushes.LemonChiffon;
myBorder3.BorderBrush = Brushes.Black;
myBorder3.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder3, Dock.Bottom);
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Foreground = Brushes.Black;
myTextBlock3.Text = "Dock = Bottom";
myBorder3.Child = myTextBlock3;

Border myBorder4 = new Border();
myBorder4.Width = 200;
myBorder4.Background = Brushes.PaleGreen;
myBorder4.BorderBrush = Brushes.Black;
myBorder4.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder4, Dock.Left);
TextBlock myTextBlock4 = new TextBlock();
myTextBlock4.Foreground = Brushes.Black;
myTextBlock4.Text = "Dock = Left";
myBorder4.Child = myTextBlock4;

Border myBorder5 = new Border();
myBorder5.Background = Brushes.White;
myBorder5.BorderBrush = Brushes.Black;
myBorder5.BorderThickness = new Thickness(1);
TextBlock myTextBlock5 = new TextBlock();
myTextBlock5.Foreground = Brushes.Black;
myTextBlock5.Text = "This content will Fill the remaining space";
myBorder5.Child = myTextBlock5;


// Add child elements to the DockPanel Children collection
myDockPanel.Children.Add(myBorder1);
myDockPanel.Children.Add(myBorder2);
myDockPanel.Children.Add(myBorder3);
myDockPanel.Children.Add(myBorder4);
myDockPanel.Children.Add(myBorder5);

// Add the parent Canvas as the Content of the Window Object
mainWindow.Content = myDockPanel;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="DockPanel Sample">
  <DockPanel LastChildFill="True">
    <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
      <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
    </Border>
    <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
      <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
    </Border>
    <Border Height="25" Background="LemonChiffon" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom">
      <TextBlock Foreground="Black">Dock = "Bottom"</TextBlock>
    </Border>
    <Border Width="200" Background="PaleGreen" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left">
      <TextBlock Foreground="Black">Dock = "Left"</TextBlock>
    </Border>
    <Border Background="White" BorderBrush="Black" BorderThickness="1">
      <TextBlock Foreground="Black">This content will "Fill" the remaining space</TextBlock>
    </Border>
  </DockPanel>
</Page>

L'applicazione compilata produce una nuova interfaccia utente simile alla seguente.

Tipo scenario DockPanel

Griglia

L'elemento Grid combina le funzionalità di posizionamento assoluto e controllo dati tabulari. Grid consente di posizionare facilmente gli elementi e applicare uno stile. Con Grid è possibile definire raggruppamenti flessibili di righe e colonne e viene fornito inoltre un meccanismo per la condivisione delle informazioni di ridimensionamento tra più elementi Grid.

Differenze tra l'elemento Grid e l'elemento Table

Gli elementi Table e Grid condividono alcune funzionalità comuni, ma ciascuno di essi si rivela più adatto per scenari diversi. Un elemento Table è progettato per l'utilizzo all'interno del contenuto di flusso (per ulteriori informazioni sul contenuto di flusso, vedere Cenni preliminari sui documenti dinamici). Gli elementi Grid vengono utilizzati con maggior efficacia all'interno di form (in generale all'esterno del contenuto di flusso). All'interno di un oggetto FlowDocument, un elemento Table supporta comportamenti del contenuto di flusso come impaginazione, riflusso di colonne e selezione di contenuto, a differenza di un elemento Grid. Un elemento Grid viene invece utilizzato con maggior efficacia all'esterno di un oggetto FlowDocument per diversi motivi, incluso il fatto che l'elemento Grid aggiunge gli elementi in base a un indice di riga e di colonna, a differenza di Table. L'elemento Grid ammette la sovrapposizione di contenuti figlio, consentendo l'esistenza di più di un elemento all'interno di un'unica "cella". L'elemento Table non supporta la sovrapposizione. Gli elementi figlio di un elemento Grid possono essere posizionati in modo assoluto rispetto all'area della relativa "cella". L'elemento Table non supporta questa funzionalità. Infine, un elemento Grid è più semplice rispetto a un elemento Table.

Comportamento di ridimensionamento di colonne e righe

Le colonne e le righe definite all'interno di un oggetto Grid possono sfruttare il ridimensionamento Star per distribuire proporzionalmente lo spazio rimanente. Quando è selezionato Star per l'altezza o la larghezza di una riga o di una colonna, tale colonna o tale riga riceve una proporzione ponderata dello spazio disponibile rimanente. Al contrario, Auto distribuirà uniformemente lo spazio in base alla dimensione del contenuto che si trova all'interno di una colonna o di una riga. Questo valore è espresso come * o 2* quando si utilizza la sintassi Extensible Application Markup Language (XAML). Nel primo caso, la riga o la colonna riceverebbe una volta lo spazio disponibile, mentre nel secondo caso due volte e così via. Per ulteriori informazioni sul ridimensionamento Star, vedere l'esempio Esempio di utilizzo del ridimensionamento Star. Combinando questa tecnica per la distribuzione proporzionale dello spazio con i valori HorizontalAlignment e VerticalAlignment di Stretch, è possibile suddividere lo spazio di layout come percentuale dello spazio dello schermo. Grid è l’unico riquadro del layout in grado di distribuire lo spazio in questo modo.

Definizione e utilizzo di un elemento Grid

Nell'esempio seguente viene illustrata la compilazione di un'interfaccia utente analoga a quella della finestra di dialogo Esegui, disponibile nel menu Start di Windows.

'Create a Grid as the root Panel element.
Dim myGrid As New Grid()
myGrid.Height = 165
myGrid.Width = 425
myGrid.Background = Brushes.Gainsboro
myGrid.ShowGridLines = True
myGrid.HorizontalAlignment = Windows.HorizontalAlignment.Left
myGrid.VerticalAlignment = Windows.VerticalAlignment.Top

' Define and Add the Rows and Columns.
Dim colDef1 As New ColumnDefinition
colDef1.Width = New GridLength(1, GridUnitType.Auto)
Dim colDef2 As New ColumnDefinition
colDef2.Width = New GridLength(1, GridUnitType.Star)
Dim colDef3 As New ColumnDefinition
colDef3.Width = New GridLength(1, GridUnitType.Star)
Dim colDef4 As New ColumnDefinition
colDef4.Width = New GridLength(1, GridUnitType.Star)
Dim colDef5 As New ColumnDefinition
colDef5.Width = New GridLength(1, GridUnitType.Star)
myGrid.ColumnDefinitions.Add(colDef1)
myGrid.ColumnDefinitions.Add(colDef2)
myGrid.ColumnDefinitions.Add(colDef3)
myGrid.ColumnDefinitions.Add(colDef4)
myGrid.ColumnDefinitions.Add(colDef5)

Dim rowDef1 As New RowDefinition
rowDef1.Height = New GridLength(1, GridUnitType.Auto)
Dim rowDef2 As New RowDefinition
rowDef2.Height = New GridLength(1, GridUnitType.Auto)
Dim rowDef3 As New Controls.RowDefinition
rowDef3.Height = New GridLength(1, GridUnitType.Star)
Dim rowDef4 As New RowDefinition
rowDef4.Height = New GridLength(1, GridUnitType.Auto)
myGrid.RowDefinitions.Add(rowDef1)
myGrid.RowDefinitions.Add(rowDef2)
myGrid.RowDefinitions.Add(rowDef3)
myGrid.RowDefinitions.Add(rowDef4)

' Add the Image.
Dim img1 As New Image
img1.Source = New System.Windows.Media.Imaging.BitmapImage(New Uri("runicon.png", UriKind.Relative))
Grid.SetRow(img1, 0)
Grid.SetColumn(img1, 0)
myGrid.Children.Add(img1)

' Add the main application dialog.
Dim txt1 As New TextBlock
txt1.Text = "Type the name of a program, document, or Internet resource, and Windows will open it for you."
txt1.TextWrapping = TextWrapping.Wrap
Grid.SetColumnSpan(txt1, 4)
Grid.SetRow(txt1, 0)
Grid.SetColumn(txt1, 1)
myGrid.Children.Add(txt1)

' Add the second TextBlock Cell to the Grid.
Dim txt2 As New TextBlock
txt2.Text = "Open:"
Grid.SetRow(txt2, 1)
Grid.SetColumn(txt2, 0)
myGrid.Children.Add(txt2)

' Add the TextBox control.
Dim tb1 As New TextBox
Grid.SetRow(tb1, 1)
Grid.SetColumn(tb1, 1)
Grid.SetColumnSpan(tb1, 5)
myGrid.Children.Add(tb1)

' Add the Button controls.
Dim button1 As New Button
Dim button2 As New Button
Dim button3 As New Button
button1.Content = "OK"
button1.Margin = New Thickness(10, 0, 10, 15)
button2.Content = "Cancel"
button2.Margin = New Thickness(10, 0, 10, 15)
button3.Content = "Browse ..."
button3.Margin = New Thickness(10, 0, 10, 15)

Grid.SetRow(button1, 3)
Grid.SetColumn(button1, 2)
Grid.SetRow(button2, 3)
Grid.SetColumn(button2, 3)
Grid.SetRow(button3, 3)
Grid.SetColumn(button3, 4)
myGrid.Children.Add(button1)
myGrid.Children.Add(button2)
myGrid.Children.Add(button3)

Me.Content = myGrid
// Create the Grid.
grid1 = new Grid ();
grid1.Background = Brushes.Gainsboro;
grid1.HorizontalAlignment = HorizontalAlignment.Left;
grid1.VerticalAlignment = VerticalAlignment.Top;
grid1.ShowGridLines = true;
grid1.Width = 425;
grid1.Height = 165;

// Define the Columns.
colDef1 = new ColumnDefinition();
colDef1.Width = new GridLength(1, GridUnitType.Auto);
colDef2 = new ColumnDefinition();
colDef2.Width = new GridLength(1, GridUnitType.Star);
colDef3 = new ColumnDefinition();
colDef3.Width = new GridLength(1, GridUnitType.Star);
colDef4 = new ColumnDefinition();
colDef4.Width = new GridLength(1, GridUnitType.Star);
colDef5 = new ColumnDefinition();
colDef5.Width = new GridLength(1, GridUnitType.Star);
grid1.ColumnDefinitions.Add(colDef1);
grid1.ColumnDefinitions.Add(colDef2);
grid1.ColumnDefinitions.Add(colDef3);
grid1.ColumnDefinitions.Add(colDef4);
grid1.ColumnDefinitions.Add(colDef5);

// Define the Rows.
rowDef1 = new RowDefinition();
rowDef1.Height = new GridLength(1, GridUnitType.Auto);
rowDef2 = new RowDefinition();
rowDef2.Height = new GridLength(1, GridUnitType.Auto);
rowDef3 = new RowDefinition();
rowDef3.Height = new GridLength(1, GridUnitType.Star);
rowDef4 = new RowDefinition();
rowDef4.Height = new GridLength(1, GridUnitType.Auto);
grid1.RowDefinitions.Add(rowDef1);
grid1.RowDefinitions.Add(rowDef2);
grid1.RowDefinitions.Add(rowDef3);
grid1.RowDefinitions.Add(rowDef4);

// Add the Image.
img1 = new Image();
img1.Source = new System.Windows.Media.Imaging.BitmapImage(new Uri("runicon.png", UriKind.Relative));
Grid.SetRow(img1, 0);
Grid.SetColumn(img1, 0);

// Add the main application dialog.
txt1 = new TextBlock();
txt1.Text = "Type the name of a program, folder, document, or Internet resource, and Windows will open it for you.";
txt1.TextWrapping = TextWrapping.Wrap;
Grid.SetColumnSpan(txt1, 4);
Grid.SetRow(txt1, 0);
Grid.SetColumn(txt1, 1);

// Add the second text cell to the Grid.
txt2 = new TextBlock();
txt2.Text = "Open:";
Grid.SetRow(txt2, 1);
Grid.SetColumn(txt2, 0);

// Add the TextBox control.
tb1 = new TextBox();
Grid.SetRow(tb1, 1);
Grid.SetColumn(tb1, 1);
Grid.SetColumnSpan(tb1, 5);

// Add the buttons.
button1 = new Button();
button2 = new Button();
button3 = new Button();
button1.Content = "OK";
button2.Content = "Cancel";
button3.Content = "Browse ...";
Grid.SetRow(button1, 3);
Grid.SetColumn(button1, 2);
button1.Margin = new Thickness(10, 0, 10, 15);
button2.Margin = new Thickness(10, 0, 10, 15);
button3.Margin = new Thickness(10, 0, 10, 15);
Grid.SetRow(button2, 3);
Grid.SetColumn(button2, 3);
Grid.SetRow(button3, 3);
Grid.SetColumn(button3, 4);

grid1.Children.Add(img1);
grid1.Children.Add(txt1);
grid1.Children.Add(txt2);
grid1.Children.Add(tb1);
grid1.Children.Add(button1);
grid1.Children.Add(button2);
grid1.Children.Add(button3);

mainWindow.Content = grid1;
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      WindowTitle="Grid Run Dialog Sample" 
      WindowWidth="425" 
      WindowHeight="225">
  <Grid Background="#DCDCDC"
        Width="425"
        Height="165"
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        ShowGridLines="True">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Image Grid.Column="0" Grid.Row="0" Source="RunIcon.png" />
    <TextBlock Grid.Column="1" Grid.ColumnSpan="4" Grid.Row="0" TextWrapping="Wrap">
      Type the name of a program, folder, document, or
      Internet resource, and Windows will open it for you.
    </TextBlock>
    <TextBlock Grid.Column="0" Grid.Row="1">Open:</TextBlock>
    <TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="5" />
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="2">OK</Button>
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="3">Cancel</Button>
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="4">Browse ...</Button>
  </Grid>
</Page>

L'applicazione compilata produce una nuova interfaccia utente simile alla seguente.

Tipico elemento Grid

StackPanel

Un oggetto StackPanel consente di disporre in uno stack gli elementi assegnando una direzione. La direzione predefinita dello stack è verticale. La proprietà Orientation può essere utilizzata per controllare il flusso del contenuto.

StackPanel e DockPanel

Sebbene sia possibile utilizzare DockPanel per disporre gli elementi figlio in uno stack, DockPanel e StackPanel non producono risultati analoghi in alcuni scenari di utilizzo. Ad esempio, l'ordine degli elementi figlio può influire sulle relative dimensioni in un oggetto DockPanel, ma non in un oggetto StackPanel. Questa differenza è dovuta al fatto che StackPanel considera le misure nella direzione dello stack a PositiveInfinity, mentre DockPanel misura solo le dimensioni disponibili.

Nell'esempio seguente viene illustrata questa differenza fondamentale.

'Add root Grid
Dim myGrid As New Grid
myGrid.Width = 175
myGrid.Height = 150
Dim myRowDef1 As New RowDefinition
Dim myRowDef2 As New RowDefinition
myGrid.RowDefinitions.Add(myRowDef1)
myGrid.RowDefinitions.Add(myRowDef2)

'Define the DockPanel
Dim myDockPanel As New DockPanel
Grid.SetRow(myDockPanel, 0)

'Define an Image and Source.
Dim myImage As New Image
Dim bi As New BitmapImage
bi.BeginInit()
bi.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi.EndInit()
myImage.Source = bi

Dim myImage2 As New Image
Dim bi2 As New BitmapImage
bi2.BeginInit()
bi2.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi2.EndInit()
myImage2.Source = bi2

Dim myImage3 As New Image
Dim bi3 As New BitmapImage
bi3.BeginInit()
bi3.UriSource = New Uri("smiley_stackpanel.PNG", UriKind.Relative)
bi3.EndInit()
myImage3.Stretch = Stretch.Fill
myImage3.Source = bi3

'Add the images to the parent DockPanel.
myDockPanel.Children.Add(myImage)
myDockPanel.Children.Add(myImage2)
myDockPanel.Children.Add(myImage3)

'Define a StackPanel.
Dim myStackPanel As New StackPanel
myStackPanel.Orientation = Orientation.Horizontal
Grid.SetRow(myStackPanel, 1)

Dim myImage4 As New Image
Dim bi4 As New BitmapImage
bi4.BeginInit()
bi4.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi4.EndInit()
myImage4.Source = bi4

Dim myImage5 As New Image
Dim bi5 As New BitmapImage
bi5.BeginInit()
bi5.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi5.EndInit()
myImage5.Source = bi5

Dim myImage6 As New Image
Dim bi6 As New BitmapImage
bi6.BeginInit()
bi6.UriSource = New Uri("smiley_stackpanel.PNG", UriKind.Relative)
bi6.EndInit()
myImage6.Stretch = Stretch.Fill
myImage6.Source = bi6

'Add the images to the parent StackPanel.
myStackPanel.Children.Add(myImage4)
myStackPanel.Children.Add(myImage5)
myStackPanel.Children.Add(myImage6)

'Add the layout panels as children of the Grid
myGrid.Children.Add(myDockPanel)
myGrid.Children.Add(myStackPanel)

// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "StackPanel vs. DockPanel";

// Add root Grid
myGrid = new Grid();
myGrid.Width = 175;
myGrid.Height = 150;
RowDefinition myRowDef1 = new RowDefinition();
RowDefinition myRowDef2 = new RowDefinition();
myGrid.RowDefinitions.Add(myRowDef1);
myGrid.RowDefinitions.Add(myRowDef2);

// Define the DockPanel
myDockPanel = new DockPanel();
Grid.SetRow(myDockPanel, 0);

//Define an Image and Source
Image myImage = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi.EndInit();
myImage.Source = bi;

Image myImage2 = new Image();
BitmapImage bi2 = new BitmapImage();
bi2.BeginInit();
bi2.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi2.EndInit();
myImage2.Source = bi2;

Image myImage3 = new Image();
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
bi3.UriSource = new Uri("smiley_stackpanel.PNG", UriKind.Relative);
bi3.EndInit();
myImage3.Stretch = Stretch.Fill;
myImage3.Source = bi3;

// Add the images to the parent DockPanel
myDockPanel.Children.Add(myImage);
myDockPanel.Children.Add(myImage2);
myDockPanel.Children.Add(myImage3);

//Define a StackPanel
myStackPanel = new StackPanel();
myStackPanel.Orientation = Orientation.Horizontal;
Grid.SetRow(myStackPanel, 1);

Image myImage4 = new Image();
BitmapImage bi4 = new BitmapImage();
bi4.BeginInit();
bi4.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi4.EndInit();
myImage4.Source = bi4;

Image myImage5 = new Image();
BitmapImage bi5 = new BitmapImage();
bi5.BeginInit();
bi5.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi5.EndInit();
myImage5.Source = bi5;

Image myImage6 = new Image();
BitmapImage bi6 = new BitmapImage();
bi6.BeginInit();
bi6.UriSource = new Uri("smiley_stackpanel.PNG", UriKind.Relative);
bi6.EndInit();
myImage6.Stretch = Stretch.Fill;
myImage6.Source = bi6;

// Add the images to the parent StackPanel
myStackPanel.Children.Add(myImage4);
myStackPanel.Children.Add(myImage5);
myStackPanel.Children.Add(myImage6);

// Add the layout panels as children of the Grid
myGrid.Children.Add(myDockPanel);
myGrid.Children.Add(myStackPanel);

// Add the Grid as the Content of the Parent Window Object
mainWindow.Content = myGrid;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      WindowTitle="StackPanel vs. DockPanel">
  <Grid Width="175" Height="150">
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>

    <DockPanel Grid.Column="0" Grid.Row="0">
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" Stretch="Fill"/>
    </DockPanel>

    <StackPanel Grid.Column="0" Grid.Row="1"  Orientation="Horizontal">
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" Stretch="Fill"/>
    </StackPanel>
    </Grid>
</Page>

In questa immagine è possibile notare il diverso comportamento di rendering.

Schermata: StackPanel e DockPanel

Definizione e utilizzo di un elemento StackPanel

Nell'esempio seguente viene mostrato l'utilizzo di un elemento StackPanel per creare una serie di pulsanti posizionati verticalmente. Per il posizionamento orizzontale, impostare la proprietà Orientation su Horizontal.

WindowTitle = "StackPanel Sample"
' Define the StackPanel
Dim myStackPanel As New StackPanel()
myStackPanel.HorizontalAlignment = Windows.HorizontalAlignment.Left
myStackPanel.VerticalAlignment = Windows.VerticalAlignment.Top

' Define child content
Dim myButton1 As New Button()
myButton1.Content = "Button 1"
Dim myButton2 As New Button()
myButton2.Content = "Button 2"
Dim myButton3 As New Button()
myButton3.Content = "Button 3"

' Add child elements to the parent StackPanel
myStackPanel.Children.Add(myButton1)
myStackPanel.Children.Add(myButton2)
myStackPanel.Children.Add(myButton3)

Me.Content = myStackPanel
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "StackPanel Sample";

// Define the StackPanel
myStackPanel = new StackPanel();
myStackPanel.HorizontalAlignment = HorizontalAlignment.Left;
myStackPanel.VerticalAlignment = VerticalAlignment.Top;

// Define child content
Button myButton1 = new Button();
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.Content = "Button 3";

// Add child elements to the parent StackPanel
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myStackPanel.Children.Add(myButton3);           

// Add the StackPanel as the Content of the Parent Window Object
mainWindow.Content = myStackPanel;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="StackPanel Sample">
    <StackPanel HorizontalAlignment="Left"
                VerticalAlignment="Top">
        <Button>Button 1</Button>
        <Button>Button 2</Button>
        <Button>Button 3</Button>
    </StackPanel>
</Page>

L'applicazione compilata produce una nuova interfaccia utente simile alla seguente.

Tipico elemento StackPanel

VirtualizingStackPanel

In WPF è disponibile anche una variante dell'elemento StackPanel che "virtualizza" automaticamente il contenuto figlio con associazione a dati. In questo contesto, il termine "virtualizzare" si riferisce a una tecnica grazie alla quale, a partire da un gran numero di elementi dei dati, viene generato un sottoinsieme di UIElements in base agli elementi visibili sullo schermo. Generare un elevato numero di elementi dell'interfaccia utente, quando solo alcuni possono essere visualizzati sullo schermo in un dato momento, richiede un intenso consumo di risorse sia in termini di memoria che di processore. VirtualizingStackPanel, tramite le funzionalità disponibili in VirtualizingPanel, calcola gli elementi visibili e utilizza l'elemento ItemContainerGenerator di un oggetto ItemsControl (ad esempio ListBox o ListView) per creare UIElements solo per gli elementi visibili.

L'elemento VirtualizingStackPanel viene impostato automaticamente come host degli elementi per controlli quali ListBox. Quando viene ospitato un insieme con associazione a dati, il contenuto viene virtualizzato automaticamente, purché il contenuto sia incluso all'interno dei limiti di ScrollViewer. In questo modo le prestazioni ottenute durante l'hosting di molti elementi figlio vengono sensibilmente migliorate.

Nel seguente markup viene illustrato l'utilizzo di VirtualizingStackPanel come host di elementi. Per eseguire la virtualizzazione, la proprietà associata IsVirtualizing deve essere impostata su True (impostazione predefinita).

<StackPanel DataContext="{Binding Source={StaticResource Leagues}}">
    <TextBlock Text="{Binding XPath=@name}" FontFamily="Arial" FontSize="18" Foreground="Black"/>
        <ListBox VirtualizingStackPanel.IsVirtualizing="True" 
                 ItemsSource="{Binding XPath=Team}" 
                 ItemTemplate="{DynamicResource NameDataStyle}"/>      
</StackPanel>

WrapPanel

WrapPanel viene utilizzato per posizionare gli elementi figlio in sequenza da sinistra verso destra, interrompendo il contenuto quando viene raggiunto il bordo del contenitore padre e facendolo ripartire dalla riga successiva. Il contenuto può essere orientato orizzontalmente o verticalmente. WrapPanel è utile negli scenari dell'interfaccia utente semplici e dinamici. È possibile utilizzarlo inoltre per applicare un ridimensionamento uniforme a tutti i relativi elementi figlio.

Nell'esempio seguente viene illustrato il modo in cui creare un oggetto WrapPanel per visualizzare controlli Button che eseguono il wrapping una volta raggiunto il bordo del relativo contenitore.

WindowTitle = "WrapPanel Sample"

' Instantiate a new WrapPanel and set properties
Dim myWrapPanel As New WrapPanel()
myWrapPanel.Background = Brushes.Azure
myWrapPanel.Orientation = Orientation.Horizontal
myWrapPanel.ItemHeight = 25

myWrapPanel.ItemWidth = 75
myWrapPanel.Width = 150
myWrapPanel.HorizontalAlignment = Windows.HorizontalAlignment.Left
myWrapPanel.VerticalAlignment = Windows.VerticalAlignment.Top

' Define 3 button elements. Each button is sized at width of 75, so the third button wraps to the next line.
Dim btn1 As New Button()
btn1.Content = "Button 1"
Dim btn2 As New Button()
btn2.Content = "Button 2"
Dim btn3 As New Button()
btn3.Content = "Button 3"

' Add the buttons to the parent WrapPanel using the Children.Add method.
myWrapPanel.Children.Add(btn1)
myWrapPanel.Children.Add(btn2)
myWrapPanel.Children.Add(btn3)

' Add the WrapPanel to the Page as Content
Me.Content = myWrapPanel

            // Create the application's main window
            mainWindow = new System.Windows.Window();
            mainWindow.Title = "WrapPanel Sample";


            // Instantiate a new WrapPanel and set properties
            myWrapPanel = new WrapPanel();
            myWrapPanel.Background = System.Windows.Media.Brushes.Azure;
            myWrapPanel.Orientation = Orientation.Horizontal;
            myWrapPanel.ItemHeight = 25;

            myWrapPanel.ItemWidth = 75;
            myWrapPanel.Width = 150;
            myWrapPanel.HorizontalAlignment = HorizontalAlignment.Left;
            myWrapPanel.VerticalAlignment = VerticalAlignment.Top;

            // Define 3 button elements. Each button is sized at width of 75, so the third button wraps to the next line.
            btn1 = new Button();
            btn1.Content = "Button 1";
            btn2 = new Button();
            btn2.Content = "Button 2";
            btn3 = new Button();
            btn3.Content = "Button 3";

            // Add the buttons to the parent WrapPanel using the Children.Add method.
            myWrapPanel.Children.Add(btn1);
            myWrapPanel.Children.Add(btn2);
            myWrapPanel.Children.Add(btn3);

            // Add the WrapPanel to the MainWindow as Content
            mainWindow.Content = myWrapPanel;
            mainWindow.Show();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="WrapPanel Sample">
  <Border HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="2">
        <WrapPanel Background="LightBlue" Width="200" Height="100">
            <Button Width="200">Button 1</Button>
            <Button>Button 2</Button>
            <Button>Button 3</Button>
            <Button>Button 4</Button>
        </WrapPanel>
  </Border>    
</Page>

L'applicazione compilata produce una nuova interfaccia utente simile alla seguente.

Tipico elemento WrapPanel

Elementi Panel nidificati

È possibile nidificare gli elementi Panel l'uno all'interno dell'altro in modo da produrre layout complessi. Questa nidificazione può risultare molto utile in situazioni in cui un elemento Panel è ideale per una porzione di un'interfaccia utente, ma potrebbe non rispondere ai requisiti necessari per un'altra porzione dell'interfaccia utente.

Non esistono limiti effettivi al livello di nidificazione che l'applicazione è in grado di supportare; tuttavia, è preferibile restringere l'utilizzo dei pannelli a quelli realmente necessari per il layout desiderato. In molti casi è possibile utilizzare un elemento Grid al posto dei pannelli nidificati a causa della flessibilità di tale elemento come contenitore di layout. Questo può accrescere le prestazioni dell'applicazione, evitando di inserire elementi inutili nella struttura ad albero.

Nell'esempio seguente viene illustrato il modo in cui creare un'interfaccia utente che sfrutta gli elementi Panel nidificati per ottenere un determinato layout. In questo particolare caso, un elemento DockPanel viene utilizzato per fornire la struttura dell'interfaccia utente, mentre elementi StackPanel nidificati, un elemento Grid e un elemento Canvas vengono utilizzati per posizionare gli elementi figlio con precisione all'interno dell'elemento padre DockPanel.

Dim myDockPanel As New DockPanel()

Dim myBorder2 As New Border()
myBorder2.BorderThickness = New Thickness(1)
myBorder2.BorderBrush = Brushes.Black
DockPanel.SetDock(myBorder2, Dock.Left)
Dim myStackPanel As New StackPanel()
Dim myButton1 As New Button()
myButton1.Content = "Left Docked"
myButton1.Margin = New Thickness(5)
Dim myButton2 As New Button()
myButton2.Content = "StackPanel"
myButton2.Margin = New Thickness(5)
myStackPanel.Children.Add(myButton1)
myStackPanel.Children.Add(myButton2)
myBorder2.Child = myStackPanel

Dim myBorder3 As New Border()
myBorder3.BorderThickness = New Thickness(1)
myBorder3.BorderBrush = Brushes.Black
DockPanel.SetDock(myBorder3, Dock.Top)
Dim myGrid As New Grid()
myGrid.ShowGridLines = True
Dim myRowDef1 As New RowDefinition()
Dim myRowDef2 As New RowDefinition()
Dim myColDef1 As New ColumnDefinition()
Dim myColDef2 As New ColumnDefinition()
Dim myColDef3 As New ColumnDefinition()
myGrid.ColumnDefinitions.Add(myColDef1)
myGrid.ColumnDefinitions.Add(myColDef2)
myGrid.ColumnDefinitions.Add(myColDef3)
myGrid.RowDefinitions.Add(myRowDef1)
myGrid.RowDefinitions.Add(myRowDef2)
Dim myTextBlock1 As New TextBlock()
myTextBlock1.FontSize = 20
myTextBlock1.Margin = New Thickness(10)
myTextBlock1.Text = "Grid Element Docked at the Top"
Grid.SetRow(myTextBlock1, 0)
Grid.SetColumnSpan(myTextBlock1, 3)
Dim myButton3 As New Button()
myButton3.Margin = New Thickness(5)
myButton3.Content = "A Row"
Grid.SetColumn(myButton3, 0)
Grid.SetRow(myButton3, 1)
Dim myButton4 As New Button()
myButton4.Margin = New Thickness(5)
myButton4.Content = "of Button"
Grid.SetColumn(myButton4, 1)
Grid.SetRow(myButton4, 1)
Dim myButton5 As New Button()
myButton5.Margin = New Thickness(5)
myButton5.Content = "Elements"
Grid.SetColumn(myButton5, 2)
Grid.SetRow(myButton5, 1)
myGrid.Children.Add(myTextBlock1)
myGrid.Children.Add(myButton3)
myGrid.Children.Add(myButton4)
myGrid.Children.Add(myButton5)
myBorder3.Child = myGrid

Dim myBorder4 As New Border()
myBorder4.BorderBrush = Brushes.Black
myBorder4.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder4, Dock.Bottom)
Dim myStackPanel2 As New StackPanel()
myStackPanel2.Orientation = Orientation.Horizontal
Dim myTextBlock2 As New TextBlock()
myTextBlock2.Text = "This StackPanel is Docked to the Bottom"
myTextBlock2.Margin = New Thickness(5)
myStackPanel2.Children.Add(myTextBlock2)
myBorder4.Child = myStackPanel2

Dim myBorder5 As New Border()
myBorder5.BorderBrush = Brushes.Black
myBorder5.BorderThickness = New Thickness(1)
Dim myCanvas As New Canvas()
myCanvas.ClipToBounds = True
Dim myTextBlock3 As New TextBlock()
myTextBlock3.Text = "Content in the Canvas will Fill the remaining space."
Canvas.SetTop(myTextBlock3, 50)
Canvas.SetLeft(myTextBlock3, 50)
Dim myEllipse As New Ellipse()
myEllipse.Height = 100
myEllipse.Width = 125
myEllipse.Fill = Brushes.CornflowerBlue
myEllipse.Stroke = Brushes.Aqua
Canvas.SetTop(myEllipse, 100)
Canvas.SetLeft(myEllipse, 150)
myCanvas.Children.Add(myTextBlock3)
myCanvas.Children.Add(myEllipse)
myBorder5.Child = myCanvas

myDockPanel.Children.Add(myBorder2)
myDockPanel.Children.Add(myBorder3)
myDockPanel.Children.Add(myBorder4)
myDockPanel.Children.Add(myBorder5)
// Define the DockPanel.
myDockPanel = new DockPanel();

// Add the Left Docked StackPanel
Border myBorder2 = new Border();
myBorder2.BorderThickness = new Thickness(1);
myBorder2.BorderBrush = Brushes.Black;
DockPanel.SetDock(myBorder2, Dock.Left);
StackPanel myStackPanel = new StackPanel();
Button myButton1 = new Button();
myButton1.Content = "Left Docked";
myButton1.Margin = new Thickness(5);
Button myButton2 = new Button();
myButton2.Content = "StackPanel";
myButton2.Margin = new Thickness(5);
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myBorder2.Child = myStackPanel;

// Add the Top Docked Grid.
Border myBorder3 = new Border();
myBorder3.BorderThickness = new Thickness(1);
myBorder3.BorderBrush = Brushes.Black;
DockPanel.SetDock(myBorder3, Dock.Top);
Grid myGrid = new Grid();
myGrid.ShowGridLines = true;
RowDefinition myRowDef1 = new RowDefinition();
RowDefinition myRowDef2 = new RowDefinition();
ColumnDefinition myColDef1 = new ColumnDefinition();
ColumnDefinition myColDef2 = new ColumnDefinition();
ColumnDefinition myColDef3 = new ColumnDefinition();
myGrid.ColumnDefinitions.Add(myColDef1);
myGrid.ColumnDefinitions.Add(myColDef2);
myGrid.ColumnDefinitions.Add(myColDef3);
myGrid.RowDefinitions.Add(myRowDef1);
myGrid.RowDefinitions.Add(myRowDef2);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.FontSize = 20;
myTextBlock1.Margin = new Thickness(10);
myTextBlock1.Text = "Grid Element Docked at the Top";
Grid.SetRow(myTextBlock1, 0);
Grid.SetColumnSpan(myTextBlock1, 3);
Button myButton3 = new Button();
myButton3.Margin = new Thickness(5);
myButton3.Content = "A Row";
Grid.SetColumn(myButton3, 0);
Grid.SetRow(myButton3, 1);
Button myButton4 = new Button();
myButton4.Margin = new Thickness(5);
myButton4.Content = "of Button";
Grid.SetColumn(myButton4, 1);
Grid.SetRow(myButton4, 1);
Button myButton5 = new Button();
myButton5.Margin = new Thickness(5);
myButton5.Content = "Elements";
Grid.SetColumn(myButton5, 2);
Grid.SetRow(myButton5, 1);
myGrid.Children.Add(myTextBlock1);
myGrid.Children.Add(myButton3);
myGrid.Children.Add(myButton4);
myGrid.Children.Add(myButton5);
myBorder3.Child = myGrid;

// Add the Bottom Docked StackPanel.
Border myBorder4 = new Border();
myBorder4.BorderBrush = Brushes.Black;
myBorder4.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder4, Dock.Bottom);
StackPanel myStackPanel2 = new StackPanel();
myStackPanel2.Orientation = Orientation.Horizontal;
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Text = "This StackPanel is Docked to the Bottom";
myTextBlock2.Margin = new Thickness(5);
myStackPanel2.Children.Add(myTextBlock2);
myBorder4.Child = myStackPanel2;

// Add the Canvas, that fills remaining space.
Border myBorder5 = new Border();
myBorder4.BorderBrush = Brushes.Black;
myBorder5.BorderThickness = new Thickness(1);
Canvas myCanvas = new Canvas();
myCanvas.ClipToBounds = true;
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Text = "Content in the Canvas will Fill the remaining space.";
Canvas.SetTop(myTextBlock3, 50);
Canvas.SetLeft(myTextBlock3, 50);
Ellipse myEllipse = new Ellipse();
myEllipse.Height = 100;
myEllipse.Width = 125;
myEllipse.Fill = Brushes.CornflowerBlue;
myEllipse.Stroke = Brushes.Aqua;
Canvas.SetTop(myEllipse, 100);
Canvas.SetLeft(myEllipse, 150);
myCanvas.Children.Add(myTextBlock3);
myCanvas.Children.Add(myEllipse);
myBorder5.Child = myCanvas;

// Add child elements to the parent DockPanel.
myDockPanel.Children.Add(myBorder2);
myDockPanel.Children.Add(myBorder3);
myDockPanel.Children.Add(myBorder4);
myDockPanel.Children.Add(myBorder5);
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="Nested Panels">
  <Border Background="AliceBlue" 
          Width="400" 
          Height="300" 
          BorderBrush="DarkSlateBlue" 
          BorderThickness="2"
          HorizontalAlignment="Left" 
          VerticalAlignment="Top">
    <DockPanel>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left">
        <StackPanel>
          <Button Margin="5">Left Docked</Button>
          <Button Margin="5">StackPanel</Button>
        </StackPanel>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
        <Grid ShowGridLines="True">
          <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <TextBlock FontSize="20" Margin="10" Grid.ColumnSpan="3" Grid.Row="0">Grid Element Docked to the Top.</TextBlock>
          <Button Grid.Row="1" Grid.Column="0" Margin="5">A Row</Button>
          <Button Grid.Row="1" Grid.Column="1" Margin="5">of Button</Button>
          <Button Grid.Row="1" Grid.Column="2" Margin="5">Elements</Button>
        </Grid>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom">
        <StackPanel Orientation="Horizontal">
          <TextBlock Margin="5">This StackPanel is Docked to the Bottom.</TextBlock>
        </StackPanel>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1">
        <Canvas ClipToBounds="True">
          <TextBlock Canvas.Top="50" Canvas.Left="50">
            Content in the Canvas will Fill the remaining Space.
          </TextBlock>
          <Ellipse Height="100" Width="125" Fill="CornflowerBlue" Stroke="Aqua" Canvas.Top="100" Canvas.Left="150"/>
        </Canvas>
      </Border>
    </DockPanel>
  </Border>
</Page>

L'applicazione compilata produce una nuova interfaccia utente simile alla seguente.

Interfaccia utente che utilizza panelli nidificati

Elementi Panel personalizzati

Mentre in WPF viene fornita una matrice di controlli layout flessibili, è possibile ottenere comportamenti di layout personalizzati anche eseguendo l'override dei metodi ArrangeOverride e MeasureOverride. Il ridimensionamento e il posizionamento personalizzati possono essere eseguiti tramite la definizione di nuovi comportamenti di posizionamento all'interno di questi metodi di override.

Analogamente, è possibile definire comportamenti di layout personalizzati (ad esempio Canvas o Grid) eseguendo l'override dei relativi metodi ArrangeOverride e MeasureOverride.

Nel seguente markup viene illustrata la procedura per la creazione di un elemento Panel personalizzato tramite C#. Questo nuovo elemento Panel, definito PlotPanel, supporta il posizionamento degli elementi figlio mediante l'utilizzo di coordinate x e y specificate a livello di codice (hard-coded). In questo esempio, un elemento Rectangle (non visualizzato) viene posizionato in corrispondenza del punto 50 (x) e 50 (y).

Public Class PlotPanel
    Inherits Panel
    'Override the default Measure method of Panel.

    Protected Overrides Function MeasureOverride(ByVal availableSize As System.Windows.Size) As System.Windows.Size
        Dim childSize As Size = CType(availableSize, Size)
        For Each child As UIElement In InternalChildren
            child.Measure(childSize)
        Next
        Return MyBase.MeasureOverride(availableSize)
    End Function
    Protected Overrides Function ArrangeOverride(ByVal finalSize As System.Windows.Size) As System.Windows.Size
        For Each child As UIElement In InternalChildren
            Dim x As Double = 50
            Dim y As Double = 50
            child.Arrange(New Rect(New System.Windows.Point(x, y), child.DesiredSize))
        Next
        Return MyBase.ArrangeOverride(finalSize)
    End Function
End Class
public class PlotPanel : Panel
{
    // Default public constructor
    public PlotPanel()
        : base()
    {
    }

    // Override the default Measure method of Panel
    protected override Size MeasureOverride(Size availableSize)
    {
        Size panelDesiredSize = new Size();

        // In our example, we just have one child. 
        // Report that our panel requires just the size of its only child.
        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);
            panelDesiredSize = child.DesiredSize;
        }

        return panelDesiredSize ;
    }
    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (UIElement child in InternalChildren)
        {
            double x = 50;
            double y = 50;

            child.Arrange(new Rect(new Point(x, y), child.DesiredSize));
        }
        return finalSize; // Returns the final Arranged size
    }
}

Per visualizzare l'esempio completo, vedere Esempio di creazione di un elemento Panel semplice personalizzato.

Per visualizzare un'implementazione di pannelli personalizzati più complessa, vedere Esempio di creazione di un elemento Panel personalizzato con ritorno a capo del contenuto.

Supporto di localizzazione/globalizzazione

In WPF vengono supportate numerose funzionalità che facilitano la creazione di un'interfaccia utente localizzabile.

Tutti gli elementi Panel supportano a livello nativo la proprietà FlowDirection, che può essere utilizzata per consentire un nuovo flusso dinamico del contenuto in base alle impostazioni locali o di lingua dell'utente. Per ulteriori informazioni, vedere FlowDirection.

La proprietà SizeToContent fornisce un meccanismo che consente agli sviluppatori di applicazioni di prevedere le esigenze di un'interfaccia utente localizzata. Utilizzando il valore WidthAndHeight di tale proprietà, un elemento Window padre viene sempre ridimensionato in modo dinamico in modo da adattarlo al contenuto e non è vincolato da restrizioni artificiali di altezza o larghezza.

DockPanel, Grid e StackPanel rappresentano tutti opzioni appropriate per un'interfaccia utente localizzabile. Canvas invece non rappresenta un'opzione ideale, poiché determina il posizionamento assoluto del contenuto, che risulterà pertanto difficile da localizzare.

Per ulteriori informazioni sulla creazione di applicazioni WPF con interfacce utente localizzabili, vedere Cenni preliminari sull'utilizzo del layout automatico.

Vedere anche

Attività

Esempio di raccolte di layout WPF

Esempio di raccolta di controlli WPF

Esempio di creazione di un elemento Panel personalizzato con ritorno a capo del contenuto

Concetti

Guida introduttiva a Windows Presentation Foundation

Sistema di layout

Panoramica su allineamento, margini e spaziatura interna

Cenni preliminari sulle proprietà associate

Cenni preliminari sull'utilizzo del layout automatico

Ottimizzazione delle prestazioni: layout e progettazione