Szukaj…


Wprowadzenie

Podczas układania elementów sterujących łatwo jest na stałe zakodować określone wartości w marginesach i wypełnieniach, aby dopasować elementy do pożądanego układu. Jednak dzięki zakodowaniu tych wartości konserwacja staje się znacznie droższa. Jeśli zmienia się układ, co można uznać za trywialny sposób, wówczas wiele pracy wymaga poprawienia tych wartości.

Ta zasada projektowania obniża koszty utrzymania układu, myśląc o układzie w inny sposób.

Demonstracja problemu i rozwiązania

Na przykład wyobraź sobie ekran z 3 sekcjami, ułożonymi w następujący sposób: Pożądany układ ekranu

Niebieskie pole może mieć margines 4,4,0,0. Zielone pole może mieć margines 4,4,4,0. Fioletowy margines pola wyniósłby 4,4,4,4. Oto XAML: (Korzystam z siatki, aby uzyskać układ; ale ta zasada projektowania ma zastosowanie niezależnie od tego, jak zdecydujesz się uzyskać układ):

<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>

Teraz wyobraź sobie, że chcemy zmienić układ, aby umieścić zielone pole po lewej stronie niebieskiego pola. Powinno być proste, prawda? Tyle, że kiedy przenosimy to pole, musimy teraz majstrować przy marginesach. Albo możemy zmienić marginesy niebieskiej skrzynki na 0,4,4,0; lub możemy zmienić kolor niebieski na 4,4,4,0 i zielony na 4,4,0,0. Oto 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>

Teraz umieśćmy fioletowe pudełko na górze. Tak więc marginesy niebieskie stają się 4,0,4,4; zielony staje się 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>

Czy nie byłoby miło, gdybyśmy mogli przenosić różne rzeczy, abyśmy wcale nie musieli dostosowywać tych wartości. Można to osiągnąć, myśląc o spacji w inny sposób. Zamiast przypisywać wszystkie białe znaki do jednej lub drugiej kontrolki, wyobraź sobie, że połowa białych znaków jest przypisywana do każdego pola: (mój rysunek nie jest całkiem w skali - kropkowane linie powinny znajdować się w połowie odległości między krawędzią pola a sąsiadem) .

wprowadź opis zdjęcia tutaj

Zatem niebieskie pole ma marginesy 2,2,2,2; zielone pole ma marginesy 2,2,2,2; fioletowe pudełko ma marginesy 2,2,2,2. A pojemnik, w którym się znajdują, ma wypełnienie (nie margines) 2,2,2,2. Oto 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>

Teraz spróbujmy przesunąć pola tak, jak poprzednio ... Połóżmy zielone pole po lewej stronie niebieskiego pola. Ok, wykonane. I nie trzeba było zmieniać wypełnienia ani marginesów. Oto 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>

Teraz umieśćmy fioletowe pudełko na górze. Ok, wykonane. I nie trzeba było zmieniać wypełnienia ani marginesów. Oto 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>

Jak używać tego w prawdziwym kodzie

Aby uogólnić to, co wykazaliśmy powyżej: poszczególne rzeczy zawierają stały margines „połowy białej spacji”, a pojemnik, w którym są trzymane, powinien mieć wypełnienie „połowy białej spacji”. Możesz zastosować te style w słowniku zasobów aplikacji, a wtedy nie musisz nawet wymieniać ich w poszczególnych elementach. Oto jak zdefiniować „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}"/>

Następnie mogę zdefiniować styl bazowy, na którym będą opierały się moje inne style kontrolek: (może to również zawierać domyślną czcionkę FontFamily, FontSize itp.)

<Style x:Key="BaseStyle" TargetType="{x:Type Control}">
    <Setter Property="Margin" Value="{StaticResource HalfTheWhiteSpace}"/>
</Style>

Następnie mogę zdefiniować mój domyślny styl dla TextBox, aby użyć tego marginesu:

<Style TargetType="TextBox" BasedOn="{StaticResource BaseStyle}"/>

Mogę zrobić coś takiego dla DatePickers, Etykiet itp. (Wszystko, co może być przechowywane w pojemniku). Uważaj na stylizowanie TextBlocka w ten sposób ... ta kontrola jest używana wewnętrznie przez wiele kontroli. Sugeruję utworzenie własnej kontroli, która po prostu wywodzi się z TextBlock. Można projektować swoje TextBlock korzystania z marginesu domyślnej; i należy używać TextBlock gdy jawnie używać TextBlock w swoim XAML.

Możesz zastosować podobne podejście, aby zastosować wypełnienie do popularnych kontenerów (np. ScrollViewer, Border, itp.).

Gdy to zrobisz, większość elementów sterujących nie będzie potrzebować marginesów i wypełnienia - musisz jedynie określić wartości w miejscach, w których celowo chcesz odejść od tej zasady projektowania.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow