Layout generale di un’app Windows 8
Sebbene condividano lo stesso approccio, c’è una enorme grande differenza tra costruire un’app per Windows Phone 7 ed un’app per Windows 8. Quest’ultima deve adattarsi alla risoluzione del device su cui sta girando (notebook, ultrabook, tablet, etc.) e soprattutto deve essere in grado di adattarsi a tre modalità di visualizzazione, ovvero:
- landscape (quando tenete il pc in orizzontale)
- portrait (quando tenete il pc in verticale)
- snapped (quando andate ad agganciare l’app sul bordo sinistro o destro dello schermo)
Sappiamo tutti che il modo migliore è lasciare che il runtime .NET o WinRT faccia tutto il lavoro di intercettazione del cambiamento della vista: tramite il Visual State Manager possiamo andare a modificare qualsiasi proprietà della UI per fare in modo che la vista si adatti. In pratica, possiamo, possiamo per esempio rendere visibili/invisibili dei controlli, possiamo stringere/allargare colonne e via dicendo. Questo implica una cosa piuttosto importante: ad ogni controllo su cui vogliamo interagire tramite Visual State Manager dobbiamo assegnare un nome.
Io dal canto mio ho trovato un modo che mi piace di più, riassunto del codice XAML qui sotto.
<Page> <Page.Resources> </Page.Resources> <Grid> <”Panel” x:Name="FullScreenMainGrid"> </”Panel”> <Panel x:Name="PortraitMainGrid"> </”Panel”> <Panel x:Name="SnappedMainGrid"> </”Panel”> </Grid> </Page>
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
In pratica avete una Grid esterna che non fa altro che contenere altri tre Panel al suo interno (tali Panel possono essere Canvas, altre Grid, StackPanel, qualsiasi pannello previsto da WinRT – io ho messo Panel giusto per rendere l’idea). In modo alla visualizzazione corrente, solo uno di questi Panel sarà visibile in un dato momento. C’è il Panel che contiene il layout specifico per il landscape, poi c’è quello per il portrait, ed infine c’è quello dedicato alla visualizzazione snapped. Può sembrare una cosa prolissa, eppure io mi trovo bene così. So che toccando una certa porzione di XAML non vado a modificare le altre viste. E se lavorate con MVVM, basta fare binding e siete a posto: il codice del viewmodel che governa la view è sempre lo stesso.
Lo parte di XAML relativa al Visual State Manager è la seguente:
<VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="ApplicationViewStates"> <VisualState x:Name="FullScreenLandscape"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FullScreenMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SnappedMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PortraitMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Filled"> </VisualState> <VisualState x:Name="FullScreenPortrait"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FullScreenMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SnappedMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PortraitMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Snapped"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FullScreenMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SnappedMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PortraitMainGrid" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Il concetto è molto semplice: per ogni stato (FullScreenLandscape, FullScreenPortrait, Snapped) rendete invisibili due Panel e rendete visibile quello previsto per quello stato.
In questo modo evitate di impazzire assegnando nomi ai controlli qua e là, e siete assolutamente sicuri di come viene renderizzata una vista in un certo stato. Ogni vista è indipendente dalle altre. Prima cercavo di stringere/allargare colonne e righe di una Grid, oppure di rimpicciolire il FontSize delle TextBlock e degli altri controlli, ma finivo sempre per impazzire. Alla fine penso che la strada più lineare, semplice e comoda da gestire sia questa.
Che ne dite?
Bellissimo!!! stavo girando a vuoto quando ho trovato questa bellissima guida! GRAZIE