Información general sobre documentos dinámicos
Los documentos dinámicos se han diseñado para optimizar su presentación y legibilidad. En lugar de establecerse en un diseño predefinido, este tipo de documentos ajusta y recoloca dinámicamente su contenido basándose en variables de tiempo de ejecución, tales como el tamaño de la ventana, la resolución del dispositivo y las preferencias opcionales del usuario. Además, ofrecen características de documentos avanzadas, como la paginación y las columnas. En este tema se ofrece información general sobre los documentos dinámicos y sobre cómo crearlos.
Este tema contiene las secciones siguientes.
- Qué es un documento dinámico
- Tipos de documentos dinámicos
- Crear contenido dinámico
- Clases relacionadas con el contenido dinámico
- Esquema de contenido
- Personalizar el texto
- Temas relacionados
Qué es un documento dinámico
Un documento dinámico está diseñado para "recolocar el contenido" dependiendo del tamaño de la ventana, la resolución del dispositivo y otras variables de entorno. Además, los documentos dinámicos tienen varias características integradas que incluyen la búsqueda, modos de presentación que optimizan la legibilidad y la capacidad de cambiar el tamaño y la apariencia de las fuentes. Este tipo de documentos son óptimos para su uso cuando la facilidad de lectura constituye el principal escenario de consumo del documento. En cambio, los documentos fijos están diseñados para tener una presentación estática. Los documentos fijos son útiles cuando la fidelidad del contenido de origen resulta esencial. Vea Documentos en WPF para obtener más información sobre los distintos tipos de documentos.
La ilustración siguiente muestra un documento dinámico de ejemplo visualizado en varias ventanas de tamaños diferentes. A medida que el área de presentación cambia, el contenido se recoloca para utilizar el espacio disponible del mejor modo posible.
Tal y como se muestra en la imagen anterior, el contenido dinámico puede incluir muchos componentes, entre los que se incluyen párrafos, listas, imágenes, etc. Estos componentes corresponden a elementos de marcado y a objetos del código de procedimientos. Analizaremos estas clases detalladamente más adelante en la sección Clases relacionadas con el flujo de esta introducción. De momento, aquí tiene un ejemplo de código simple que crea un documento dinámico compuesto por un párrafo con texto en negrita y una lista.
<!-- This simple flow document includes a paragraph with some
bold text in it and a list. -->
<FlowDocumentReader xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<FlowDocument>
<Paragraph>
<Bold>Some bold text in the paragraph.</Bold>
Some text that is not bold.
</Paragraph>
<List>
<ListItem>
<Paragraph>ListItem 1</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 2</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 3</Paragraph>
</ListItem>
</List>
</FlowDocument>
</FlowDocumentReader>
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents
Namespace SDKSample
Partial Public Class SimpleFlowExample
Inherits Page
Public Sub New()
Dim myParagraph As New Paragraph()
' Add some Bold text to the paragraph
myParagraph.Inlines.Add(New Bold(New Run("Some bold text in the paragraph.")))
' Add some plain text to the paragraph
myParagraph.Inlines.Add(New Run(" Some text that is not bold."))
' Create a List and populate with three list items.
Dim myList As New List()
' First create paragraphs to go into the list item.
Dim paragraphListItem1 As New Paragraph(New Run("ListItem 1"))
Dim paragraphListItem2 As New Paragraph(New Run("ListItem 2"))
Dim paragraphListItem3 As New Paragraph(New Run("ListItem 3"))
' Add ListItems with paragraphs in them.
myList.ListItems.Add(New ListItem(paragraphListItem1))
myList.ListItems.Add(New ListItem(paragraphListItem2))
myList.ListItems.Add(New ListItem(paragraphListItem3))
' Create a FlowDocument with the paragraph and list.
Dim myFlowDocument As New FlowDocument()
myFlowDocument.Blocks.Add(myParagraph)
myFlowDocument.Blocks.Add(myList)
' Add the FlowDocument to a FlowDocumentReader Control
Dim myFlowDocumentReader As New FlowDocumentReader()
myFlowDocumentReader.Document = myFlowDocument
Me.Content = myFlowDocumentReader
End Sub
End Class
End Namespace
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
namespace SDKSample
{
public partial class SimpleFlowExample : Page
{
public SimpleFlowExample()
{
Paragraph myParagraph = new Paragraph();
// Add some Bold text to the paragraph
myParagraph.Inlines.Add(new Bold(new Run("Some bold text in the paragraph.")));
// Add some plain text to the paragraph
myParagraph.Inlines.Add(new Run(" Some text that is not bold."));
// Create a List and populate with three list items.
List myList = new List();
// First create paragraphs to go into the list item.
Paragraph paragraphListItem1 = new Paragraph(new Run("ListItem 1"));
Paragraph paragraphListItem2 = new Paragraph(new Run("ListItem 2"));
Paragraph paragraphListItem3 = new Paragraph(new Run("ListItem 3"));
// Add ListItems with paragraphs in them.
myList.ListItems.Add(new ListItem(paragraphListItem1));
myList.ListItems.Add(new ListItem(paragraphListItem2));
myList.ListItems.Add(new ListItem(paragraphListItem3));
// Create a FlowDocument with the paragraph and list.
FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);
myFlowDocument.Blocks.Add(myList);
// Add the FlowDocument to a FlowDocumentReader Control
FlowDocumentReader myFlowDocumentReader = new FlowDocumentReader();
myFlowDocumentReader.Document = myFlowDocument;
this.Content = myFlowDocumentReader;
}
}
}
La ilustración siguiente muestra la apariencia de este fragmento de código.
En este ejemplo, el control FlowDocumentReader se utiliza para hospedar el contenido dinámico. Vea Tipos de documentos dinámicos para obtener más información sobre los controles que hospedan contenido dinámico. Los elementos Paragraph, List, ListItem y Bold se utilizan para controlar el formato del contenido, basándose en su orden en el marcado. Por ejemplo, el elemento Bold abarca sólo una parte del texto del párrafo; como resultado, sólo ese fragmento de texto está en negrita. Si ha utilizado HTML, esto le resultará familiar.
Tal y como se muestra en la ilustración anterior, los documentos dinámicos tienen varias características integradas:
Búsqueda: permite al usuario realizar una búsqueda de texto completo en un documento.
Modo de visualización: el usuario puede elegir su modo de visualización preferido, incluyendo el modo de visualización de una sola página (una página a la vez), de dos páginas a la vez (formato de lectura de libro) y de desplazamiento continuo (sin límite). Para obtener más información sobre estos modos de visualización, consulte FlowDocumentReaderViewingMode.
Controles de navegación de páginas: si el modo de visualización del documento utiliza páginas, los controles de navegación de páginas incluyen un botón que permite saltar a la página siguiente (flecha abajo) o a la página anterior (flecha arriba), así como indicadores del número de página actual y el número total de páginas. También es posible pasar las páginas utilizando las teclas de dirección del teclado.
Zoom: los controles de zoom permiten al usuario aumentar o reducir el nivel de zoom haciendo clic en los botones con el signo más y el signo menos, respectivamente. Los controles de zoom incluyen también un control deslizante para ajustar el nivel de zoom. Para obtener más información, vea Zoom.
Estas características se pueden modificar dependiendo del control utilizado para hospedar el contenido dinámico. En la sección siguiente se describen los distintos controles.
Tipos de documentos dinámicos
La presentación y la apariencia del contenido en los documentos dinámicos dependerán del objeto utilizado para hospedar el contenido dinámico. Hay cuatro controles que permiten la visualización del contenido dinámico: FlowDocumentReader, FlowDocumentPageViewer, RichTextBox y FlowDocumentScrollViewer. Estos controles se describen brevemente a continuación.
Nota: es necesario que FlowDocument hospede directamente el contenido dinámico, por lo que todos estos controles utilizan un objeto FlowDocument para habilitar el hospedaje de dicho contenido.
FlowDocumentReader
FlowDocumentReader dispone de características que permiten al usuario seleccionar dinámicamente distintos modos de visualización, incluido el modo de visualización de una sola página (una página a la vez), dos páginas a la vez (formato de lectura de libro) y desplazamiento continuo (sin límite). Para obtener más información sobre estos modos de visualización, vea FlowDocumentReaderViewingMode. Si no necesita la capacidad de cambiar dinámicamente entre distintos modos de visualización, FlowDocumentPageViewer y FlowDocumentScrollViewer proporcionan visores de contenido dinámico más ligeros que son fijos para un modo de visualización concreto.
FlowDocumentPageViewer y FlowDocumentScrollViewer
FlowDocumentPageViewer muestra el contenido en el modo de visualización de una sola página, mientras que FlowDocumentScrollViewer muestra el contenido en modo de desplazamiento continuo. Tanto FlowDocumentPageViewer como FlowDocumentScrollViewer son fijos para un modo de visualización concreto. Puede compararlos con FlowDocumentReader, que incluye características que permiten al usuario elegir dinámicamente entre varios modos de visualización (suministrados por la enumeración FlowDocumentReaderViewingMode), a costa de exigir un uso más intensivo de recursos que FlowDocumentPageViewer o FlowDocumentScrollViewer.
De manera predeterminada, se muestra siempre una barra de desplazamiento vertical y la barra de desplazamiento horizontal se vuelve visible cuando es necesario. La interfaz de usuario predeterminada para FlowDocumentScrollViewer no incluye barra de herramientas; sin embargo, se puede utilizar la propiedad IsToolBarVisible para habilitar una barra de herramientas integrada.
RichTextBox
Utilice un control RichTextBox si desea que el usuario pueda editar el contenido dinámico. Por ejemplo, si desea crear un editor que le permita al usuario manipular elementos como tablas, formatos de cursiva y negrita, etc., utilice RichTextBox. Vea Información general sobre el control RichTextBox para obtener más información.
Nota: el contenido dinámico existente dentro de un control RichTextBox no se comporta exactamente como el contenido dinámico incluido en otros controles. Por ejemplo, en RichTextBox no hay ninguna columna, por lo que no existe un comportamiento de cambio de tamaño automático. Además, las características normalmente integradas de contenido dinámico como la búsqueda, el modo de visualización, la navegación de páginas y el zoom no están disponibles dentro de un elemento RichTextBox.
Crear contenido dinámico
El contenido dinámico puede ser complejo, estando compuesto por varios elementos como texto, imágenes, tablas e incluso clases derivadas de UIElement como los controles. Los puntos siguientes resultan esenciales para entender cómo se crea el contenido de flujo dinámico:
Clases relacionadas con el flujo: cada una de las clases utilizadas en el contenido dinámico tiene un propósito concreto. Además, la relación jerárquica entre las clases dinámicas le ayuda a entender cómo se utilizan. Por ejemplo, las clases derivadas de la clase Block se utilizan para contener otros objetos, mientras que las clases derivadas de Inline contienen objetos que se muestran.
Esquema de contenido: un documento dinámico puede requerir un número sustancial de elementos anidados. El esquema de contenido especifica las posibles relaciones de elemento primario/secundario entre los elementos.
Las secciones siguientes analizarán con más detalle cada una de estas áreas.
Clases relacionadas con el contenido dinámico
El diagrama siguiente muestra los objetos más utilizados con el contenido dinámico:
En lo que al contenido dinámico se refiere, hay dos categorías importantes:
Clases derivadas de bloque: también denominadas "elementos de contenido de bloque" o simplemente "elementos de bloque". Los elementos que heredan de la clase Block se pueden utilizar para agrupar elementos bajo un elemento primario común o para aplicar atributos comunes a un grupo.
Clases derivadas inline: también denominadas "elementos de contenido inline " o simplemente "elementos inline". Los elementos que heredan de Inline están incluidos dentro de un elemento de bloque o de otro elemento inline. Los elementos inline se utilizan a menudo como contenedor directo del contenido que se representa en la pantalla. Por ejemplo, un elemento Paragraph (elemento de bloque) puede contener un elemento Run (elemento inline), pero es Run el que contiene en realidad el texto que se representa en la pantalla.
A continuación se describe brevemente cada una de las clases de estas dos categorías.
Clases derivadas de bloque
Paragraph
Paragraph se utiliza normalmente para agrupar el contenido en un párrafo. El uso más sencillo y común de Paragraph es crear un párrafo de texto.
<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<Paragraph>
Some paragraph text.
</Paragraph>
</FlowDocument>
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents
Namespace SDKSample
Partial Public Class ParagraphExample
Inherits Page
Public Sub New()
' Create paragraph with some text.
Dim myParagraph As New Paragraph()
myParagraph.Inlines.Add(New Run("Some paragraph text."))
' Create a FlowDocument and add the paragraph to it.
Dim myFlowDocument As New FlowDocument()
myFlowDocument.Blocks.Add(myParagraph)
Me.Content = myFlowDocument
End Sub
End Class
End Namespace
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
namespace SDKSample
{
public partial class ParagraphExample : Page
{
public ParagraphExample()
{
// Create paragraph with some text.
Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add(new Run("Some paragraph text."));
// Create a FlowDocument and add the paragraph to it.
FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);
this.Content = myFlowDocument;
}
}
}
Sin embargo, también puede contener otros elementos inline derivados, como comprobará a continuación.
Sección
Section sólo se utiliza para contener otros elementos derivados de Block. No aplica ningún formato predeterminado a los elementos que contiene. Sin embargo, cualquier conjunto de valores establecidos en un elemento Section se aplica a sus elementos secundarios. Asimismo, una sección le permite recorrer en iteración mediante programación su colección secundaria. Section se utiliza de una manera similar a la etiqueta <DIV> en HTML.
En el ejemplo siguiente, se definen tres párrafos debajo de un elemento Section. La sección tiene un valor de propiedad Background de Rojo, por lo que el color de fondo del párrafo también es rojo.
<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<!-- By default, Section applies no formatting to elements contained
within it. However, in this example, the section has a Background
property value of "Red", therefore, the three paragraphs (the block)
inside the section also have a red background. -->
<Section Background="Red">
<Paragraph>
Paragraph 1
</Paragraph>
<Paragraph>
Paragraph 2
</Paragraph>
<Paragraph>
Paragraph 3
</Paragraph>
</Section>
</FlowDocument>
Imports System
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows.Documents
Namespace SDKSample
Partial Public Class SectionExample
Inherits Page
Public Sub New()
' Create three paragraphs
Dim myParagraph1 As New Paragraph(New Run("Paragraph 1"))
Dim myParagraph2 As New Paragraph(New Run("Paragraph 2"))
Dim myParagraph3 As New Paragraph(New Run("Paragraph 3"))
' Create a Section and add the three paragraphs to it.
Dim mySection As New Section()
mySection.Background = Brushes.Red
mySection.Blocks.Add(myParagraph1)
mySection.Blocks.Add(myParagraph2)
mySection.Blocks.Add(myParagraph3)
' Create a FlowDocument and add the section to it.
Dim myFlowDocument As New FlowDocument()
myFlowDocument.Blocks.Add(mySection)
Me.Content = myFlowDocument
End Sub
End Class
End Namespace
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;
namespace SDKSample
{
public partial class SectionExample : Page
{
public SectionExample()
{
// Create three paragraphs
Paragraph myParagraph1 = new Paragraph(new Run("Paragraph 1"));
Paragraph myParagraph2 = new Paragraph(new Run("Paragraph 2"));
Paragraph myParagraph3 = new Paragraph(new Run("Paragraph 3"));
// Create a Section and add the three paragraphs to it.
Section mySection = new Section();
mySection.Background = Brushes.Red;
mySection.Blocks.Add(myParagraph1);
mySection.Blocks.Add(myParagraph2);
mySection.Blocks.Add(myParagraph3);
// Create a FlowDocument and add the section to it.
FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(mySection);
this.Content = myFlowDocument;
}
}
}
BlockUIContainer
BlockUIContainer permite incrustar elementos UIElement (por ejemplo, un control Button) en contenido dinámico derivado de bloque. InlineUIContainer (vea a continuación) se utiliza para incrustar elementos UIElement en contenido dinámico derivado insertado. BlockUIContainer y InlineUIContainer son importantes porque no hay ninguna otra manera de utilizar un elemento UIElement en el contenido dinámico a menos que esté incluido en uno de estos dos elementos.
El ejemplo siguiente muestra cómo utilizar el elemento BlockUIContainer para hospedar los objetos UIElement dentro del contenido dinámico.
<FlowDocument ColumnWidth="400">
<Section Background="GhostWhite">
<Paragraph>
A UIElement element may be embedded directly in flow content
by enclosing it in a BlockUIContainer element.
</Paragraph>
<BlockUIContainer>
<Button>Click me!</Button>
</BlockUIContainer>
<Paragraph>
The BlockUIContainer element may host no more than one top-level
UIElement. However, other UIElements may be nested within the
UIElement contained by an BlockUIContainer element. For example,
a StackPanel can be used to host multiple UIElement elements within
a BlockUIContainer element.
</Paragraph>
<BlockUIContainer>
<StackPanel>
<Label Foreground="Blue">Choose a value:</Label>
<ComboBox>
<ComboBoxItem IsSelected="True">a</ComboBoxItem>
<ComboBoxItem>b</ComboBoxItem>
<ComboBoxItem>c</ComboBoxItem>
</ComboBox>
<Label Foreground ="Red">Choose a value:</Label>
<StackPanel>
<RadioButton>x</RadioButton>
<RadioButton>y</RadioButton>
<RadioButton>z</RadioButton>
</StackPanel>
<Label>Enter a value:</Label>
<TextBox>
A text editor embedded in flow content.
</TextBox>
</StackPanel>
</BlockUIContainer>
</Section>
</FlowDocument>
En la ilustración siguiente se muestra cómo se representa este ejemplo.
List
List se utiliza para crear una lista con viñetas o numérica. Establezca la propiedad MarkerStyle en un valor de enumeración TextMarkerStyle para determinar el estilo de la lista. En el siguiente ejemplo se muestra cómo crear una lista sencilla.
<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<List>
<ListItem>
<Paragraph>
List Item 1
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
List Item 2
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
List Item 3
</Paragraph>
</ListItem>
</List>
</FlowDocument>
Imports System
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows.Documents
Namespace SDKSample
Partial Public Class ListExample
Inherits Page
Public Sub New()
' Create three paragraphs
Dim myParagraph1 As New Paragraph(New Run("List Item 1"))
Dim myParagraph2 As New Paragraph(New Run("List Item 2"))
Dim myParagraph3 As New Paragraph(New Run("List Item 3"))
' Create the ListItem elements for the List and add the
' paragraphs to them.
Dim myListItem1 As New ListItem()
myListItem1.Blocks.Add(myParagraph1)
Dim myListItem2 As New ListItem()
myListItem2.Blocks.Add(myParagraph2)
Dim myListItem3 As New ListItem()
myListItem3.Blocks.Add(myParagraph3)
' Create a List and add the three ListItems to it.
Dim myList As New List()
myList.ListItems.Add(myListItem1)
myList.ListItems.Add(myListItem2)
myList.ListItems.Add(myListItem3)
' Create a FlowDocument and add the section to it.
Dim myFlowDocument As New FlowDocument()
myFlowDocument.Blocks.Add(myList)
Me.Content = myFlowDocument
End Sub
End Class
End Namespace
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;
namespace SDKSample
{
public partial class ListExample : Page
{
public ListExample()
{
// Create three paragraphs
Paragraph myParagraph1 = new Paragraph(new Run("List Item 1"));
Paragraph myParagraph2 = new Paragraph(new Run("List Item 2"));
Paragraph myParagraph3 = new Paragraph(new Run("List Item 3"));
// Create the ListItem elements for the List and add the
// paragraphs to them.
ListItem myListItem1 = new ListItem();
myListItem1.Blocks.Add(myParagraph1);
ListItem myListItem2 = new ListItem();
myListItem2.Blocks.Add(myParagraph2);
ListItem myListItem3 = new ListItem();
myListItem3.Blocks.Add(myParagraph3);
// Create a List and add the three ListItems to it.
List myList = new List();
myList.ListItems.Add(myListItem1);
myList.ListItems.Add(myListItem2);
myList.ListItems.Add(myListItem3);
// Create a FlowDocument and add the section to it.
FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myList);
this.Content = myFlowDocument;
}
}
}
Nota:List es el único elemento dinámico que utiliza ListItemCollection para administrar los elementos secundarios.
Tabla
Table se utiliza para crear una tabla. Table es similar al elemento Grid pero tiene más funciones y, por consiguiente, requiere mayor consumo de recursos. Dado que Grid es un elemento UIElement, no se puede utilizar en el contenido dinámico a menos que esté incluido en un elemento BlockUIContainer o InlineUIContainer. Para obtener más información sobre Table, vea Información general sobre tablas.
Clases derivadas inline
Run
Run se utiliza para contener texto sin formato. Los objetos Run se usarán ampliamente en contenido de flujo. Sin embargo, en marcado, no es obligatorio usar los elementos Run explícitamente. El uso de Run es obligatorio cuando se crean o manipulan documentos dinámicos mediante código. Por ejemplo, en el marcado siguiente, el primer elemento Paragraph especifica explícitamente el elemento Run, mientras que el segundo no lo hace. Ambos párrafos generan el mismo resultado.
<Paragraph>
<Run>Paragraph that explicitly uses the Run element.</Run>
</Paragraph>
<Paragraph>
This Paragraph omits the the Run element in markup. It renders
the same as a Paragraph with Run used explicitly.
</Paragraph>
Nota: A partir de .NET Framework 4, la propiedad Text del objeto Run es una propiedad de dependencia. Puede enlazar la propiedad Text a un origen de datos como TextBlock. La propiedad Text admite el enlace unidireccional totalmente. La propiedad Text también admite el enlace bidireccional, salvo para RichTextBox. Para obtener un ejemplo, vea Run.Text.
Span
Span agrupa otros elementos de contenido alineados. No se aplica ninguna representación inherente al contenido dentro de un elemento Span. Sin embargo, los elementos que heredan de Span, incluyendo Hyperlink, Bold, Italic y Underline, aplican formato al texto.
A continuación se muestra un ejemplo de un objeto Span utilizado para incluir contenido inline, incluyendo texto, un elemento Bold y un elemento Button.
<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<Paragraph>
Text before the Span. <Span Background="Red">Text within the Span is
red and <Bold>this text is inside the Span-derived element Bold.</Bold>
A Span can contain more then text, it can contain any inline content. For
example, it can contain a
<InlineUIContainer>
<Button>Button</Button>
</InlineUIContainer>
or other UIElement, a Floater, a Figure, etc.</Span>
</Paragraph>
</FlowDocument>
La captura de pantalla siguiente muestra cómo se representa este ejemplo.
InlineUIContainer
InlineUIContainer permite incrustar elementos UIElement (por ejemplo, un control como Button) en un elemento de contenido Inline. Este elemento es el equivalente inline al elemento BlockUIContainer descrito anteriormente. A continuación se muestra un ejemplo que utiliza InlineUIContainer para insertar un control Button inline en un elemento Paragraph.
<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<Paragraph>
Text to precede the button...
<!-- Set the BaselineAlignment property to "Bottom"
so that the Button aligns properly with the text. -->
<InlineUIContainer BaselineAlignment="Bottom">
<Button>Button</Button>
</InlineUIContainer>
Text to follow the button...
</Paragraph>
</FlowDocument>
Imports System
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows.Documents
Namespace SDKSample
Partial Public Class InlineUIContainerExample
Inherits Page
Public Sub New()
Dim run1 As New Run(" Text to precede the button... ")
Dim run2 As New Run(" Text to follow the button... ")
' Create a new button to be hosted in the paragraph.
Dim myButton As New Button()
myButton.Content = "Click me!"
' Create a new InlineUIContainer to contain the Button.
Dim myInlineUIContainer As New InlineUIContainer()
' Set the BaselineAlignment property to "Bottom" so that the
' Button aligns properly with the text.
myInlineUIContainer.BaselineAlignment = BaselineAlignment.Bottom
' Asign the button as the UI container's child.
myInlineUIContainer.Child = myButton
' Create the paragraph and add content to it.
Dim myParagraph As New Paragraph()
myParagraph.Inlines.Add(run1)
myParagraph.Inlines.Add(myInlineUIContainer)
myParagraph.Inlines.Add(run2)
' Create a FlowDocument and add the paragraph to it.
Dim myFlowDocument As New FlowDocument()
myFlowDocument.Blocks.Add(myParagraph)
Me.Content = myFlowDocument
End Sub
End Class
End Namespace
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;
namespace SDKSample
{
public partial class InlineUIContainerExample : Page
{
public InlineUIContainerExample()
{
Run run1 = new Run(" Text to precede the button... ");
Run run2 = new Run(" Text to follow the button... ");
// Create a new button to be hosted in the paragraph.
Button myButton = new Button();
myButton.Content = "Click me!";
// Create a new InlineUIContainer to contain the Button.
InlineUIContainer myInlineUIContainer = new InlineUIContainer();
// Set the BaselineAlignment property to "Bottom" so that the
// Button aligns properly with the text.
myInlineUIContainer.BaselineAlignment = BaselineAlignment.Bottom;
// Asign the button as the UI container's child.
myInlineUIContainer.Child = myButton;
// Create the paragraph and add content to it.
Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add(run1);
myParagraph.Inlines.Add(myInlineUIContainer);
myParagraph.Inlines.Add(run2);
// Create a FlowDocument and add the paragraph to it.
FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);
this.Content = myFlowDocument;
}
}
}
Nota: no es necesario utilizar InlineUIContainer explícitamente en el marcado. Si lo omite, se creará de todas formas un elemento InlineUIContainer al compilar el código.
Figure y Floater
Figure y Floater se utilizan para incrustar contenido en documentos dinámicos con propiedades de posición que se pueden personalizar de forma independiente del flujo de contenido primario. Los elementos Figure o Floater se utilizan a menudo para resaltar o recalcar partes de contenido, hospedar imágenes auxiliares u otro contenido dentro del flujo principal de contenido, o bien, para insertar contenido de relación indirecta como los anuncios.
El ejemplo siguiente muestra cómo incrustar un elemento Figure en un párrafo de texto.
<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<Paragraph>
<Figure
Width="300" Height="100"
Background="GhostWhite" HorizontalAnchor="PageLeft" >
<Paragraph FontStyle="Italic" Background="Beige" Foreground="DarkGreen" >
A Figure embeds content into flow content with placement properties
that can be customized independently from the primary content flow
</Paragraph>
</Figure>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy
nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi
enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis
nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure.
</Paragraph>
</FlowDocument>
Imports System
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows.Documents
Namespace SDKSample
Partial Public Class FigureExample
Inherits Page
Public Sub New()
' Create strings to use as content.
Dim strFigure As String = "A Figure embeds content into flow content with" & " placement properties that can be customized" & " independently from the primary content flow"
Dim strOther As String = "Lorem ipsum dolor sit amet, consectetuer adipiscing" & " elit, sed diam nonummy nibh euismod tincidunt ut laoreet" & " dolore magna aliquam erat volutpat. Ut wisi enim ad" & " minim veniam, quis nostrud exerci tation ullamcorper" & " suscipit lobortis nisl ut aliquip ex ea commodo consequat." & " Duis autem vel eum iriure."
' Create a Figure and assign content and layout properties to it.
Dim myFigure As New Figure()
myFigure.Width = New FigureLength(300)
myFigure.Height = New FigureLength(100)
myFigure.Background = Brushes.GhostWhite
myFigure.HorizontalAnchor = FigureHorizontalAnchor.PageLeft
Dim myFigureParagraph As New Paragraph(New Run(strFigure))
myFigureParagraph.FontStyle = FontStyles.Italic
myFigureParagraph.Background = Brushes.Beige
myFigureParagraph.Foreground = Brushes.DarkGreen
myFigure.Blocks.Add(myFigureParagraph)
' Create the paragraph and add content to it.
Dim myParagraph As New Paragraph()
myParagraph.Inlines.Add(myFigure)
myParagraph.Inlines.Add(New Run(strOther))
' Create a FlowDocument and add the paragraph to it.
Dim myFlowDocument As New FlowDocument()
myFlowDocument.Blocks.Add(myParagraph)
Me.Content = myFlowDocument
End Sub
End Class
End Namespace
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Documents;
namespace SDKSample
{
public partial class FigureExample : Page
{
public FigureExample()
{
// Create strings to use as content.
string strFigure = "A Figure embeds content into flow content with" +
" placement properties that can be customized" +
" independently from the primary content flow";
string strOther = "Lorem ipsum dolor sit amet, consectetuer adipiscing" +
" elit, sed diam nonummy nibh euismod tincidunt ut laoreet" +
" dolore magna aliquam erat volutpat. Ut wisi enim ad" +
" minim veniam, quis nostrud exerci tation ullamcorper" +
" suscipit lobortis nisl ut aliquip ex ea commodo consequat." +
" Duis autem vel eum iriure.";
// Create a Figure and assign content and layout properties to it.
Figure myFigure = new Figure();
myFigure.Width = new FigureLength(300);
myFigure.Height = new FigureLength(100);
myFigure.Background = Brushes.GhostWhite;
myFigure.HorizontalAnchor = FigureHorizontalAnchor.PageLeft;
Paragraph myFigureParagraph = new Paragraph(new Run(strFigure));
myFigureParagraph.FontStyle = FontStyles.Italic;
myFigureParagraph.Background = Brushes.Beige;
myFigureParagraph.Foreground = Brushes.DarkGreen;
myFigure.Blocks.Add(myFigureParagraph);
// Create the paragraph and add content to it.
Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add(myFigure);
myParagraph.Inlines.Add(new Run(strOther));
// Create a FlowDocument and add the paragraph to it.
FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);
this.Content = myFlowDocument;
}
}
}
En la ilustración siguiente se muestra cómo se representa este ejemplo.
Los elementos Figure y Floater son distintos y se utilizan en situaciones diferentes.
Elemento Figure:
Se puede determinar su posición: puede establecer sus puntos de anclaje horizontales y verticales para acoplarlo con respecto a la página, el contenido, la columna o el párrafo. También puede utilizar sus propiedades HorizontalOffset y VerticalOffset para especificar desplazamientos arbitrarios.
Se puede ajustar su tamaño a varias columnas: puede establecer el alto y el ancho del elemento Figure en múltiplos de los valores de alto o ancho de la página, el contenido o la columna. Observe que en el caso de la página y del contenido, no se permiten múltiplos mayores que 1. Por ejemplo, puede establecer el ancho de Figure en "0,5 page", "0,25 content" o "2 Column". También puede establecer el alto y el ancho en valores absolutos de píxel.
No pagina: si el contenido de un elemento Figure no cabe en Figure, se representará el contenido que quepa y se perderá el contenido restante.
Elemento Floater:
No se puede determinar su posición y se representará en cualquier espacio que esté disponible. No se puede establecer el desplazamiento ni los puntos de anclaje de un elemento Floater.
No se puede ajustar su tamaño a más de una columna: de forma predeterminada, Floater ajusta su tamaño a una columna. Su propiedad Width puede establecerse en un valor absoluto de píxel, pero si este valor es mayor que el ancho de una columna, se omite y el tamaño del elemento Floater se ajusta a una columna. Su tamaño puede establecerse en menos de una columna configurando el ancho en píxeles correcto, pero el tamaño no es relativo a la columna, por lo que "0,5Column" no es una expresión válida para el ancho de Floater. Floater no tiene una propiedad que especifique el alto: su alto no puede establecerse ya que depende del contenido.
Floater pagina: si su contenido en el ancho especificado se extiende más allá del alto de una columna, el elemento Floater se parte y salta a la siguiente columna, la siguiente página, etc.
Figure se presta especialmente para contenido independiente cuyo tamaño y posición desea controlar, ya que le da la seguridad de que el contenido se ajustará al tamaño especificado. Floater se presta especialmente para contenido que fluye más libremente y de manera similar al contenido de la página principal, pero que es independiente de este último.
LineBreak
LineBreak origina un salto de línea en el contenido dinámico. El siguiente ejemplo muestra el uso de LineBreak.
<FlowDocument xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<Paragraph>
Before the LineBreak in Paragraph.
<LineBreak />
After the LineBreak in Paragraph.
<LineBreak/><LineBreak/>
After two LineBreaks in Paragraph.
</Paragraph>
<Paragraph>
<LineBreak/>
</Paragraph>
<Paragraph>
After a Paragraph with only a LineBreak in it.
</Paragraph>
</FlowDocument>
La captura de pantalla siguiente muestra cómo se representa este ejemplo.
Elementos de colección dinámica
En muchos de los ejemplos anteriores, los elementos BlockCollection y InlineCollection se utilizan para generar contenido dinámico mediante programación. Por ejemplo, para agregar elementos a un objeto Paragraph, puede utilizar la sintaxis siguiente:
…
myParagraph.Inlines.Add(new Run("Some text"));
…
Esto agrega un elemento Run al elemento InlineCollection del objeto Paragraph. Esto es lo mismo que el elemento Run implícito incluido en un objeto Paragraph en el marcado:
…
<Paragraph>
Some Text
</Paragraph>
…
Como ejemplo de uso del elemento BlockCollection, el ejemplo siguiente crea un nuevo elemento Section y, a continuación, utiliza el método Add para agregar un nuevo elemento Paragraph al contenido de Section.
Dim secx As New Section()
secx.Blocks.Add(New Paragraph(New Run("A bit of text content...")))
Section secx = new Section();
secx.Blocks.Add(new Paragraph(new Run("A bit of text content...")));
Además de agregar elementos a una colección dinámica, también se pueden quitar. En el siguiente ejemplo se elimina el último elemento Inline de Span.
spanx.Inlines.Remove(spanx.Inlines.LastInline)
spanx.Inlines.Remove(spanx.Inlines.LastInline);
En el siguiente ejemplo se borra todo el contenido (los elementos Inline) de Span.
spanx.Inlines.Clear()
spanx.Inlines.Clear();
Al trabajar con contenido dinámico mediante programación, probablemente realizará un uso extensivo de estas colecciones.
Que un elemento dinámico utilice un elemento InlineCollection (Inlines) o un elemento BlockCollection (Blocks) para contener sus elementos secundarios dependerá de qué tipo de elementos secundarios (Block o Inline) puedan ser incluidos en el elemento primario. Las reglas de contención para los elementos de contenido dinámico se resumen en el esquema de contenido de la sección siguiente.
Nota: existe un tercer tipo de colección utilizado con el contenido dinámico, ListItemCollection, pero esta colección sólo se usa con un elemento List. Además, hay varias colecciones que se utilizan con Table. Vea Información general sobre tablas para obtener más información.
Esquema de contenido
Dado el número de elementos de contenido dinámico diferentes que existen, puede resultar muy complicado efectuar un seguimiento del tipo de elementos secundarios que puede contener un elemento. El diagrama siguiente resume las reglas de contención para los elementos dinámicos. Las flechas representan las posibles relaciones entre elementos primarios/secundarios.
Como se puede ver en el diagrama anterior, los elementos secundarios permitidos para un elemento no están determinados necesariamente por el hecho de que éste sea un elemento Block o Inline. Por ejemplo, un objeto Span (un elemento Inline) sólo puede tener elementos secundarios Inline, mientras que un objeto Figure (también un elemento Inline) sólo puede tener elementos secundarios Block. Por consiguiente, un diagrama es útil para determinar rápidamente qué elemento puede incluirse en otro. Como ejemplo, utilicemos el diagrama para determinar cómo construir el contenido dinámico de un elemento RichTextBox.
1. Un objeto RichTextBox debe contener un elemento FlowDocument, que a su vez debe contener un objeto derivado de Block. A continuación se muestra el segmento correspondiente del diagrama anterior.
Llegados a este punto, esta es la apariencia que podría tener el marcado.
<RichTextBox>
<FlowDocument>
<!-- One or more Block-derived object… -->
</FlowDocument>
</RichTextBox>
2. Según el diagrama, hay varios elementos Block entre los que elegir, incluyendo Paragraph, Section, Table, List y BlockUIContainer (vea Clases derivadas de bloque más arriba). Supongamos que deseamos un elemento Table. Según el diagrama anterior, un objeto Table incluye un elemento TableRowGroup que contiene elementos TableRow, que a su vez contienen elementos TableCell que incluyen un objeto derivado de Block. A continuación se muestra el segmento correspondiente para el elemento Table tomado del diagrama anterior.
A continuación se muestra el marcado correspondiente.
<RichTextBox>
<FlowDocument>
<Table>
<TableRowGroup>
<TableRow>
<TableCell>
<!-- One or more Block-derived object… -->
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</FlowDocument>
</RichTextBox>
3. De nuevo, se requieren uno o varios elementos Block debajo de un elemento TableCell. Para facilitar el proceso, coloquemos texto dentro de la celda. Podemos hacerlo utilizando un objeto Paragraph con un elemento Run. A continuación se muestran los segmentos correspondientes del diagrama que demuestran que un objeto Paragraph puede aceptar un elemento Inline y que un objeto Run (un elemento Inline) sólo puede aceptar texto sin formato.
A continuación se muestra el ejemplo completo en el marcado.
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<RichTextBox>
<FlowDocument>
<!-- Normally a table would have multiple rows and multiple
cells but this code is for demonstration purposes.-->
<Table>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>
<!-- The schema does not actually require
explicit use of the Run tag in markup. It
is only included here for clarity. -->
<Run>Paragraph in a Table Cell.</Run>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</FlowDocument>
</RichTextBox>
</Page>
Personalizar el texto
Normalmente, el tipo de contenido más abundante en un documento dinámico es el texto. Aunque los objetos descritos anteriormente se pueden utilizar para controlar la mayoría de los aspectos de la representación del texto, hay otros métodos para personalizar el texto que se describen en esta sección.
Decoraciones de texto
Las decoraciones de texto le permiten aplicar efectos de subrayado, de línea alta, de línea base y de tachado al texto (vea las imágenes siguientes). Estas decoraciones se agregan utilizando la propiedad TextDecorations expuesta por varios objetos, como Inline, Paragraph, TextBlock y TextBox.
En el ejemplo siguiente se muestra cómo establecer la propiedad TextDecorations de un objeto Paragraph.
<FlowDocument ColumnWidth="200">
<Paragraph TextDecorations="Strikethrough">
This text will render with the strikethrough effect.
</Paragraph>
</FlowDocument>
Dim parx As New Paragraph(New Run("This text will render with the strikethrough effect."))
parx.TextDecorations = TextDecorations.Strikethrough
Paragraph parx = new Paragraph(new Run("This text will render with the strikethrough effect."));
parx.TextDecorations = TextDecorations.Strikethrough;
En la ilustración siguiente se muestra cómo se representa este ejemplo.
Las ilustraciones siguientes muestran cómo se representan las decoraciones Línea alta, Línea base y Subrayado, respectivamente.
Tipografía
La propiedad Typography la expone la mayoría del contenido relacionado con el flujo, como TextElement, FlowDocument, TextBlock y TextBox. Esta propiedad se utiliza para controlar características/variaciones tipográficas del texto (por ejemplo, mayúsculas pequeñas o grandes, generación de superíndices y subíndices, etc.).
En el ejemplo siguiente se muestra cómo establecer el atributo Typography usando Paragraph como elemento de ejemplo.
<Paragraph
TextAlignment="Left"
FontSize="18"
FontFamily="Palatino Linotype"
Typography.NumeralStyle="OldStyle"
Typography.Fraction="Stacked"
Typography.Variants="Inferior"
>
<Run>
This text has some altered typography characteristics. Note
that use of an open type font is necessary for most typographic
properties to be effective.
</Run>
<LineBreak/><LineBreak/>
<Run>
0123456789 10 11 12 13
</Run>
<LineBreak/><LineBreak/>
<Run>
1/2 2/3 3/4
</Run>
</Paragraph>
En la ilustración siguiente se muestra cómo se representa este ejemplo.
En contraste, en la ilustración siguiente se muestra cómo se representa un ejemplo similar con propiedades tipográficas predeterminadas.
En el ejemplo siguiente se muestra cómo establecer la propiedad Typography mediante programación.
Dim par As New Paragraph()
Dim runText As New Run("This text has some altered typography characteristics. Note" & "that use of an open type font is necessary for most typographic" & "properties to be effective.")
Dim runNumerals As New Run("0123456789 10 11 12 13")
Dim runFractions As New Run("1/2 2/3 3/4")
par.Inlines.Add(runText)
par.Inlines.Add(New LineBreak())
par.Inlines.Add(New LineBreak())
par.Inlines.Add(runNumerals)
par.Inlines.Add(New LineBreak())
par.Inlines.Add(New LineBreak())
par.Inlines.Add(runFractions)
par.TextAlignment = TextAlignment.Left
par.FontSize = 18
par.FontFamily = New FontFamily("Palatino Linotype")
par.Typography.NumeralStyle = FontNumeralStyle.OldStyle
par.Typography.Fraction = FontFraction.Stacked
par.Typography.Variants = FontVariants.Inferior
Paragraph par = new Paragraph();
Run runText = new Run(
"This text has some altered typography characteristics. Note" +
"that use of an open type font is necessary for most typographic" +
"properties to be effective.");
Run runNumerals = new Run("0123456789 10 11 12 13");
Run runFractions = new Run("1/2 2/3 3/4");
par.Inlines.Add(runText);
par.Inlines.Add(new LineBreak());
par.Inlines.Add(new LineBreak());
par.Inlines.Add(runNumerals);
par.Inlines.Add(new LineBreak());
par.Inlines.Add(new LineBreak());
par.Inlines.Add(runFractions);
par.TextAlignment = TextAlignment.Left;
par.FontSize = 18;
par.FontFamily = new FontFamily("Palatino Linotype");
par.Typography.NumeralStyle = FontNumeralStyle.OldStyle;
par.Typography.Fraction = FontFraction.Stacked;
par.Typography.Variants = FontVariants.Inferior;
Vea Tipografía en WPF para obtener más información sobre tipografía.
Vea también
Conceptos
Optimizar el rendimiento: Texto
Información general sobre el modelo de contenido de TextElement
Información general sobre el control RichTextBox
Información general sobre tablas
Información general sobre anotaciones