Share via


Sistema de diseño

En este tema se describe el sistema de diseño de Windows Presentation Foundation (WPF). Es esencial entender cómo y cuándo se realizan los cálculos de diseño para crear interfaces de usuario en WPF.

Este tema contiene las siguientes secciones:

  • Cuadros de límite de elementos

  • Sistema de diseño

  • Medir y organizar elementos secundarios

  • Elementos de panel y comportamientos de diseño personalizado

  • Consideraciones sobre el rendimiento del diseño

  • Representación de subpíxeles y redondeo del diseño

  • Pasos adicionales

Cuadros de límite de elementos

Al pensar en el diseño en WPF, es importante entender el cuadro de límite que rodea todos los elementos. Cada FrameworkElement usado por el sistema de diseño se puede considerar como un rectángulo que se inserta en el diseño. La clase LayoutInformation devuelve los límites de la asignación del diseño de un elemento o ranura. El tamaño del rectángulo se determina calculando el espacio de pantalla disponible, el tamaño de cualquier restricción, las propiedades específicas del diseño (como el margen y el relleno) y el comportamiento individual del elemento Panel primario. Al procesar estos datos, el sistema de diseño puede calcular la posición de todos los elementos secundarios de un Panel determinado. Es importante recordar que las características de tamaño definidas en el elemento primario, como un Border, afectan a sus elementos secundarios.

En la ilustración siguiente se muestra un diseño sencillo.

Cuadrícula típica sin rectángulo de selección superpuesto.

Este diseño se puede lograr usando el XAML siguiente.

<Grid Name="myGrid" Background="LightSteelBlue" Height="150">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="250"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
    <RowDefinition />
  </Grid.RowDefinitions>
  <TextBlock Name="txt1" Margin="5" FontSize="16" FontFamily="Verdana" Grid.Column="0" Grid.Row="0">Hello World!</TextBlock>
  <Button Click="getLayoutSlot1" Width="125" Height="25" Grid.Column="0" Grid.Row="1">Show Bounding Box</Button>
  <TextBlock Name="txt2" Grid.Column="1" Grid.Row="2"/>
</Grid>

Un único elemento TextBlock se hospeda dentro de un Grid. Aunque el texto rellena solo la esquina superior izquierda de la primera columna, el espacio asignado para TextBlock es mucho mayor realmente. El cuadro de límite de cualquier objeto FrameworkElement se puede recuperar usando el método GetLayoutSlot. En la ilustración siguiente se muestra el cuadro de límite para el elemento TextBlock.

El rectángulo de selección de TextBlock está visible ahora.

Como muestra el rectángulo amarillo, el espacio asignado para el elemento TextBlock es realmente mucho mayor de lo que parece. Al agregar elementos adicionales a Grid, esta asignación se puede reducir o expandir, dependiendo del tipo y el tamaño de los elementos que se agregan.

La ranura de diseño de TextBlock se traduce en Path usando el método GetLayoutSlot. Esta técnica puede ser útil para mostrar el cuadro de límite de un elemento.

Private Sub getLayoutSlot1(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim myRectangleGeometry As New RectangleGeometry
    myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1)
    Dim myGeometryDrawing As New GeometryDrawing
    Dim myPath As New Path
    myPath.Data = myRectangleGeometry
    myPath.Stroke = Brushes.LightGoldenrodYellow
    myPath.StrokeThickness = 5
    Grid.SetColumn(myPath, 0)
    Grid.SetRow(myPath, 0)
    myGrid.Children.Add(myPath)
    txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString()
End Sub
private void getLayoutSlot1(object sender, System.Windows.RoutedEventArgs e)
{
    RectangleGeometry myRectangleGeometry = new RectangleGeometry();
    myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1);
    GeometryDrawing myGeometryDrawing = new GeometryDrawing();
    Path myPath = new Path();
    myPath.Data = myRectangleGeometry;
    myPath.Stroke = Brushes.LightGoldenrodYellow;
    myPath.StrokeThickness = 5;
    Grid.SetColumn(myPath, 0);
    Grid.SetRow(myPath, 0);
    myGrid.Children.Add(myPath);
    txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString();
}

Sistema de diseño

En su versión más simple, el diseño es un sistema recursivo que conduce a la configuración del tamaño, posición y presentación de un elemento. Más específicamente, el diseño describe el proceso de medir y organizar los miembros de una colección Children de un elemento Panel. El diseño es un proceso intensivo. Cuanto mayor sea la colección Children, mayor será el número de cálculos que se deben realizar. También se puede incluir mayor complejidad según el comportamiento de diseño definido por el elemento Panel que posee la colección. Un Panel relativamente sencillo, como Canvas, puede tener un rendimiento mucho mejor que un Panel más complejo, como Grid.

