Compartir a través de


Diseño

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

Este tema contiene las secciones siguientes:

Cuadros de límite de elementos

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

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

Captura de pantalla que muestra una cuadrícula típica, sin cuadro de límite superpuesto.

Este diseño se puede lograr mediante el código 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 Grid. Aunque el texto rellena solo la esquina superior izquierda de la primera columna, el espacio asignado para TextBlock es realmente mucho mayor. El cuadro delimitador de cualquier FrameworkElement se puede recuperar mediante el método GetLayoutSlot. En la ilustración siguiente se muestra el cuadro de límite del elemento TextBlock.

Captura de pantalla que muestra que el cuadro delimitador del TextBlock ahora es visible.

Como se muestra en el rectángulo amarillo, el espacio asignado para el TextBlock elemento es realmente mucho mayor de lo que aparece. A medida que se agregan elementos adicionales a Grid, esta asignación podría reducirse o expandirse, según el tipo y el tamaño de los elementos que se agregan.

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

private void getLayoutSlot1(object sender, System.Windows.RoutedEventArgs e)
{
    RectangleGeometry myRectangleGeometry = new RectangleGeometry();
    myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1);
    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();
}
Private Sub getLayoutSlot1(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim myRectangleGeometry As New RectangleGeometry
    myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1)
    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

El sistema de diseño

En su forma más sencilla, el diseño es un sistema recursivo que conduce a que un elemento tenga el tamaño, la posición y el dibujo. Más concretamente, el diseño describe el proceso de medición y organización de los miembros de la colección de Panel un Children elemento. El diseño es un proceso intensivo. Cuanto mayor sea la Children colección, mayor será el número de cálculos que se deben realizar. La complejidad también se puede introducir en función del comportamiento de diseño definido por el Panel elemento propietario de la colección. Un objeto relativamente simple Panel, como Canvas, puede tener un rendimiento significativamente mejor que un más complejo Panel, como Grid.

Cada vez que un niño UIElement cambia su posición, puede desencadenar un nuevo pase por el sistema de diseño. Por lo tanto, es importante comprender los eventos que pueden invocar el sistema de diseño, ya que la invocación innecesaria puede dar lugar a un rendimiento deficiente de la aplicación. A continuación se describe el proceso que se produce cuando se invoca el sistema de diseño.

  1. Un elemento secundario UIElement comienza el proceso de diseño al medir primero sus propiedades principales.

  2. Las propiedades de ajuste de tamaño definidas en FrameworkElement se evalúan, como Width, Heighty Margin.

  3. PanelSe aplica lógica específica, como la direcciónDock; el apilamiento Orientation.

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

  5. La Children colección se muestra en la pantalla.

  6. El proceso se invoca nuevamente si se agregan más Children a la colección, se aplica un LayoutTransform o se llama al método UpdateLayout.

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

Medición y organización de niños

El sistema de diseño completa dos pasadas para cada miembro de la colección Children, una pasada de medida y una de diseño. Cada hijo Panel proporciona sus métodos MeasureOverride y ArrangeOverride para lograr un comportamiento específico en el diseño.

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

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

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

Nota:

Hay una diferencia entre las propiedades de Height y y Width y ActualHeightActualWidth. Por ejemplo, la ActualHeight propiedad es un valor calculado basado en otras entradas de alto y el sistema de diseño. El propio sistema de diseño establece el valor basado en un paso de representación real y, por tanto, puede quedar ligeramente rezagado respecto al valor configurado con respecto a propiedades, como Height, que sirven de base para el cambio de entrada.

Dado ActualHeight que es un valor calculado, debe tener en cuenta que podría haber varios cambios notificados o incrementales en él como resultado de varias operaciones por parte del sistema de diseño. El sistema de diseño puede calcular el espacio de medida necesario para los elementos secundarios, las restricciones del elemento primario, etc.

El objetivo final del pase de medición es que el elemento secundario determine su DesiredSize, lo cual ocurre durante la llamada de MeasureCore. DesiredSize valor es almacenado por Measure para su uso durante el paso de organización del contenido.

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

