Capítulo 3: Controles y XAML
Introducción
Capítulo 1: Modelo de aplicación "Longhorn"
Capítulo 2: Creación de una aplicación "Longhorn"
Capítulo 3: Controles y XAML
Brent Rector
Wise Owl Consulting
Diciembre de 2003
Contenido
Elementos XAML
Paneles XAML
Controles
Recursos y estilos
Gráficos y animaciones
Servicios de documentos
Resumen
Como has visto en el capítulo 2, las aplicaciones de la plataforma Longhorn normalmente constan de un objeto Application y un conjunto de páginas de interfaz de usuario que escribes en un lenguaje de marcado declarativo denominado XAML.
El objeto Application es un singleton y persiste durante toda la vigencia de la aplicación. Permite que la lógica de la aplicación controle eventos de nivel superior y comparta código y estado entre las páginas. El objeto Application también determina si la aplicación es una aplicación de ventana única o una aplicación de navegación.
Normalmente, escribes cada página de interfaz de usuario con un dialecto de XML denominado Lenguaje de marcado de aplicación extensible (XAML). Cada página consta de elementos XAML, nodos de texto y otros componentes organizados en un árbol jerárquico. La relación jerárquica de estos componentes determina cómo se representa y se comporta la página.
También puedes considerar una página XAML para que sea una descripción de un modelo de objetos. Cuando el tiempo de ejecución crea la página, crea una instancia de cada uno de los elementos y nodos descritos en el documento XAML y crea un modelo de objetos equivalente en memoria. Puede manipular este modelo de objetos mediante programación; por ejemplo, puede agregar y quitar elementos y nodos para que la página se represente y se comporte de forma diferente.
Fundamentalmente, una página XAML describe las clases que el tiempo de ejecución debe crear, los valores de propiedad y los controladores de eventos para las instancias de las clases y una jerarquía del modelo de objetos, es decir, qué instancia es el elemento primario de otra instancia.
Todos los documentos XAML son documentos XML bien formados que usan un conjunto definido de nombres de elementos. Por lo tanto, todas las reglas relacionadas con la formación de documentos XML bien formados se aplican igualmente a los documentos XAML. Por ejemplo, el documento debe contener un único elemento raíz; todos los nombres de elemento distinguen mayúsculas de minúsculas; una definición de elemento no puede superponerse a otra definición de elemento, pero debe contenerla por completo, etc. Si no está familiarizado con la sintaxis XML, ahora es un excelente momento para aprenderlo.
Elementos XAML
Cada página XAML contiene uno o varios elementos que controlan el diseño y el comportamiento de la página. Estos elementos se organizan jerárquicamente en un árbol. Cada elemento tiene solo un elemento primario. Por lo general, los elementos pueden tener cualquier número de elementos secundarios. Sin embargo, algunos tipos de elementos (por ejemplo, Scrollbar) no tienen elementos secundarios; y otros tipos de elementos (por ejemplo, Border) pueden tener un único elemento secundario.
Cada nombre de elemento corresponde al nombre de una clase administrada. Al agregar un elemento a un documento XAML, el tiempo de ejecución crea una instancia de la clase correspondiente. Por ejemplo, el marcado siguiente representa un elemento DockPanel raíz que tiene un único elemento Table secundario. El elemento Table contiene tres elementos Row secundarios. Cada elemento Row contiene tres elementos secundarios y algunos de ellos tienen nodos de texto secundarios.
<Border xmlns="https://schemas.microsoft.com/2003/xaml"
Background="BlanchedAlmond">
<DockPanel>
<Table>
<Body>
<Row>
<Cell><Button/></Cell>
<Cell><Text>Item</Text></Cell>
<Cell><Text>Price</Text></Cell>
</Row>
<Row>
<Cell><CheckBox Checked="true"/></Cell>
<Cell><TextBox Height="50">Nissan 350Z</TextBox></Cell>
<Cell><TextBox Height="50">29.95</TextBox></Cell>
</Row>
<Row>
<Cell><CheckBox/></Cell>
<Cell><TextBox Height="50">Porsche Boxster</TextBox></Cell>
<Cell><TextBox Height="50">9.95</TextBox></Cell>
</Row>
</Body>
</Table>
</DockPanel>
</Border>
Este documento XAML crea una jerarquía de objetos como se muestra en la figura 3-1 y la presentación que se muestra en la figura 3-2.
Figura 3-1. Un modelo de objetos de página XAML de ejemplo
Figura 3-2. Pantalla del XAML anterior (haga clic para obtener una imagen más grande).
Puede acceder a gran parte de la funcionalidad de estos objetos usando solo marcado. Con solo marcado, puede realizar cualquiera de las siguientes acciones:
- Describir un conjunto jerárquico de objetos en los que se creará una instancia del entorno de ejecución
- Establecer propiedades de objeto en valores conocidos estáticamente
- Establecer propiedades de objeto en valores recuperados de un origen de datos
- Hacer que los valores de propiedad modificados se almacenen de nuevo en el origen de datos
- Cambiar repetidamente el valor de una propiedad a lo largo del tiempo
- Enlazar un controlador de eventos al evento de un objeto
Sin embargo, aunque puedes crear algunas interfaces de usuario increíbles con solo marcado, también puedes acceder a la funcionalidad de un elemento mediante programación mediante el modelo de objetos XAML. El modelo de objetos permite manipular todos los aspectos de los elementos de una página. En realidad, proporciona funcionalidades adicionales que no son accesibles a través de XAML.
Cada elemento XAML deriva de System.Windows.UIElement o System.Windows.ContentElement y, por lo tanto, todos los elementos poseen una serie de características comunes. Los elementos se pueden agrupar en las cuatro categorías básicas siguientes:
- Los controles derivan de System.Windows.Control y controlan la interacción del usuario.
- Los paneles son controles especializados que derivan de System.Windows.Panel y controlan el diseño de página y actúan como contenedores para los elementos.
- Los elementos de formato de texto derivan de System.Windows.TextElement y controlan el formato de texto y la estructura del documento.
- Las formas controlan formas gráficas vectoriales.
Paneles XAML
Normalmente, una página XAML comienza con un elemento de panel. El panel es un contenedor para el contenido de una página y controla el posicionamiento y la representación de ese contenido. De hecho, cuando se muestra cualquier cosa mediante XAML, un panel siempre está implicado, aunque a veces es implícito en lugar de uno que describa explícitamente. Un panel puede contener otros paneles, lo que le permite particionar la superficie de visualización en regiones, cada uno controlado por su panel.
Hay seis clases de panel integradas en la plataforma Longhorn:
- Un elemento Canvas coloca explícitamente cada elemento secundario mediante coordenadas relativas al área Canvas.
- Un DockPanel coloca sus elementos secundarios en la parte superior, inferior, izquierda, derecha o centro del panel. Al asignar varios elementos secundarios al mismo área, un DockPanel los organiza horizontal o verticalmente dentro de esa área.
- Un FlowPanel organiza sus elementos secundarios según sus propiedades de alineación y salto de línea. Cuando el contenido supera la longitud de una sola línea, el panel interrumpirá las líneas, ajustará las líneas y alineará el contenido correctamente.
- Un TextPanel representa varias líneas de texto en varios formatos de texto. Normalmente lo usará solo cuando necesite un diseño de texto complejo. En la mayoría de los casos, usará el elemento Text ligero para admitir texto básico.
- GridPanel es un elemento ligero que organiza sus elementos secundarios en filas y columnas que forman una cuadrícula. Resulta útil para crear tablas sencillas, pero tiene características limitadas. Usaría el control Table para el diseño de tabla complejo.
- FixedPanel coloca sus elementos secundarios en una página de diseño fija. Los elementos de las páginas de diseño fijas siempre tienen la misma posición y paginación, independientemente de la resolución del dispositivo o del tamaño de la ventana.
Por lo general, estos paneles proporcionarán funcionalidad suficiente para la mayoría de los desarrolladores. Sin embargo, también puede crear sus propias clases de panel que coloquen y muestren contenido de forma especializada.
Lienzo
El panel Lienzo proporciona una flexibilidad considerable con respecto al posicionamiento y la organización de elementos en la pantalla. Permite especificar la ubicación de cada elemento secundario y, cuando los elementos se superponen, puede especificar el orden en el que el lienzo dibuja los elementos superpuestos cambiando el orden en que aparecen los elementos en el marcado.
El marcado siguiente genera tres gráficos superpuestos, como se ve en la figura 3-1: un rectángulo verde con un borde naranja, una elipse amarilla translúcida con un borde azul y un texto centrado en el rectángulo. (El pensamiento de nunca más escribir un controlador de WM_PAINT para dibujar cosas como esto trae lágrimas a mis ojos . . . lágrimas de alegría que he agarrado a agregar! El marco dibuja las formas en el orden presentado, por lo que el texto aparece sobre el rectángulo.
<Canvas xmlns="https://schemas.microsoft.com/2003/xaml" >
<Rectangle
Fill="#33CC66"
Width="2in" Height="1in"
Canvas.Top="25" Canvas.Left="50"
StrokeThickness="6px" Stroke="Orange" />
<Ellipse
Fill="yellow"
CenterX="1.5in" CenterY="1.1in"
RadiusX=".5in" RadiusY="1in"
StrokeThickness="4px" Stroke="Blue" />
<Text
Canvas.Top="50" Canvas.Left="60" Foreground="#000000"
FontWeight="Bold" FontFamily="Arial"
FontStyle="Normal" FontSize="25">Hello Shapes!</Text>
</Canvas>
Figura 3-3. Ejemplo de uso del panel Lienzo
DockPanel
El panel DockPanel organiza los elementos secundarios horizontal o verticalmente, en relación entre sí. La clase DockPanel examina la propiedad Dock de cada elemento secundario para determinar cómo alinear el elemento a lo largo de los bordes del panel. Puede establecer la propiedad Dock en uno de los cinco valores: Top, Bottom, Left, Right o Fill.
Por ejemplo, un panel alinea el primer elemento secundario con su propiedad Dock igual a Top en el borde superior del panel. A continuación, el panel alinea el siguiente elemento secundario con su propiedad Dock igual a Top justo debajo del elemento anterior. El panel alinea de forma similar los elementos secundarios con su propiedad Dock establecida en Bottom, Left o Right. Establecer la propiedad Dock del último elemento secundario en Fill hace que ocupe todo el espacio restante en DockPanel. Nunca siga un elemento Dock="Fill" con otros elementos porque los elementos posteriores no estarán visibles. El valor predeterminado de la propiedad Dock es Left, por lo que cuando no se establece la propiedad Dock para un elemento, se apila horizontalmente a la izquierda.
La propiedad Dock es una propiedad adjunta, se define mediante la clase DockPanel , pero se establece en un elemento secundario de la siguiente manera:
<child DockPanel.Dock="Top"/>
O bien, en el código:
DockPanel.SetDock(child, Dock.Top)
El marcado siguiente usa un DockPanel y cinco paneles canvas para crear una interfaz de usuario que se suele ver. DockPanel alinea los dos primeros lienzos en la parte superior del DockPanel. Alinea el tercer lienzo con el borde inferior del DockPanel, el cuarto frente al borde izquierdo y el quinto lienzo rellena el espacio restante. Puede colocar un menú en el panel superior y una barra de herramientas en el panel justo debajo del menú. Esta decisión deja el panel izquierdo para una vista de árbol, el panel inferior de una barra de estado y el panel restante para la vista de elemento seleccionada detallada, como puede ver en la figura 3-4.
<Border xmlns="https://schemas.microsoft.com/2003/xaml"
Background="White">
<DockPanel>
<Border Width="500" DockPanel.Dock="Top"
BorderThickness="2,2,2,2" BorderBrush="Black" Background="#87ceeb" >
<Text>Dock = "Top"</Text>
</Border>
<Border Width="500" DockPanel.Dock="Top"
BorderThickness="2,2,2,2" BorderBrush="Black" Background="#87ceeb" >
<Text>Dock = "Top"</Text>
</Border>
<Border Width="500" DockPanel.Dock="Bottom"
BorderThickness="2,2,2,2"
BorderBrush="Black" Background="#ffff99" >
<Text>Dock = "Bottom"</Text>
</Border>
<Border Width="200" DockPanel.Dock="Left"
BorderThickness="2,2,2,2" BorderBrush="Black" Background="#98fb98" >
<Text>Dock = "Left"</Text>
</Border>
<Border Width="300" DockPanel.Dock="Fill"
BorderThickness="2,2,2,2" BorderBrush="Black" Background="White" >
<Text>Dock = "Fill"</Text>
</Border>
</DockPanel>
</Border>
Figura 3-4. Un ejemplo con el panel DockPanel
FlowPanel
El panel FlowPanel proporciona una serie de características de diseño automático y permite presentaciones complejas de texto y gráficos. El tamaño del panel se define con sus propiedades Width y Height . A continuación, el panel muestra sus elementos secundarios de una manera que mejor use el espacio del panel, encapsulando y alineando los elementos según sea necesario. La dirección de flujo predeterminada para un FlowPanel es de izquierda a derecha y de arriba abajo.
En el siguiente ejemplo de marcado se muestra cómo flowPanel interrumpe y ajusta el contenido. FlowPanel contiene cuatro lienzos cuadrados de una pulgada. FlowPanel intenta mostrar sus elementos secundarios de izquierda a derecha y arriba abajo.
<Border xmlns="https://schemas.microsoft.com/2003/xaml" Background="White">
<FlowPanel>
<Border Background="Red" Width="1in" Height="1in"/>
<Border Background="Green" Width="1in" Height="1in"/>
<Border Background="Blue" Width="1in" Height="1in"/>
<Border Background="Yellow" Width="1in" Height="1in"/>
</FlowPanel>
</Border>
La figura 3-3 muestra la salida cuando FlowPanel puede ajustarse a todos los elementos de una sola línea. En la figura 3-4 se muestra el ajuste de FlowPanel del último elemento a una nueva línea. En la figura 3-5 se muestra el peor caso en el que FlowPanel debe colocar cada elemento en su propia línea. En la figura 3-6 se muestra el último ajuste de elemento en una nueva línea y la figura 3-7 muestra cada ajuste de elementos a una nueva línea.
Figura 3-5. FlowPanel interrumpe las líneas solo cuando sea necesario.
Figura 3-6. El panel FlowPanel ajustando el último elemento a una nueva línea
Figura 3-7. Panel FlowPanel que ajusta cada elemento a una nueva línea
TextPanel
El panel TextPanel da formato, tamaños y dibuja texto. Esta clase de panel admite varias líneas de texto, así como varios formatos de texto. Normalmente usará la clase TextPanel cuando necesite compatibilidad con diseños complejos. Sin embargo, cuando solo se requiere una presentación de texto simple, es mejor usar el elemento Text en su lugar.
En el siguiente ejemplo de marcado se muestra cómo textPanel interrumpe y ajusta el contenido. TextPanel ajusta el número de columnas y el alto de cada columna a medida que cambia el tamaño de la ventana.
<Border xmlns="https://schemas.microsoft.com/2003/xaml" Background="White">
<TextPanel
ColumnCount="3"
ColumnWidth="200px"
ColumnGap="25px"
ColumnRuleWidth="5px"
ColumnRuleBrush="blue">
<Block Background="LightGray">
<Inline FontFamily="Arial" FontWeight="Bold"
FontSize="16pt">Transcript of the
<Italic>Nicolay Draft</Italic>
of the Gettysburg Address.
</Inline>
</Block>
§
</TextPanel>
</Border>
En la figura 3-8 se muestra la salida resultante.
Figura 3-8. TextPanel con varias características de fuente, columnas y formato
GridPanel
El panel GridPanel muestra datos tabulares. GridPanel admite muchas propiedades que puede usar para personalizar el diseño de los datos tabulares. Por ejemplo, puede establecer las propiedades Columns y Rows para controlar el número de columnas y filas de la cuadrícula. Del mismo modo, las propiedades ColumnStyles y RowStyles permiten establecer una colección de propiedades que GridPanel aplica a las filas y columnas, respectivamente.
GridPanel organiza sus elementos secundarios en orden, empezando por la celda superior izquierda y moviéndose a la derecha hasta el final de la fila. Un elemento secundario puede tomar más de una columna si establece la propiedad GridPanel.ColumnSpan en el elemento secundario. Del mismo modo, GridPanel.RowSpan permite que un elemento secundario abarque varias filas.
En el marcado siguiente se muestra una interfaz de usuario calculator que tiene un aspecto bastante similar a la utilidad Calculadora de Windows.
<Border xmlns="https://schemas.microsoft.com/2003/xaml" Background="#DEE7F7">
<DockPanel Dock="Left">
<Border BorderThickness="0,0,0,0">
<!-- Padding="10, 10, 10, 10" -->
<GridPanel Columns="7">
<GridPanel.ColumnStyles>
<Column Width="16%"/>
<Column Width="4%"/>
<Column Width="16%"/>
<Column Width="16%"/>
<Column Width="16%"/>
<Column Width="16%"/>
<Column Width="16%"/>
</GridPanel.ColumnStyles>
<GridPanel.RowStyles>
<Row Height="25"/>
<Row Height="10"/>
<Row Height="35"/>
<Row Height="7"/>
<Row Height="35"/>
<Row Height="35"/>
<Row Height="35"/>
<Row Height="35"/>
</GridPanel.RowStyles>
<Border GridPanel.ColumnSpan="7" BorderBrush="#DEE7F7"
BorderThickness="2,2,2,2" Background="White">
<Text HorizontalAlignment="right"
ID="CalcText">0.</Text>
</Border>
<Text GridPanel.ColumnSpan="7"/>
<Border BorderThickness="0,0,0,0">
<GridPanel>
<Border BorderBrush="#DEE7F7" BorderThickness="2,2,2,2">
<Text Width="16%"
HorizontalAlignment="center"></Text>
</Border>
</GridPanel>
</Border>
<Text Width="4%"/>
<DockPanel GridPanel.ColumnSpan="5" Dock="Left">
<Button Width="33.33%" Foreground="Red">Backspace</Button>
<Button Width="33.33%" Foreground="Red">CE</Button>
<Button Width="33.33%" Foreground="Red">C</Button>
</DockPanel>
<Text GridPanel.ColumnSpan="7"/>
<Button Foreground="Red">MC</Button>
<Text/>
<Button Foreground="Blue">7</Button>
<Button Foreground="Blue">8</Button>
<Button Foreground="Blue">9</Button>
<Button Foreground="Red">/</Button>
<Button Foreground="Blue">sqrt</Button>
<Button Foreground="Red">MR</Button>
<Text/>
<Button Foreground="Blue">4</Button>
<Button Foreground="Blue">5</Button>
<Button Foreground="Blue">6</Button>
<Button Foreground="Red">*</Button>
<Button Foreground="Blue">%</Button>
<Button Foreground="Red">MS</Button>
<Text/>
<Button Foreground="Blue">1</Button>
<Button Foreground="Blue">2</Button>
<Button Foreground="Blue">3</Button>
<Button Foreground="Red">-</Button>
<Button Foreground="Blue">1/x</Button>
<Button Foreground="Red">M+</Button>
<Text/>
<Button Foreground="Blue">0</Button>
<Button Foreground="Blue">+/-</Button>
<Button Foreground="Blue">.</Button>
<Button Foreground="Red">+</Button>
<Button Foreground="Red">=</Button>
</GridPanel>
</Border>
</DockPanel>
</Border>
En la figura 3-9 se muestra la salida resultante.
Figura 3-9. GridPanel como calculadora
FixedPanel
El panel FixedPanel permite especificar las ubicaciones y tamaños exactos de cada elemento. Los elementos de fixedPanel siempre se mostrarán en la misma ubicación y tamaño en todos los dispositivos. Analizaré el panel FixedPanel más adelante en este capítulo de la sección "Servicios de diseño de documentos".
Controles
XAML tiene todos los controles que se esperan de Windows: botones, casillas, botones de radio, cuadros de lista, cuadros combinados, menús, barras de desplazamiento, controles deslizantes, etc. En este ejemplo se muestran algunos de los controles comunes proporcionados en Longhorn. Puede ver los resultados en la figura 3-10.
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem Header="New" />
<MenuItem Header="Open" />
</MenuItem>
<MenuItem Header="Edit">
<MenuItem Header="Cut"/>
<MenuItem Header="Copy"/>
<MenuItem Header="Paste"/>
</MenuItem>
</Menu>
<FlowPanel>
<Button> Button </Button>
<Border Width="15"/>
<CheckBox Checked="true"> CheckBox </CheckBox>
<Border Width="15"/>
<RadioButtonList>
<RadioButton> RadioButton 1 </RadioButton>
<RadioButton Checked="true"> RadioButton 2 </RadioButton>
<RadioButton> RadioButton 3 </RadioButton>
</RadioButtonList>
<Border Width="15"/>
<ListBox>
<ListItem> ListItem 1 </ListItem>
<ListItem> ListItem 2 </ListItem>
<ListItem> ListItem 3 </ListItem>
</ListBox>
<Border Width="15"/>
<ComboBox>
<ListItem> ListItem 1 </ListItem>
<ListItem> ListItem 2 </ListItem>
<ListItem> ListItem 3 </ListItem>
</ComboBox>
<Border Width="15"/>
<DockPanel>
<VerticalSlider DockPanel.Dock="Top" Height="200"
Minimum="0" Maximum="255" Value="75"
SmallChange="1" LargeChange="16"/>
<Text DockPanel.Dock="Bottom">Slider</Text>
</DockPanel>
<Border Width="15"/>
<DockPanel>
<VerticalScrollBar DockPanel.Dock="Top"
Minimum="0" Maximum="255" Value="125" Height="200"
SmallChange="1" LargeChange="16"/>
<Text DockPanel.Dock="bottom">ScrollBar</Text>
</DockPanel>
<Border Width="15"/>
<TextBox> TextBox </TextBox>
</FlowPanel>
</DockPanel>
</Border>
Figura 3-10. Un ejemplo de controles XAML
XAML también permite combinar elementos y controles para crear efectos enriquecidos. Llamamos a esta combinación de elementos que controlan la composición, y es uno de los aspectos más poderosos de Longhorn. Por ejemplo, para crear un botón con una imagen, coloque un elemento Image dentro de Button:
<Button>
<Image Source="tulip.jpg"/>
</Button>
Para tener una imagen y un texto en el botón, como puede ver en la figura 3-11, usamos nuestro antiguo dockPanel de confianza:
<Button>
<DockPanel>
<Image Source="tulip.jpg"/>
<Text DockPanel.Dock="fill" VerticalAlignment="center"> Button
<Italic>with Image!</Italic>
</Text>
</DockPanel>
</Button>
Figura 3-11. Un botón con una imagen y texto
Puede colocar prácticamente cualquier cosa dentro de cualquier cosa, incluido este extraño ejemplo de una CheckBox dentro de un Botón:
<Button>
<CheckBox Checked="true"> CheckBox </CheckBox>
</Button>
La composición es lo suficientemente eficaz como para que muchos de los controles longhorn se definan realmente mediante composición. Por ejemplo, una barra de desplazamiento es realmente dos botones y un control deslizante, además de una lógica de controlador de eventos para enlazarlas juntas.
XAML también incluye algunos "primitivos" de control, que se usan principalmente con la composición del control para crear efectos más grandes. Por ejemplo, ScrollViewer toma un elemento secundario (normalmente un panel) y agrega barras de desplazamiento a él. En este ejemplo se coloca una lista muy grande de elementos CheckBox dentro de un ScrollViewer, algo que antes de Longhorn requería un control independiente, como Windows Forms CheckedListBox:
<Border BorderThickness="1" BorderBrush="black">
<ScrollViewer Height="100" Width="200">
<GridPanel Columns="1">
<CheckBox Checked="true"> CheckBox 1</CheckBox>
<CheckBox Checked="true"> CheckBox 2</CheckBox>
<CheckBox Checked="true"> CheckBox 3</CheckBox>
<CheckBox Checked="true"> CheckBox </CheckBox>
<CheckBox Checked="true"> CheckBox </CheckBox>
<CheckBox Checked="true"> CheckBox </CheckBox>
<CheckBox Checked="true"> CheckBox </CheckBox>
<CheckBox Checked="true"> CheckBox </CheckBox>
</GridPanel>
</ScrollViewer>
</Border>
Recursos y estilos
XAML proporciona instalaciones muy enriquecidas para personalizar el aspecto de la aplicación, a través de entidades conocidas como estilos. Sin embargo, antes de entrar en este tema, es necesario obtener información sobre los recursos. El término recursos usados en este contexto simplemente hace referencia a una manera de reutilizar los objetos y valores definidos normalmente. Veamos un ejemplo:
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<FlowPanel>
<FlowPanel.Resources>
<SolidColorBrush def:Name="MyColor" Color="Gold"/>
</FlowPanel.Resources>
<Button Background="{MyColor}"/>
<Ellipse Fill="{MyColor}"/>
</FlowPanel>
</Border>
Este código define un nuevo recurso denominado MyColor, cuyo tipo es SolidColorBrush y el valor es Gold. Este recurso forma parte de la colección Resources de FlowPanel. Cada elemento tiene una colección Resources . Puede definir recursos en cualquier elemento que desee, pero con más frecuencia los colocará solo en el elemento raíz, en este caso, flowPanel.
Una vez definido un recurso, puede hacer referencia al recurso en un valor de propiedad colocando el nombre del recurso entre llaves, como se muestra aquí:
<Button Background="{MyColor}"/>
Cuando el procesador XAML vea {MyColor} en este ejemplo, comprobará primero la colección Resources del botón. Dado que Button no tiene una definición de MyColor (su colección Resources está vacía), comprobará el elemento primario del botón, flowPanel.
Un tipo de recurso especialmente útil es un estilo. Style es el nombre de la clase y el nombre de una propiedad que tienen todos los elementos. Un estilo define las propiedades que se van a establecer en un elemento, que después usa ese estilo designado. En este ejemplo se define un estilo denominado MyStyle y se aplica ese estilo a un botón:
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<FlowPanel>
<FlowPanel.Resources>
<Style def:Name="MyStyle">
<Button Background="Red" FontSize="24"/>
</Style>
</FlowPanel.Resources>
<Button>Normal</Button>
<Button Style="{MyStyle}">Styled</Button>
</FlowPanel>
</Border>
También puede definir un recurso Style sin nombre, que se convierte en el estilo predeterminado del elemento para los elementos en los que no se especifica una propiedad Style explícita. En este ejemplo se agrega un estilo predeterminado al ejemplo anterior:
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<FlowPanel>
<FlowPanel.Resources>
<Style>
<Button Background="Green" FontSize="15"/>
</Style>
<Style def:Name="MyStyle">
<Button Background="Red" FontSize="24"/>
</Style>
</FlowPanel.Resources>
<Button>Normal</Button>
<Button Style="{MyStyle}">Styled</Button>
</FlowPanel>
</Border>
Puede realizar un tipo de herencia de estilo estableciendo la propiedad BasedOn de la clase Style . Al hacer referencia a la nueva clase Style , se establecerán todas las propiedades que hizo el estilo anterior, además de las propiedades adicionales que especifique. En el ejemplo siguiente se definen dos estilos: el primero establece la propiedad Background y la segunda, según la primera, establece la propiedad FontSize .
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<FlowPanel>
<FlowPanel.Resources>
<Style def:Name="Style1">
<Button Background="Red"/>
</Style>
<Style def:Name="Style2" BasedOn="{Style1}">
<Button FontSize="24"/>
</Style>
</FlowPanel.Resources>
<Button Style="{Style1}">Style 1</Button>
<Button Style="{Style2}">Style 2</Button>
</FlowPanel>
</Border>
Incluso es posible que un estilo establezca las propiedades condicionalmente mediante una característica conocida como desencadenadores de propiedades. Style tiene una propiedad denominada VisualTriggers, que es una colección de PropertyTriggers. Cada PropertyTrigger especifica una condición mediante las propiedades Property y Value , y contiene una colección de instrucciones Set . Cuando la propiedad del elemento con estilo coincide con ese valor, se aplican las instrucciones Set y, cuando la condición ya no es true, los valores no se aplican, como si nunca se hubieran establecido en primer lugar. En este ejemplo se usan desencadenadores de propiedad para que el botón sea verde cuando el mouse esté sobre el botón y, de lo contrario, rojo:
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<FlowPanel>
<FlowPanel.Resources>
<Style def:Name="Style1">
<Button Background="Red"/>
<Style.VisualTriggers>
<PropertyTrigger Property="IsMouseOver" Value="true">
<Set PropertyPath="Background" Value="Green"/>
</PropertyTrigger>
</Style.VisualTriggers>
</Style>
</FlowPanel.Resources>
<Button Style="{Style1}">Style 1</Button>
</FlowPanel>
</Border>
Muchos controles XAML usan la composición del control. Combinan una serie de controles más pequeños para crear un control más grande y complicado. Estilos incluso te permiten cambiar esto! Al especificar una composición diferente, puede redefinir completamente la apariencia de un control mientras mantiene su comportamiento.
Después de declarar el elemento de estilo y sus propiedades, la <etiqueta Style.VisualTree> especifica dentro del Style qué elementos se van a componer para crear el control más grande. Puede establecer las propiedades de los elementos secundarios como de costumbre y dar a esos elementos secundarios propios. También puede usar alias de propiedad para establecer valores de propiedad. Por ejemplo, Name1="*Alias(Target=Name2)" establecerá la propiedad Name1 del elemento secundario en la propiedad Name2 del control mayor. En el ejemplo siguiente se crea un estilo para Button que cambia la composición para lograr un aspecto redondo, como puede ver en la figura 3-12. Las propiedades Background y Content del botón se aliasan en los puntos adecuados del árbol visual.
<Border Background="white"
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition">
<FlowPanel>
<FlowPanel.Resources>
<Style def:Name="RoundButton">
<Button FontSize="20"/>
<Style.VisualTree>
<Canvas>
<Rectangle ID="MainRect"
RadiusX="10" RadiusY="10"
Fill="*Alias(Target=Background)"
Width="100%" Height="100%" />
<FlowPanel Width="100%" Height="100%" >
<ContentPresenter
ContentControl.Content="*Alias(Target = Content)"
Margin="15,3,15,5"/>
</FlowPanel>
</Canvas>
</Style.VisualTree>
</Style>
</FlowPanel.Resources>
<Button Style="{RoundButton}">
standard RoundButton
</Button>
<Button Background="red" Style="{RoundButton}">
red RoundButton
</Button>
<Button>
standard button
</Button>
<Button Background="red">
red standard button
</Button>
</FlowPanel>
</Border>
Figura 3-12. Un par de botones RoundButton y estándar en un FlowPanel
Gráficos y animaciones
XAML proporciona una amplia compatibilidad con las formas de dibujo, la transformación del estado de un objeto y la animación de casi cualquier propiedad de un objeto. Los elementos Shape se usan para dibujar, Transformar elementos para modificar una propiedad o un objeto, y elementos Animation para cambiar una propiedad de un objeto a lo largo del tiempo.
Formas
XAML proporciona un conjunto de elementos Shape para dibujar, que incluyen Ellipse, Line, Rectangle, Path, Polygon y Polyline. Una forma tiene un relleno, que es el color de fondo y un trazo, que es el color de contorno. Relleno y trazo predeterminado es transparente, así que asegúrese de establecer al menos uno de ellos. La propiedad StrokeWidth controla el grosor del contorno.
Las formas no pueden tener elementos secundarios. Normalmente se colocan formas dentro de un lienzo, por lo que la primera forma del marcado será la primera dibujada. En este ejemplo se muestran algunas de las formas básicas, que también puede ver en la figura 3-13:
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<Canvas Height="400" Width="400">
<Ellipse CenterX="70" CenterY="75"
RadiusX="30" RadiusY="50"
Fill="yellow" Stroke="red" StrokeThickness="15"/>
<Rectangle RectangleLeft="150" RectangleTop="20"
RectangleHeight="100" RectangleWidth="40"
Fill="lightBlue" Stroke="green"/>
<Line X1="20" Y1="220" X2="150" Y2="240"
Stroke="black" StrokeThickness="5"/>
<Polygon Points="220,140 270,240 170,240"
StrokeLineJoin="Round"
Stroke="black" StrokeThickness="20"/>
</Canvas>
</Border>
Figura 3-13. Varias formas en un lienzo
Hasta ahora, solo hemos usado colores sólidos con las propiedades Stroke y Fill . Pero en XAML, casi en cualquier lugar puedes usar un color que puedas especificar un pincel. SolidColorBrush es el tipo de pincel que hemos usado hasta ahora, pero XAML también admite ImageBrush, LinearGradientBrush y RadialGradientBrush. ImageBrush tiene una propiedad ImageSource que especifica el nombre del archivo de imagen. SolidColorBrush tiene una propiedad Color . LinearGradientBrush y RadialGradientBrush contienen una GradientStopCollection, que permite degradados muy complicados. En este ejemplo se definen cuatro pinceles como recursos y se usan como trazo y relleno de los puntos suspensivos. Puede ver cómo se ven en la figura 3-14.
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<Border.Resources>
<LinearGradientBrush def:Name="lineargradient" StartPoint="0,0"
EndPoint="1,1" >
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="Blue" Offset="0"/>
<GradientStop Color="white" Offset="1"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<RadialGradientBrush def:Name="radialgradient" Focus="0.3,0.3">
<RadialGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="red" Offset="0"/>
<GradientStop Color="yellow" Offset="1"/>
</GradientStopCollection>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
<ImageBrush def:Name="image" ImageSource="Tulip.jpg" TileMode="Tile"/>
<SolidColorBrush def:Name="solid" Color="gray"/>
</Border.Resources>
<Canvas Height="400" Width="400">
<Ellipse CenterX="100" CenterY="75"
RadiusX="90" RadiusY="50"
Fill="{lineargradient}" Stroke="{image}" StrokeThickness="15"/>
<Ellipse CenterX="300" CenterY="170"
RadiusX="50" RadiusY="150"
Fill="{radialgradient}" Stroke="{solid}" StrokeThickness="15"/>
</Canvas>
</Border>
Figura 3-14. Degradados en el trabajo
Transformaciones
XAML admite varios tipos de transformaciones. RotateTransform gira según la cantidad de la propiedad Angle . TranslateTransform mueve las cosas según las propiedades X e Y . ScaleTransform se reducirá o estirará según las propiedades ScaleX y ScaleY . SkewTransform slants cosas, usando las propiedades AngleX, AngleY y Center . MatrixTransform admite transformaciones afín arbitrarias. Por último, TransformCollection es una transformación que permite combinar varias transformaciones.
Algunas clases, como Brush, tienen una propiedad Transform . En otros casos, puede usar el elemento TransformDecorator , que tiene una propiedad Transform . TransformDecorator transformará su elemento secundario. (Al igual que Border, solo puede tener un elemento secundario). TransformDecorator puede contener cualquier tipo de elemento secundario, incluidas formas, paneles y controles. En este ejemplo se usa para TransformDecorators. La primera contiene una elipse y la gira 45 grados. El segundo TransformDecorator contiene un ListBox y gira y escala el ListBox. Puede ver el aspecto de las formas en la figura 3-15.
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<Canvas Height="400" Width="400">
<TransformDecorator Transform="rotate 45">
<Ellipse CenterX="100" CenterY="75"
RadiusX="90" RadiusY="50"
Fill="white" Stroke="black" StrokeThickness="15"/>
</TransformDecorator>
<TransformDecorator Canvas.Top="200" Canvas.Left="100">
<TransformDecorator.Transform>
<TransformCollection>
<RotateTransform Angle="135"/>
<ScaleTransform ScaleX="2" ScaleY="4"/>
</TransformCollection>
</TransformDecorator.Transform>
<ListBox >
<ListItem> ListItem 1 </ListItem>
<ListItem> ListItem 2 </ListItem>
<ListItem> ListItem 3 </ListItem>
</ListBox>
</TransformDecorator>
</Canvas>
</Border>
Figura 3-15. ListBox y Ellipse sesgados
Animaciones
XAML también admite animaciones. Puede animar casi todas las propiedades. Algunas propiedades tienen una propiedad "Animaciones" correspondiente, por ejemplo , RotateTransform.Angle y RotateTransform.AngleAnimations. En otros casos, puedes asignar una colección de animaciones a una propiedad mediante la sintaxis de propiedad compuesta. Por ejemplo, vea el código siguiente:
<Button>
<Button.Width>
… put animation collection here …
</Button.Width>
</Button>
Cada tipo de propiedad tiene una colección de animaciones independiente. El tipo de Button.Width es Length, por lo que uno usa LengthAnimationCollection. Del mismo modo, los propios objetos de animación son específicos del tipo de la propiedad que animas: LengthAnimationCollection contiene un conjunto de objetos LengthAnimation .
Los objetos de animación tienen una propiedad From y To , cuyos tipos coinciden con el tipo de la propiedad que se está animando. El objeto de animación también tiene las propiedades Begin, Duration y End , que se miden en segundos y controlan el tiempo de la animación. Begin también admite el valor Inmediato y Duration admite Indefinida. Puedes usar las propiedades RepeatCount y RepeatDuration para repetir la animación automáticamente. La propiedad Fill especifica lo que sucede con la propiedad después de que se supere la animación. Fill="Hold" es uno de los valores más importantes; mantiene la propiedad en el valor end de animación.
Las clases de animación no forman parte del espacio de nombres XAML predeterminado, por lo que tendrás que usar ?< La asignación> y xmlns crea para cargar el espacio de nombres MSAvalon.Windows.Media.Animation. Dado que este espacio de nombres contiene clases de varios archivos DLL, necesitará un elemento independiente<? Asignación> y xmlns para cada DLL.
En el ejemplo siguiente se animan dos propiedades, la propiedad RotateTransform.Angle y la propiedad Button.Width , que usan clases de ambos espacios de nombres de animación. En la figura 3-16 se muestra el botón en momentos diferentes.
<?Mapping XmlNamespace="animC" ClrNamespace="MSAvalon.Windows.Media.Animation"
Assembly="PresentationCore" ?>
<?Mapping XmlNamespace="animF" ClrNamespace="MSAvalon.Windows.Media.Animation"
Assembly="PresentationFramework" ?>
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:animC="animC"
xmlns:animF="animF"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<Canvas Height="400" Width="400">
<TransformDecorator Canvas.Top="200" Canvas.Left="100">
<TransformDecorator.Transform>
<TransformCollection>
<RotateTransform Angle="135">
<RotateTransform.AngleAnimations>
<animC:DoubleAnimationCollection>
<animC:DoubleAnimation From="0" To="360" Duration="4"
AutoReverse="True"
RepeatDuration="Indefinite"/>
</animC:DoubleAnimationCollection>
</RotateTransform.AngleAnimations>
</RotateTransform>
</TransformCollection>
</TransformDecorator.Transform>
<ListBox >
<ListItem> ListItem 1 </ListItem>
<ListItem> ListItem 2 </ListItem>
<ListItem> ListItem 3 </ListItem>
</ListBox>
</TransformDecorator>
<Button Width="40" Canvas.Top="10" Canvas.Left="10">
<Button.Width>
<animF:LengthAnimationCollection>
<animF:LengthAnimation From="40" To="300"
AutoReverse="true" Begin="1" Duration="1.2"
RepeatDuration="Indefinite"/>
</animF:LengthAnimationCollection>
</Button.Width>
Button
</Button>
</Canvas>
</Border>
Figura 3-16. Vistas del botón animado en momentos diferentes
Servicios de documentos
La plataforma Longhorn proporciona amplios servicios que admiten una mejor experiencia de visualización de documentos en línea. Hay dos servicios principales: un control diseñado para ver, paginar y navegar por el contenido de un documento y servicios de diseño diseñados para mejorar la experiencia de lectura.
PageViewer Control
Use el control PageViewer cuando desee mostrar un documento al usuario para su visualización en línea. El control PageViewer proporciona funcionalidad de navegación de página y paginación. El control da formato automáticamente al contenido del documento en páginas independientes. El usuario puede navegar directamente a diferentes páginas mediante los controles proporcionados por el visor de páginas.
Paginación y navegación
Tradicionalmente, el contenido en línea, como las páginas web, era continuo. Una interfaz de usuario proporciona barras de desplazamiento para permitirle ver el contenido que no cabe en el área visible. En efecto, "desplazaría" la ventana de vista a la posición del documento que desea ver.
Con la paginación, divide el contenido del documento en una o varias páginas individuales, de forma similar a un libro. La plataforma Longhorn proporciona compatibilidad con el contenido paginado mediante la inclusión de varios controles que le ayudan a mostrar y navegar por el contenido que se muestra como páginas discretas. Además, Longhorn proporciona una interfaz de programación de aplicaciones de paginación (API) para ampliar estas funcionalidades y proporcionar compatibilidad con la paginación enriquecida para aplicaciones de paginación personalizadas.
El control PageViewer es realmente un control complejo creado a partir de controles más pequeños mediante técnicas de composición de control que he descrito anteriormente. El control PageViewer usa los controles PageSource y PageElement para proporcionar su funcionalidad de paginación. El control PageSource interrumpe y da formato al contenido entre páginas. El control PageElement representa una sola página. El control PageViewer también usa el control PageBar para permitirle navegar por las páginas.
El uso del control PageViewer es muy sencillo. Para mostrar un documento conocido, puede usarlo como se muestra en el código siguiente. Por supuesto, puede enlazar controladores de eventos y cambiar el documento de origen para que el visor de páginas muestre documentos diferentes.
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<PageViewer Source="AuthorsandPublishers.xaml" />
</Border>
En la figura 3-17 se muestra el visor de páginas hospedado en una ventana del explorador que muestra su documento. Anote los controles de navegación de página en la parte superior del documento.
Figura 3-17. Control PageViewer
Servicios de diseño de documentos
Longhorn también proporciona servicios de diseño de documentos diseñados para mejorar la experiencia de lectura. Longhorn contiene compatibilidad con dos nuevos tipos de documentos:
- Documentos de flujo adaptable
- Documentos de diseño corregidos
Estos nuevos formatos de documento permiten a los desarrolladores proporcionar a los usuarios de sus aplicaciones una mejor experiencia de lectura de documentos.
Los documentos de flujo adaptable usan elementos de marcado especializados que declaran que un documento debe ser Adaptable. Longhorn optimiza automáticamente un documento adaptable para usar mejor el espacio de pantalla disponible y proporciona la mejor experiencia de lectura para el usuario en función de las funcionalidades o limitaciones de su sistema.
Por ejemplo, el usuario podría tener una de las pantallas de pantalla ancha de relación de aspecto de 16 por 9 introducidas recientemente. Es muy difícil leer una línea de texto que abarca una línea horizontal larga. Dependiendo del ancho de la ventana, un documento adaptable podría dividir el texto en dos, tres o más columnas, lo que reduce el esfuerzo de un usuario para examinar una línea de texto.
En otro ejemplo, un documento podría contener una imagen y un texto que fluye alrededor de la imagen. A medida que se reduce el tamaño de la ventana del documento en un documento no adaptativo, la imagen sigue siendo un tamaño fijo y se ve menos y menos del texto. Un documento adaptable podría reducir la imagen cuando determina que el texto no es suficiente visible en la ventana. Esto permite al lector seguir teniendo una idea general de lo que representa la imagen, pero seguir leyendo el texto en el contexto de la imagen. En una ventana más pequeña, es probable que cada píxel de una imagen sea menos importante y útil para el lector que poder leer más texto. Una alternativa, como separar la imagen y el texto circundante en páginas independientes, derrota la intención del autor del documento, que era presentar el texto y la imagen juntos en contexto.
Los documentos de diseño fijos aparecen igual cada vez, independientemente del tamaño de pantalla, el tamaño de la ventana o el dispositivo de salida del visor. Puede crear un documento de diseño fijo mediante elementos de marcado especializados o mediante la impresión de un documento mediante un controlador de impresora de Gráficos vectoriales de Microsoft Windows (WVG).
Documentos de diseño adaptable
En un documento de diseño adaptable, se proporcionan preferencias clave en el marcado de nivel de raíz. A continuación, Longhorn puede representar el documento de una manera que hace el mejor uso del área de la ventana y mejora su legibilidad. Longhorn determina automáticamente el ancho óptimo y el número de columnas de una página, tamaños ideales para todos los elementos de texto, tamaños y posiciones óptimos para todas las figuras, y los anchos de márgenes y márgenes para dar la mejor presentación general del contenido.
Generar un documento de diseño adaptable
Para crear un documento de diseño adaptable, use marcado declarativo similar al siguiente:
<Border
xmlns="https://schemas.microsoft.com/2003/xaml"
xmlns:def="Definition"
Background="BlanchedAlmond"
>
<AdaptiveMetricsContext ColumnPreference="Medium"
FontFamily="Arial">
<TextPanel Background="white">
<Section>
<Heading OutlineLevel="1">Adaptive Layout Example</Heading>
<Paragraph>
This example shows the advanced capabilities of Adaptive Flow
Layout. Lorem ipsum dolor sit amet, consectetuer adipiscing
elit, sed diam nonummy nibh euismod tin cidunt ut laoreet dolore
magna aliquam erat volutpat. Ut wisi enim ad minim veni am, quis
nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip
ex ea commodo consequat. Duis autem vel eum iriure.</Paragraph>
<Paragraph>
<Image TextPanel.FlowBehavior="Figure" Source="picture1.jpg"
TextPanel.Emphasis="Medium" />
Notice how images and text are flowed intelligently to enhance the
reading experi ence. Lorem ipsum dolor sit amet, consectetuer
adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet
dolore magna aliquam erat volutpat. Ut wisi e nim ad minim veniam,
quis nostrud exerci tation ullamcorper suscipit lobortis ni sl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure.
</Paragraph>
<Paragraph>Adaptive layout is an exciting new feature of Longhorn.
<Image TextPanel.FlowBehavior="Figure" Source="picture2.jpg"
TextPanel.Emphasis="Low" />
Lorem ipsum dolor sit amet, consectetuer
adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet
dolore magna aliquam erat volutpat. Ut wisi e nim ad minim veniam,
quis nostrud exerci tation ullamcorper suscipit lobortis ni sl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure.
</Paragraph>
</Section>
</TextPanel>
</AdaptiveMetricsContext>
</Border>
documentos de Fixed-Layout
Use un documento de diseño fijo para presentar el contenido del documento exactamente en el mismo diseño y formato, independientemente del software de la aplicación, el hardware y el sistema operativo utilizados. Además, un documento de diseño fijo se representa de forma idéntica en todos los dispositivos de salida. Un documento de diseño fijo es un conjunto de objetos que describen colectivamente la apariencia de una o varias páginas.
Generar un documento de Fixed-Layout
Puede usar dos técnicas diferentes para generar un documento de diseño fijo:
- Imprimir un documento sin marcado en un archivo mediante el controlador de impresora Longhorn
- Escribir un documento de diseño fijo mediante XAML
Al imprimir un documento con la mayoría de las aplicaciones de Microsoft Win32 (por ejemplo, Microsoft Office) mediante el controlador de impresora Longhorn, el controlador de impresora creará un archivo XAML que contiene marcado para paginar y colocar cada carácter, imagen o gráfico vectorial en el documento impreso.
Puede optar por generar el documento como un archivo de marcado directamente o para incluir el archivo de marcado dentro de un contenedor. Al seleccionar la salida del contenedor, también puede aplicar derechos digitales y protección de documentos al documento.
Como alternativa, puedes crear XAML mediante un editor. A continuación se muestra un ejemplo esquelético del documento de diseño fijo:
<FixedPanel xmlns="https://schemas.microsoft.com/2003/xaml/" >
<FixedPage Width="8.50in" Height="11.00in"> <!-- PAGE 1 -->
<Text FontFamily="Arial" FontSize="8.4" FixedPage.Left="1.250in"
FixedPage.Top="0.530in" FontWeight="Bold">1.</Text>
<Text FontFamily="Arial" FixedPage.Left="1.350in" FixedPage.Top="0.500in"
FontWeight="Bold" FontSize="12">Fixed Document</Text>
</FixedPage>
<FixedPage>
<Text>This is page 2</Text>
</FixedPage>
<FixedPage>
<Text>This is page 3</Text>
</FixedPage>
</FixedPanel>
Resumen
Los paneles permiten dividir la superficie de presentación en áreas con diferentes características de diseño. Tiene una gran variedad de controles que puede usar para rellenar los paneles de una pantalla. Las formas, las transformaciones y las animaciones permiten generar una salida gráfica dinámica. Mediante la composición del control, puede combinar estas características para producir prácticamente cualquier interfaz de usuario que desee. Puede generar documentos adaptables que diseñan el contenido de forma inteligente y facilitan la lectura del lector. Como alternativa, puede colocar con precisión cada elemento único en una página y controlar la paginación explícitamente para generar un documento que aparezca exactamente como desee, independientemente del dispositivo de salida. Además, puedes hacerlo mediante declaración mediante XAML. ¡Esto seguro que es una paliza escribiendo un controlador de mensajes WM_PAINT!