wpf
Principio de diseño "La mitad del espacio en blanco"
Buscar..
Introducción
Al diseñar los controles, es fácil codificar valores específicos en márgenes y rellenos para que las cosas se ajusten al diseño deseado. Sin embargo, al codificar estos valores, el mantenimiento se vuelve mucho más caro. Si el diseño cambia, en lo que podría considerarse una forma trivial, entonces hay que trabajar mucho para corregir estos valores.
Este principio de diseño reduce el costo de mantenimiento del diseño al pensar en el diseño de una manera diferente.
Demostración del problema y la solución.
Por ejemplo, imagina una pantalla con 3 secciones, dispuestas así:
La caja azul podría tener un margen de 4,4,0,0. El cuadro verde podría tener un margen de 4,4,4,0. El margen de la caja púrpura sería 4,4,4,4. Aquí está el XAML: (Estoy usando una cuadrícula para lograr el diseño, pero este principio de diseño se aplica independientemente de cómo elijas para lograr el diseño):
<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>
Ahora imagine que queremos cambiar el diseño, para colocar el cuadro verde a la izquierda del cuadro azul. Debería ser simple, ¿no? Excepto que cuando movemos esa caja, ahora necesitamos jugar con los márgenes. O bien podemos cambiar los márgenes de la caja azul a 0,4,4,0; o podríamos cambiar azul a 4,4,4,0 y verde a 4,4,0,0. Aquí está el 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>
Ahora vamos a poner la caja morada en la parte superior. Entonces los márgenes del azul se convierten en 4,0,4,4; El verde se convierte en 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>
¿No sería bueno si pudiéramos mover las cosas de manera que no tuviéramos que ajustar estos valores en absoluto? Esto se puede lograr simplemente pensando en el espacio en blanco de una manera diferente. En lugar de asignar todo el espacio en blanco a un control u otro, imagine la mitad del espacio en blanco que se asigna a cada cuadro: (mi dibujo no está del todo a escala: las líneas de puntos deben estar a medio camino entre el borde del cuadro y su vecino) .
Así que la caja azul tiene márgenes de 2,2,2,2; La caja verde tiene márgenes de 2,2,2,2; La caja morada tiene márgenes de 2,2,2,2. Y al contenedor en el que están alojados se le da un relleno (no margen) de 2,2,2,2. Aquí está el 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>
Ahora intentemos mover las cajas de la misma manera que antes ... Pongamos la caja verde a la izquierda de la caja azul. OK hecho. Y no hubo necesidad de cambiar ningún relleno o márgenes. Aquí está el 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>
Ahora vamos a poner la caja morada en la parte superior. OK hecho. Y no hubo necesidad de cambiar ningún relleno o márgenes. Aquí está el 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>
Cómo usar esto en código real.
Para generalizar lo que hemos demostrado anteriormente: las cosas individuales contienen un margen fijo de "mitad del espacio en blanco", y el contenedor en el que se encuentran debe tener un relleno de "mitad del espacio en blanco". Puede aplicar estos estilos en el diccionario de recursos de su aplicación, y ni siquiera necesitará mencionarlos en los elementos individuales. Así es como puedes definir "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}"/>
Luego puedo definir un estilo base para basar mis otros estilos de controles en: (esto también podría contener su FontFamily, FontSize, etc., por defecto)
<Style x:Key="BaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="{StaticResource HalfTheWhiteSpace}"/>
</Style>
Luego puedo definir mi estilo predeterminado para que TextBox use este margen:
<Style TargetType="TextBox" BasedOn="{StaticResource BaseStyle}"/>
Puedo hacer este tipo de cosas para DatePickers, etiquetas, etc., etc. (cualquier cosa que pueda estar dentro de un contenedor). Tenga cuidado con el estilo de TextBlock como este ... ese control es usado internamente por muchos controles. Te sugiero que crees tu propio control que simplemente se deriva de TextBlock. Puede aplicar estilo a su TextBlock para usar el margen predeterminado; y debe usar su TextBlock siempre que use explícitamente un TextBlock en su XAML.
Puede utilizar un enfoque similar para aplicar el relleno a contenedores comunes (por ejemplo, ScrollViewer, Border, etc.).
Una vez que hayas hecho esto, la mayoría de tus controles no necesitarán márgenes ni relleno, y solo necesitarás especificar los valores en los lugares donde quieras desviarte intencionalmente de este principio de diseño.