wpf
Principio di progettazione "Half the Whitespace"
Ricerca…
introduzione
Quando si impostano i controlli, è facile codificare con precisione i valori specifici nei margini e nelle imbottiture per adattarli al layout desiderato. Tuttavia, codificando a fondo questi valori, la manutenzione diventa molto più costosa. Se il layout cambia, in quello che potrebbe essere considerato un modo banale, è necessario molto lavoro per correggere questi valori.
Questo principio di progettazione riduce il costo di manutenzione del layout pensando al layout in un modo diverso.
Dimostrazione del problema e soluzione
Ad esempio, immagina uno schermo con 3 sezioni, disposte in questo modo:
La casella blu potrebbe avere un margine di 4,4,0,0. Il riquadro verde potrebbe avere un margine di 4,4,4,0. Il margine viola della scatola sarebbe 4,4,4,4. Ecco XAML: (Sto utilizzando una griglia per ottenere il layout, ma questo principio di progettazione si applica indipendentemente da come si sceglie di ottenere il layout):
<UserControl x:Class="WpfApplication5.UserControl1HardCoded"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Column="0" Grid.Row="0" Margin="4,4,0,0" Background="DodgerBlue" BorderBrush="DarkBlue" BorderThickness="5"/>
<Border Grid.Column="1" Grid.Row="0" Margin="4,4,4,0" Background="Green" BorderBrush="DarkGreen" BorderThickness="5"/>
<Border Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Margin="4,4,4,4" Background="MediumPurple" BorderBrush="Purple" BorderThickness="5"/>
</Grid>
</UserControl>
Ora immagina di voler cambiare il layout, per mettere la scatola verde sulla sinistra della scatola blu. Dovrebbe essere semplice, non dovrebbe? Tranne che quando spostiamo quella scatola, ora dobbiamo armeggiare con i margini. O possiamo cambiare i margini della casella blu a 0,4,4,0; oppure potremmo cambiare il blu in 4,4,4,0 e il verde in 4,4,0,0. Ecco la XAML:
<UserControl x:Class="WpfApplication5.UserControl2HardCoded"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Column="1" Grid.Row="0" Margin="4,4,4,0" Background="DodgerBlue" BorderBrush="DarkBlue" BorderThickness="5"/>
<Border Grid.Column="0" Grid.Row="0" Margin="4,4,0,0" Background="Green" BorderBrush="DarkGreen" BorderThickness="5"/>
<Border Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Margin="4,4,4,4" Background="MediumPurple" BorderBrush="Purple" BorderThickness="5"/>
</Grid>
</UserControl>
Ora mettiamo la scatola viola in alto. Quindi i margini del blu diventano 4,0,4,4; il verde diventa 4,0,0,4.
<UserControl x:Class="WpfApplication5.UserControl3HardCoded"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Border Grid.Column="1" Grid.Row="1" Margin="4,0,4,4" Background="DodgerBlue" BorderBrush="DarkBlue" BorderThickness="5"/>
<Border Grid.Column="0" Grid.Row="1" Margin="4,0,0,4" Background="Green" BorderBrush="DarkGreen" BorderThickness="5"/>
<Border Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Margin="4,4,4,4" Background="MediumPurple" BorderBrush="Purple" BorderThickness="5"/>
</Grid>
</UserControl>
Non sarebbe bello se potessimo spostare le cose in modo che non avessimo bisogno di aggiustare questi valori. Questo può essere ottenuto semplicemente pensando agli spazi bianchi in un modo diverso. Piuttosto che allocare tutti gli spazi bianchi a un controllo o all'altro, immagina la metà dello spazio bianco assegnato a ciascuna casella: (il mio disegno non è abbastanza in scala - le linee tratteggiate dovrebbero essere a metà strada tra il bordo della scatola e il suo vicino) .
Quindi la scatola blu ha margini di 2,2,2,2; la scatola verde ha margini di 2,2,2,2; la scatola viola ha margini di 2,2,2,2. E il contenitore in cui sono alloggiati riceve un'imbottitura (non di margine) di 2,2,2,2. Ecco la XAML:
<UserControl x:Class="WpfApplication5.UserControl1HalfTheWhitespace"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Padding="2,2,2,2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Column="0" Grid.Row="0" Margin="2,2,2,2" Background="DodgerBlue" BorderBrush="DarkBlue" BorderThickness="5"/>
<Border Grid.Column="1" Grid.Row="0" Margin="2,2,2,2" Background="Green" BorderBrush="DarkGreen" BorderThickness="5"/>
<Border Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Margin="2,2,2,2" Background="MediumPurple" BorderBrush="Purple" BorderThickness="5"/>
</Grid>
</UserControl>
Ora proviamo a spostare le scatole, come prima ... Mettiamo la scatola verde sulla sinistra della scatola blu. Ok fatto. E non c'era bisogno di cambiare alcun padding o margini. Ecco la XAML:
<UserControl x:Class="WpfApplication5.UserControl2HalfTheWhitespace"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Padding="2,2,2,2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Column="1" Grid.Row="0" Margin="2,2,2,2" Background="DodgerBlue" BorderBrush="DarkBlue" BorderThickness="5"/>
<Border Grid.Column="0" Grid.Row="0" Margin="2,2,2,2" Background="Green" BorderBrush="DarkGreen" BorderThickness="5"/>
<Border Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Margin="2,2,2,2" Background="MediumPurple" BorderBrush="Purple" BorderThickness="5"/>
</Grid>
</UserControl>
Ora mettiamo la scatola viola in alto. Ok fatto. E non c'era bisogno di cambiare alcun padding o margini. Ecco la XAML:
<UserControl x:Class="WpfApplication5.UserControl3HalfTheWhitespace"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Padding="2,2,2,2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Border Grid.Column="1" Grid.Row="1" Margin="2,2,2,2" Background="DodgerBlue" BorderBrush="DarkBlue" BorderThickness="5"/>
<Border Grid.Column="0" Grid.Row="1" Margin="2,2,2,2" Background="Green" BorderBrush="DarkGreen" BorderThickness="5"/>
<Border Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Margin="2,2,2,2" Background="MediumPurple" BorderBrush="Purple" BorderThickness="5"/>
</Grid>
</UserControl>
Come usare questo nel codice reale
Per generalizzare ciò che abbiamo dimostrato sopra: le singole cose contengono un margine fisso di "metà degli spazi bianchi", e il contenitore in cui sono conservate dovrebbe avere una spaziatura di "metà degli spazi bianchi". È possibile applicare questi stili nel dizionario delle risorse dell'applicazione e quindi non sarà nemmeno necessario menzionarli sui singoli articoli. Ecco come è possibile definire "HalfTheWhiteSpace":
<system:Double x:Key="DefaultMarginSize">2</system:Double>
<Thickness x:Key="HalfTheWhiteSpace" Left="{StaticResource DefaultMarginSize}" Top="{StaticResource DefaultMarginSize}" Right="{StaticResource DefaultMarginSize}" Bottom="{StaticResource DefaultMarginSize}"/>
Quindi posso definire uno stile di base per basare i miei altri stili di controllo su: (questo potrebbe anche contenere la tua FontFamily predefinita, FontSize, ecc. Ecc.)
<Style x:Key="BaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="{StaticResource HalfTheWhiteSpace}"/>
</Style>
Quindi posso definire il mio stile predefinito per TextBox per utilizzare questo margine:
<Style TargetType="TextBox" BasedOn="{StaticResource BaseStyle}"/>
Posso fare questo genere di cose per DatePickers, etichette, ecc. Ecc. (Qualsiasi cosa possa essere contenuta in un contenitore). Attenzione allo styling di TextBlock come questo ... quel controllo è usato internamente da molti controlli. Ti suggerisco di creare il tuo controllo che deriva semplicemente da TextBlock. Per definire lo stile tuo TextBlock di utilizzare il margine di default; e si dovrebbe utilizzare il TextBlock ogni volta che si utilizza in modo esplicito un TextBlock in XAML.
È possibile utilizzare un approccio simile per applicare il padding ai contenitori comuni (ad esempio ScrollViewer, Border, ecc.).
Dopo averlo fatto, la maggior parte dei controlli non avrà bisogno di margini e spaziature e sarà necessario specificare solo i valori nei punti in cui si desidera intenzionalmente deviare da questo principio di progettazione.