El método ArrangeCore evalúa el DesiredSize del elemento secundario y examina cualquier margen adicional que pueda afectar al tamaño representado del elemento. ArrangeCore genera un arrangeSize, que se pasa al método ArrangeOverride de Panel como parámetro. ArrangeOverride genera el objeto finalSize del hijo. Por último, el método ArrangeCore lleva a cabo una evaluación final de las propiedades de desplazamiento, como el margen y la alineación, y coloca el elemento hijo dentro de su espacio de diseño. El elemento hijo no tiene que llenar (y con frecuencia no llena) todo el espacio asignado. A continuación, se devuelve el control al elemento primario Panel y se completa el proceso de diseño.

Elementos de panel y comportamientos de diseño personalizados

WPF incluye un grupo de elementos que derivan de Panel. Estos Panel elementos permiten muchos diseños complejos. Por ejemplo, los elementos de apilamiento se pueden lograr fácilmente mediante el uso del StackPanel elemento, mientras que los diseños de flujo libre y más complejos son posibles mediante .Canvas

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

Nombre del panel Descripción
Canvas Define un área dentro de la cual puedes posicionar explícitamente los elementos secundarios mediante coordenadas, relativas al área Canvas.
DockPanel Define un área dentro de la que puede organizar los elementos secundarios horizontal o verticalmente, en relación entre sí.
Grid Define un área de cuadrícula flexible que consta de columnas y filas.
StackPanel Organiza los elementos secundarios en una sola línea que se puede orientar horizontal o verticalmente.
VirtualizingPanel Proporciona un marco para Panel los elementos que virtualizan su colección de datos secundaria. Se trata de una clase abstracta.
WrapPanel Coloca los elementos secundarios en posición secuencial de izquierda a derecha, pasando el contenido a la siguiente línea en el borde del cuadro contenedor. La ordenación posterior se produce secuencialmente de arriba a abajo o derecha a izquierda, dependiendo del valor de la Orientation propiedad.

En el caso de las aplicaciones que requieren un diseño que no es posible mediante ninguno de los elementos predefinidos Panel, se puede lograr un comportamiento de diseño personalizado heredando de Panel y sobreescribiendo los métodos MeasureOverride y ArrangeOverride.

Consideraciones sobre el rendimiento del diseño

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

  • Tenga en cuenta qué cambios de valor de propiedad forzarán una actualización recursiva por parte del sistema de diseño.

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

  • Cuando sea posible, use un RenderTransform en lugar de un LayoutTransform.

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

  • Evite llamadas innecesarias a UpdateLayout.

    El UpdateLayout método fuerza una actualización de diseño recursiva y, con frecuencia, no es necesario. A menos que esté seguro de que se requiere una actualización completa, confíe en el sistema de diseño para llamar a este método por usted.

  • Al trabajar con una colección grande Children, considere usar una VirtualizingStackPanel en lugar de una StackPanel normal.

    Al virtualizar la colección secundaria, el VirtualizingStackPanel sólo mantiene los objetos en la memoria que se encuentran actualmente en el ViewPort del elemento primario. Como resultado, el rendimiento se mejora considerablemente en la mayoría de los escenarios.

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

El sistema de gráficos WPF usa unidades independientes del dispositivo para habilitar la resolución y la independencia del dispositivo. Cada píxel independiente del dispositivo se escala automáticamente con la configuración de puntos por pulgada (ppp) del sistema. Esto proporciona el escalado adecuado de las aplicaciones WPF para diferentes configuraciones de ppp y hace que la aplicación sea compatible automáticamente con ppp.

Sin embargo, esta independencia de dpi puede crear un renderizado de bordes irregular debido al suavizado de bordes. Estos artefactos, normalmente vistos como bordes borrosos o semitransparentes, pueden producirse cuando la ubicación de un borde cae en medio de un píxel del dispositivo en lugar de entre píxeles del dispositivo. El sistema de diseño proporciona una manera de ajustar esto con el redondeo de diseño. El redondeo de diseño consiste en que el sistema de diseño redondea los valores de píxeles no enteros durante el paso de diseño.

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

Pasos siguientes

Comprender cómo se miden y organizan los elementos es el primer paso para comprender el diseño. Para obtener más información sobre los elementos disponibles Panel , vea Información general sobre paneles. Para comprender mejor las distintas propiedades de posicionamiento que pueden afectar al diseño, consulte Alineación, Márgenes y Información general sobre relleno. Cuando esté listo para reunirlo todo en una aplicación ligera, vea Tutorial: Mi primera aplicación de escritorio de WPF.

Consulte también