wpf
"Half the Whitespace" ontwerpprincipe
Zoeken…
Invoering
Bij het instellen van besturingselementen is het eenvoudig om specifieke waarden in marges en opvullingen hard te coderen om dingen in de gewenste lay-out te laten passen. Door deze waarden hard te coderen, wordt onderhoud echter veel duurder. Als de lay-out verandert, op wat misschien als een triviale manier kan worden beschouwd, moet er veel werk worden verricht om deze waarden te corrigeren.
Dit ontwerpprincipe verlaagt de onderhoudskosten van de lay-out door op een andere manier over de lay-out na te denken.
Demonstratie van het probleem en de oplossing
Stel je bijvoorbeeld een scherm voor met 3 secties, zoals deze:
Het blauwe vak kan een marge van 4,4,0,0 krijgen. Het groene vak kan een marge van 4,4,4,0 krijgen. De paarse marge van de doos zou 4,4,4,4 zijn. Hier is de XAML: (ik gebruik een raster om de lay-out te bereiken; maar dit ontwerpprincipe is van toepassing ongeacht hoe u ervoor kiest om de lay-out te bereiken):
<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>
Stel je nu voor dat we de lay-out willen wijzigen, om het groene vak links van het blauwe vak te plaatsen. Moet eenvoudig zijn, toch? Behalve dat wanneer we dat vak verplaatsen, we nu moeten sleutelen aan de marges. We kunnen de marges van de blauwe doos wijzigen in 0,4,4,0; of we kunnen blauw veranderen in 4,4,4,0 en groen in 4,4,0,0. Hier is de 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>
Laten we nu de paarse doos bovenaan plaatsen. De marges van blauw worden dus 4,0,4,4; groen wordt 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>
Zou het niet mooi zijn als we dingen konden verplaatsen zodat we deze waarden helemaal niet hoefden aan te passen. Dit kan worden bereikt door gewoon op een andere manier over de witruimte te denken. Stel je voor dat de helft van de witruimte wordt toegewezen aan elk vak in plaats van alle witruimte toe te wijzen aan de ene of de andere besturingselement: (mijn tekening is niet helemaal op schaal - de stippellijnen moeten zich halverwege tussen de rand van de doos en zijn buur bevinden) .
Dus de blauwe doos heeft marges van 2,2,2,2; de groene doos heeft marges van 2,2,2,2; de paarse doos heeft marges van 2,2,2,2. En de container waarin ze zijn ondergebracht, krijgt een vulling (geen marge) van 2,2,2,2. Hier is de 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>
Laten we nu proberen de dozen te verplaatsen, op dezelfde manier als voorheen ... Laten we de groene doos links van de blauwe doos plaatsen. Oke, klaar. En het was niet nodig om de opvulling of marges te wijzigen. Hier is de 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>
Laten we nu de paarse doos bovenaan plaatsen. Oke, klaar. En het was niet nodig om de opvulling of marges te wijzigen. Hier is de 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>
Hoe dit in echte code te gebruiken
Om te generaliseren wat we hierboven hebben aangetoond: afzonderlijke dingen bevatten een vaste marge van "de helft van de witruimte", en de container waarin ze worden bewaard, moet een opvulling hebben van "de helft van de witruimte". U kunt deze stijlen toepassen in uw woordenboek met toepassingsbronnen en dan hoeft u ze niet eens te vermelden bij de afzonderlijke items. Hier is hoe je "HalfTheWhiteSpace" zou kunnen definiëren:
<system:Double x:Key="DefaultMarginSize">2</system:Double>
<Thickness x:Key="HalfTheWhiteSpace" Left="{StaticResource DefaultMarginSize}" Top="{StaticResource DefaultMarginSize}" Right="{StaticResource DefaultMarginSize}" Bottom="{StaticResource DefaultMarginSize}"/>
Vervolgens kan ik een basisstijl definiëren om mijn andere besturingsstijlen op te baseren: (dit kan ook uw standaard FontFamily, FontSize, etc, etc bevatten)
<Style x:Key="BaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="{StaticResource HalfTheWhiteSpace}"/>
</Style>
Vervolgens kan ik mijn standaardstijl voor TextBox definiëren om deze marge te gebruiken:
<Style TargetType="TextBox" BasedOn="{StaticResource BaseStyle}"/>
Ik kan dit soort dingen doen voor DatePickers, Labels, enz. Enz. (Alles wat in een container kan worden bewaard). Pas op voor het stylen van TextBlock als dit ... dat besturingselement intern wordt gebruikt door veel besturingselementen. Ik stel voor dat u uw eigen besturingselement maakt dat eenvoudigweg afkomstig is van TextBlock. U kunt uw TextBlock opmaken om de standaardmarge te gebruiken; en u zou uw TextBlock moeten gebruiken wanneer u expliciet een TextBlock in uw XAML gebruikt.
U kunt een vergelijkbare benadering gebruiken om de opvulling toe te passen op algemene containers (bijv. ScrollViewer, Border, enz.).
Als u dit eenmaal hebt gedaan, hebben de meeste bedieningselementen geen marges en opvulling meer nodig en hoeft u alleen waarden op te geven op plaatsen waar u opzettelijk wilt afwijken van dit ontwerpprincipe.