Cada vez que un UIElement secundario cambia su posición, tiene el potencial de desencadenar un nuevo paso del sistema de diseño. Por tanto, es importante entender los eventos que pueden invocar el sistema de diseño, ya que una invocación innecesaria puede deteriorar el rendimiento de la aplicación. A continuación se describe el proceso que tiene lugar cuando se invoca el sistema de diseño.

  1. Un UIElement secundario comienza el proceso de diseño midiendo en primer lugar sus propiedades básicas.

  2. Se evalúan las propiedades de tamaño definidas en FrameworkElement, como Width, Height y Margin.

  3. Se aplica la lógica concreta de Panel, como la dirección de Dock o la Orientation de apilado.

  4. El contenido se organiza después de medir todos los elementos secundarios.

  5. Se dibuja la colección Children en la pantalla.

  6. Se invoca el proceso de nuevo si se agregan Children adicionales a la colección, se aplica una LayoutTransform o se llama al método UpdateLayout.

Este proceso y cómo se invoca se definen con más detalle en las próximas secciones.

Medir y organizar elementos secundarios

El sistema de diseño completa dos pasos por cada miembro de la colección Children: un paso de medida y un paso de organización. Cada Panel secundario proporciona sus propios métodos MeasureOverride y ArrangeOverride para lograr su propio comportamiento de diseño concreto.

Durante el paso de medida, se evalúa cada miembro de la colección Children. El proceso comienza con una llamada al método Measure. Se llama a este método dentro de la implementación del elemento Panel primario y no es preciso llamarla explícitamente para que el diseño tenga lugar.

En primer lugar, se evalúan las propiedades de tamaño nativas de UIElement, como Clip y Visibility. Esto genera un valor denominado constraintSize que se pasa a MeasureCore.

En segundo lugar, se procesan las propiedades de marco definidas en FrameworkElement, lo que afecta al valor de constraintSize. Estas propiedades suelen describir las características de tamaño del UIElement subyacente, como Height, Width, Margin y Style. Cada una de estas propiedades puede modificar el espacio necesario para mostrar el elemento. A continuación se llama a MeasureOverride con constraintSize como parámetro.

NotaNota

Existe una diferencia entre las propiedades de Height y Width, y ActualHeight y ActualWidth.Por ejemplo, la propiedad ActualHeight es un valor calculado que se basa en otras entradas de alto y en el sistema de diseño.El propio sistema de diseño establece el valor, basándose en un paso de representación real; por tanto, puede existir un pequeño desfase con respecto al valor establecido de propiedades como Height, que constituyen la base del cambio de entrada.

Puesto que ActualHeight es un valor calculado, debe tener en cuenta que puede haber cambios notificados múltiples o incrementales del mismo como resultado de las diversas operaciones realizadas por el sistema de diseño.El sistema de diseño puede calcular el espacio de medidas necesario para los elementos secundarios, las restricciones impuestas por el elemento principal, etc.

El objetivo final del paso de medida es que el elemento secundario determine su DesiredSize, lo que sucede durante la llamada a MeasureCore. Measure almacena el valor DesiredSize para usarlo durante el paso de organización del contenido.

El paso de organización se inicia con una llamada al método Arrange. Durante el paso de organización, el elemento Panel primario genera un rectángulo que representa los límites del elemento secundario. Este valor se pasa al método ArrangeCore para procesarlo.

El método ArrangeCore evalúa el DesiredSize del elemento secundario y evalúa cualquier margen adicional que pueda afectar al tamaño representado del elemento. ArrangeCore genera un parámetro arrangeSize, que se pasa al método ArrangeOverride de Panel como un parámetro. ArrangeOverride genera el finalSize del elemento secundario. Por último, el método ArrangeCore realiza una última evaluación de las propiedades de desplazamiento, como los márgenes y la alineación, y coloca el elemento secundario dentro de su ranura de diseño. El elemento secundario no tiene que rellenar todo el espacio asignado, y con frecuencia no lo hace. A continuación, el control se devuelve al Panel primario y el proceso de diseño se completa.

Elementos de panel y comportamientos de diseño personalizado

WPF incluye un grupo de elementos que derivan de Panel. Estos elementosPanel hacen posibles muchos diseños complejos. Por ejemplo, se consigue fácilmente apilar elementos usando el elemento StackPanel, mientras que otros diseños dinámicos más libres y complejos son posibles gracias a Canvas.

En la tabla siguiente se resumen los elementos Panel de diseño disponibles.

Nombre del panel

Descripción

Canvas

Define una área en la que pueden colocarse explícitamente los elementos secundarios utilizando las coordenadas relativas al área del control Canvas.

DockPanel

Define un área en la que se pueden organizar horizontal o verticalmente los elementos secundarios, uno respecto al otro.

Grid

Define un área de cuadrícula flexible que está compuesta de columnas y filas.

StackPanel

Organiza los elementos secundarios en una única línea que se puede orientar horizontal o verticalmente.

VirtualizingPanel

Proporciona un marco para elementos Panel que virtualizan su recolección de datos secundarios. Ésta es una clase abstracta.

WrapPanel

