wpf
"Half the Whitespace" Designprincipen
Sök…
Introduktion
När du lägger ut kontroller är det lätt att hårdkoda specifika värden i marginaler och paddningar för att få saker som passar önskad layout. Men genom hårdkodning av dessa värden blir underhåll mycket dyrare. Om layouten ändras, på vad som kan betraktas som ett trivialt sätt, måste mycket arbete gå till att korrigera dessa värden.
Denna designprincip minskar kostnaderna för underhåll av layouten genom att tänka på layouten på ett annat sätt.
Demonstration av problemet och lösningen
Föreställ dig till exempel en skärm med tre sektioner, utformade så här:
Den blå rutan kan få en marginal på 4,4,0,0. Den gröna rutan kan få en marginal på 4,4,4,0. Den lila rutmarginalen skulle vara 4,4,4,4. Här är XAML: (Jag använder ett rutnät för att uppnå layouten, men denna designprincip gäller oavsett hur du väljer att uppnå layouten):
<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>
Föreställ dig nu att vi vill ändra layout för att placera den gröna rutan till vänster om den blå rutan. Borde vara enkelt, borde det inte? Förutom att när vi flyttar den rutan, måste vi nu tänka på marginalerna. Antingen kan vi ändra blårutans marginaler till 0,4,4,0; eller så kan vi ändra blått till 4,4,4,0 och grönt till 4,4,0,0. Här är 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>
Låt oss nu lägga den lila lådan upptill. Så blått marginaler blir 4,0,4,4; grönt blir 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>
Skulle det inte vara trevligt om vi kunde flytta saker så att vi inte behövde justera dessa värden alls. Detta kan uppnås genom att bara tänka på vitrummet på ett annat sätt. Istället för att tilldela allt vitrummet till den ena kontrollen eller den andra, kan du tänka dig halva vitrummet som tilldelas varje ruta: (min ritning är inte helt i skala - de prickade linjerna bör vara halvvägs mellan lådans kant och dess granne) .
Så den blå rutan har marginaler på 2,2,2,2; den gröna rutan har marginaler på 2,2,2,2; den lila lådan har marginaler på 2,2,2,2. Och behållaren i vilken de är inrymt får en stoppning (inte marginal) på 2,2,2,2. Här är 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>
Låt oss försöka flytta lådorna runt, på samma sätt som tidigare ... Låt oss sätta den gröna rutan till vänster om den blå rutan. OK klar. Och det fanns inget behov av att ändra polstring eller marginaler. Här är 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>
Låt oss nu lägga den lila lådan högst upp. OK klar. Och det fanns inget behov av att ändra polstring eller marginaler. Här är 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>
Hur man använder detta i riktig kod
För att generalisera vad vi har visat ovan: enskilda saker innehåller en fast marginal på "halva vitrummet", och behållaren som de hålls i bör ha en stoppning av "halva vitrummet". Du kan tillämpa dessa stilar i din applikationsresursordbok, och då behöver du inte ens nämna dem på de enskilda artiklarna. Så här kan du definiera "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}"/>
Då kan jag definiera en basstil för att basera mina andra kontrollstilar på: (detta kan också innehålla din standard FontFamily, FontSize, etc, etc)
<Style x:Key="BaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="{StaticResource HalfTheWhiteSpace}"/>
</Style>
Sedan kan jag definiera min standardstyling för TextBox för att använda denna marginal:
<Style TargetType="TextBox" BasedOn="{StaticResource BaseStyle}"/>
Jag kan göra den här typen av saker för DatePickers, etiketter, etc, etc. (allt som kan hållas i en container). Se upp för att utforma TextBlock så här ... att kontrollen används internt av många kontroller. Jag föreslår att du skapar din egen kontroll som helt enkelt härrör från TextBlock. Du kan utforma din TextBlock så att du använder standardmarginalen; och du bör använda din TextBlock när du uttryckligen använder en TextBlock i din XAML.
Du kan använda en liknande metod för att applicera stoppningen på vanliga behållare (t.ex. ScrollViewer, Border, etc).
När du har gjort det kommer de flesta av dina kontroller inte att behöva marginaler och stoppning - och du behöver bara ange värden på platser där du avsiktligt vill avvika från denna designprincip.