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.

Cambio de flujo del contenido de documentos de flujo

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.

Captura de pantalla: Ejemplo de FlowDocument representado

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:

Diagrama: Jerarquía de clases de elementos de contenido dinámico

En lo que al contenido dinámico se refiere, hay dos categorías importantes:

  1. 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.

  2. 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.

Captura de pantalla: UIElement incrustado en contenido dinámico

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.

Captura de pantalla: Ejemplo de Span representado

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.

Captura de pantalla: Ejemplo de figura

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.

Captura de pantalla: Ejemplo de LineBreak

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.

Diagrama: Esquema de contención de contenido dinámico

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.

Diagrama: Reglas de contención de RichTextBox

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.

Diagrama: Esquema primario/secundario para tabla

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.

Diagrama: Esquema primario/secundario para párrafoDiagrama: Esquema primario/secundario para ejecución

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.

Captura de pantalla: Texto con efecto de tachado predeterminado

Las ilustraciones siguientes muestran cómo se representan las decoraciones Línea alta, Línea base y Subrayado, respectivamente.

Captura de pantalla: TextDecorator de línea altaCaptura de pantalla: Efecto de línea base predeterminada en textoCaptura de pantalla: Texto con efecto de subrayado predeterminado

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.

Captura de pantalla: Texto con tipografía modificada

En contraste, en la ilustración siguiente se muestra cómo se representa un ejemplo similar con propiedades tipográficas predeterminadas.

Captura de pantalla: Texto con tipografía modificada

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

Tipografía en WPF

Información general sobre el modelo de contenido de TextElement

Información general sobre el control RichTextBox

Documentos en WPF

Información general sobre tablas

Información general sobre anotaciones

Otros recursos

Temas "Cómo..." de elementos de contenido dinámico