Organiza los elementos secundarios secuencialmente de izquierda a derecha y traslada el contenido a la línea siguiente cuando alcanza el borde del cuadro contenedor. La ordenación siguiente se realiza secuencialmente de arriba abajo o de izquierda a derecha, dependiendo del valor de la propiedad Orientation.

En el caso de las aplicaciones que necesitan un diseño que no es posible lograr usando cualquiera de los elementos Panel predefinidos, se pueden conseguir comportamientos de diseño personalizados heredando de Panel e invalidando los métodos MeasureOverride y ArrangeOverride. Para obtener un ejemplo, vea Ejemplo Custom Radial Panel.

Consideraciones sobre el rendimiento del diseño

El diseño es un proceso recursivo. Cada elemento secundario de una colección Children se procesa durante cada invocación del sistema de diseño. Por tanto, debe evitarse activar el sistema de diseño cuando no es necesario. Las consideraciones siguientes pueden ayudarle a lograr un rendimiento mejor.

  • Sea consciente de que los cambios del valor de propiedad forzarán una actualización recursiva por parte del sistema de diseño.

    Las propiedades de dependencia cuyos valores pueden producir la inicialización del sistema de diseño se marcan con marcas públicas. AffectsMeasure y AffectsArrange proporcionan pistas útiles acerca de qué cambios del valor de propiedad forzarán una actualización recursiva por parte del sistema de diseño. En general, cualquier propiedad que puede afectar al tamaño del cuadro de límite de un elemento debe establecer la marca AffectsMeasure en true. Para obtener más información, vea Información general sobre las propiedades de dependencia.

  • Siempre que sea posible, use una propiedad RenderTransform en lugar de LayoutTransform.

    LayoutTransform puede ser una manera muy útil de afectar al contenido de una user interface (UI). Sin embargo, si el efecto de la transformación no tiene que afectar a la posición de otros elementos, es mejor emplear una propiedad RenderTransform en su lugar, porqueRenderTransform no invoca el sistema de diseño. LayoutTransform aplica su transformación y fuerza una actualización recursiva del diseño para tener en cuenta la nueva posición del elemento afectado.

  • Evite las llamadas innecesarias a UpdateLayout.

    El método UpdateLayout fuerza una actualización recursiva del diseño y no suele ser necesario. A menos que esté seguro de que se necesita una actualización completa, deje que el sistema de diseño llame a este método en su lugar.

  • Cuando se trabaja con una colección Children grande, puede ser conveniente usar un VirtualizingStackPanel en lugar de un StackPanel normal.

    Al virtualizar la colección secundaria, VirtualizingStackPanel únicamente conserva en la memoria los objetos que se encuentran actualmente dentro de la ventanilla del elemento primario. Como resultado, el rendimiento se mejora sustancialmente en la mayoría de los escenarios.

Representación de subpíxeles y redondeo del diseño

El sistema de gráficos de WPF utiliza unidades independientes del dispositivo para que sean independientes de la resolución y del dispositivo. Cada píxel independiente del dispositivo ajusta su escala automáticamente al valor de dots per inch (dpi) del sistema. De esta forma, se proporciona a las aplicaciones de WPF un ajuste de escala correcto para las distintas configuraciones de dpi y hace que la aplicación distinga este valor de dpi automáticamente.

Sin embargo, esta independencia de dpi puede crear representaciones de bordes irregulares debido al suavizado de contorno. Estas anomalías de la imagen, que suelen aparecer como bordes borrosos o semitransparentes, pueden producirse cuando un borde se encuentra en medio de un píxel de dispositivo en vez de situarse entre píxeles de dispositivo. El sistema de diseño ofrece una manera de ajustarlo con el redondeo del diseño. El redondeo del diseño es donde el sistema de diseño redondea cualquier valor de píxel no entero durante el paso de diseño.

El redondeo del diseño está deshabilitado de forma predeterminada. Para habilitar el redondeo del diseño, establezca la propiedad UseLayoutRounding en true en cualquier FrameworkElement. Como se trata de una propiedad de dependencia, el valor se propagará a todos los elementos secundarios del árbol visual. Para habilitar el redondeo del diseño para toda la interfaz de usuario, establezca UseLayoutRounding en true en el contenedor raíz. Para obtener un ejemplo, vea UseLayoutRounding.

Pasos adicionales

Entender cómo se miden y organizan los elementos es el primer paso para entender el diseño. Para obtener más información sobre los elementos Panel disponibles, vea Información general sobre elementos Panel. Para entender mejor las diversas propiedades de posición que pueden afectar al diseño, consulte Información general sobre alineación, márgenes y relleno. Para obtener un ejemplo de un elemento Panel personalizado, vea Ejemplo Custom Radial Panel. Cuando esté preparado para aplicar todos estos conocimientos a la creación de una aplicación ligera, vea Tutorial: Introducción a WPF.

Vea también

Referencia

FrameworkElement

UIElement

Conceptos

Información general sobre elementos Panel

Información general sobre alineación, márgenes y relleno

Optimizar el rendimiento: Presentación y diseño