Visão geral do documento de fluxo

Os documentos de fluxo são projetados para otimizar a visualização e a legibilidade. Em vez de serem definidos como um layout predefinido, os documentos de fluxo ajustam e refluxam dinamicamente seu conteúdo com base em variáveis de tempo de execução, como tamanho da janela, resolução do dispositivo e preferências opcionais do usuário. Além disso, os documentos de fluxo oferecem recursos de documentos avançados, como paginação e colunas. Este tópico fornece uma visão geral dos documentos de fluxo e como criá-los.

O que é um documento de fluxo

Um documento de fluxo foi projetado para "refluxar conteúdo" dependendo do tamanho da janela, da resolução do dispositivo e de outras variáveis de ambiente. Além disso, os documentos de fluxo têm uma série de recursos internos, incluindo pesquisa, modos de exibição que otimizam a legibilidade e a capacidade de alterar o tamanho e a aparência das fontes. Os documentos dinâmicos são utilizados melhor quando a facilidade de leitura é o cenário de consumo do documento principal. Por outro lado, os Documentos Fixos foram projetados para ter uma apresentação estática. Os Documentos Fixos são úteis quando a fidelidade do conteúdo de origem é essencial. Consulte Documentos no WPF para obter mais detalhes sobre os diversos tipos de documentos.

A ilustração a seguir mostra um documento de fluxo de exemplo exibido em várias janelas de tamanhos diferentes. Quando a área de exibição muda, o conteúdo é reorganizado para fazer o melhor uso do espaço disponível.

Conteúdo do Documento de Fluxo Refluxo de conteúdo de documento dinâmico

Como visto na imagem acima, o conteúdo do fluxo pode incluir muitos componentes, incluindo parágrafos, listas, imagens e muito mais. Esses componentes correspondem a elementos na marcação e objetos no código de procedimento. Abordaremos essas classes em detalhes mais adiante na seção Classes Relacionadas ao Fluxo desta visão geral. Por enquanto, aqui está um exemplo de código simples que cria um documento de fluxo que consiste em um parágrafo com algum texto em negrito e uma lista.

<!-- This simple flow document includes a paragraph with some
     bold text in it and a list. -->
<FlowDocumentReader xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://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>
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;
        }
    }
}

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

A ilustração abaixo mostra a aparência desse snippet de código.

Captura de tela Captura de tela: exemplo de FlowDocument renderizado

Neste exemplo, o controle FlowDocumentReader é usado para hospedar o conteúdo do fluxo. Consulte Tipos de Documento de Fluxo para obter mais informações sobre controles de hospedagem de conteúdo de fluxo. Paragraph, List, ListIteme elementos Bold são usados para controlar a formatação de conteúdo, com base em sua ordem na marcação. Por exemplo, o elemento Bold abrange apenas parte do texto no parágrafo; como resultado, somente essa parte do texto está em negrito. Se você tiver usado HTML, isso será familiar para você.

Conforme realçado na ilustração acima, há vários recursos integrados aos Documentos do Flow:

  • Pesquisa: permite que o usuário execute uma pesquisa de texto completo de um documento inteiro.

  • Modo de Exibição: o usuário pode selecionar seu modo de exibição preferencial, incluindo um modo de exibição de página única (página por vez), um modo de exibição de duas páginas por vez (formato de leitura de livro) e um modo de exibição de rolagem contínua (sem fundo). Para obter mais informações sobre esses modos de exibição, consulte FlowDocumentReaderViewingMode.

  • Controles de navegação de página: se o modo de exibição do documento usa páginas, os controles de navegação da página incluem um botão para ir para a próxima página (a seta para baixo) ou a página anterior (a seta para cima), bem como indicadores para o número de página atual e o número total de páginas. Inverter páginas também pode ser feito usando as teclas de seta do teclado.

  • Zoom: os controles de zoom permitem que o usuário aumente ou diminua o nível de zoom clicando nos botões de adição ou subtração, respectivamente. Os controles de zoom também incluem um controle deslizante para ajustar o nível de zoom. Para obter mais informações, consulte Zoom.

Esses recursos podem ser modificados com base no controle usado para hospedar o conteúdo do fluxo. A próxima seção descreve os diferentes controles.

Tipos de documento de fluxo

A exibição do conteúdo do documento de fluxo e como ele aparece depende de qual objeto é usado para hospedar o conteúdo do fluxo. Há quatro controles que dão suporte à exibição de conteúdo de fluxo: FlowDocumentReader, FlowDocumentPageViewer, RichTextBoxe FlowDocumentScrollViewer. Esses controles são descritos brevemente abaixo.

Nota

FlowDocument é necessário para hospedar diretamente o conteúdo do fluxo, portanto, todos esses controles de exibição consomem uma FlowDocument para habilitar a hospedagem de conteúdo de fluxo.

FlowDocumentReader

FlowDocumentReader inclui recursos que permitem que o usuário escolha dinamicamente entre vários modos de exibição, incluindo um modo de exibição de página única (página por vez), um modo de exibição de duas páginas por vez (formato de leitura de livro) e um modo de exibição de rolagem contínua (sem fundo). Para obter mais informações sobre esses modos de exibição, consulte FlowDocumentReaderViewingMode. Se você não precisar da capacidade de alternar dinamicamente entre diferentes modos de exibição, FlowDocumentPageViewer e FlowDocumentScrollViewer oferecem visualizadores de conteúdo leve que são fixos em um modo de exibição específico.

FlowDocumentPageViewer e FlowDocumentScrollViewer

FlowDocumentPageViewer mostra o conteúdo no modo de exibição de página por vez, enquanto FlowDocumentScrollViewer mostra o conteúdo no modo de rolagem contínua. Tanto FlowDocumentPageViewer quanto FlowDocumentScrollViewer estão fixados em um modo de exibição específico. Compare com FlowDocumentReader, que inclui recursos que permitem que o usuário escolha dinamicamente entre vários modos de exibição (conforme fornecido pela enumeração FlowDocumentReaderViewingMode), ao custo de ser mais intensivo em recursos do que FlowDocumentPageViewer ou FlowDocumentScrollViewer.

Por padrão, uma barra de rolagem vertical é sempre mostrada e uma barra de rolagem horizontal fica visível, se necessário. A interface do usuário padrão para FlowDocumentScrollViewer não inclui uma barra de ferramentas; no entanto, a propriedade IsToolBarVisible pode ser usada para habilitar uma barra de ferramentas interna.

RichTextBox

Você usa um RichTextBox quando deseja permitir que o usuário edite o conteúdo do fluxo. Por exemplo, se você quisesse criar um editor que permitisse que um usuário manipulasse coisas como tabelas, itálico e formatação em negrito, etc. você usaria um RichTextBox. Consulte Visão Geral do RichTextBox para obter mais informações.

Nota

O conteúdo de fluxo dentro de uma RichTextBox não se comporta exatamente como o conteúdo de fluxo contido em outros controles. Por exemplo, não há colunas em um RichTextBox e, portanto, nenhum comportamento de redimensionamento automático. Além disso, os recursos normalmente integrados de conteúdo de fluxo, como pesquisa, modo de exibição, navegação de página e zoom, não estão disponíveis em um RichTextBox.

Criando conteúdo de fluxo

O conteúdo do fluxo pode ser complexo, consistindo em vários elementos, incluindo texto, imagens, tabelas e até mesmo UIElement classes derivadas, como controles. Para entender como criar conteúdo de fluxo complexo, os seguintes pontos são críticos:

  • classes relacionadas ao fluxo: cada classe usada no conteúdo do fluxo tem uma finalidade específica. Além disso, a relação hierárquica entre classes de fluxo ajuda você a entender como elas são usadas. Por exemplo, classes derivadas da classe Block são usadas para conter outros objetos, enquanto classes derivadas de Inline contêm objetos que são exibidos.

  • Esquema de Conteúdo: um documento de fluxo pode requerer um grande número de elementos aninhados. O esquema de conteúdo especifica possíveis relações pai/filho entre elementos.

As seções a seguir percorrerão cada uma dessas áreas com mais detalhes.

O diagrama abaixo mostra os objetos mais usados com conteúdo de fluxo:

Diagrama : hierarquia de classes de elementos de conteúdo de fluxo

Para fins de conteúdo de fluxo, há duas categorias importantes:

  1. Classes Derivadas de Bloco: também chamadas de "Elementos de Conteúdo de Bloco" ou apenas "Elementos de Bloco". Elementos que herdam de Block podem ser usados para agrupar elementos em um pai comum ou aplicar atributos comuns a um grupo.

  2. Classes derivadas de embutidos: também chamadas de "elementos de conteúdo embutido" ou simplesmente "elementos embutidos". Elementos que herdam de Inline estão contidas em um elemento de bloco ou então de outro elemento embutido. Elementos embutidos geralmente são usados como o contêiner direto do conteúdo que é renderizado na tela. Por exemplo, um Paragraph (Elemento de Bloco) pode conter um Run (Elemento em Linha), mas o Run realmente contém o texto que é renderizado na tela.

Cada classe nessas duas categorias é brevemente descrita abaixo.

Classes derivadas de bloco

Paragraph

Paragraph normalmente é usado para agrupar conteúdo em um parágrafo. O uso mais simples e comum de Paragraph é criar um parágrafo de texto.

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Paragraph>
    Some paragraph text.
  </Paragraph>
</FlowDocument>
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;
        }
    }
}

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

No entanto, você também pode conter outros elementos derivados em linha, como você verá abaixo.

Section

Section é usado apenas para conter outros elementos derivados de Block. Ele não aplica nenhuma formatação padrão aos elementos que ele contém. No entanto, todos os valores de propriedade definidos em um Section se aplicam aos respectivos elementos filho. Você também tem permissão para iterar programaticamente pela coleção filho de uma seção. Section é usado de maneira semelhante à tag <DIV> em HTML.

No exemplo abaixo, três parágrafos são definidos sob uma Section. A seção tem um valor de propriedade Background igual a vermelho, logo, a cor de fundo dos parágrafos também é vermelha.

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>
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;
        }
    }
}

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

BlockUIContainer

BlockUIContainer permite que elementos UIElement (ou seja, um Button) sejam inseridos no conteúdo de fluxo derivado de bloco. InlineUIContainer (veja abaixo) é usado para inserir elementos UIElement no conteúdo de fluxo derivado embutido. BlockUIContainer e InlineUIContainer são importantes porque não há outra maneira de usar um UIElement no conteúdo do fluxo, a menos que ele esteja contido em um desses dois elementos.

O exemplo a seguir mostra como usar o elemento BlockUIContainer para hospedar objetos UIElement dentro do conteúdo do fluxo.

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

A figura a seguir mostra como este exemplo é renderizado:

Captura de tela que mostra um elemento de interface (UIElement) inserido no fluxo de conteúdo.

List

List é usado para criar uma lista com marcadores ou uma lista numerada. Defina a propriedade MarkerStyle como um valor de enumeração TextMarkerStyle para determinar o estilo da lista. O exemplo a seguir mostra como criar uma lista simples.

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>
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;
        }
    }
}

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

Nota

List é o único elemento de fluxo que usa o ListItemCollection para gerenciar elementos filho.

Tabela

Table é usado para criar uma tabela. Table é semelhante ao elemento Grid, mas tem mais funcionalidades e, portanto, requer maior sobrecarga de recursos. Como Grid é um UIElement, ele não pode ser usado no conteúdo do fluxo, a menos que esteja contido em um BlockUIContainer ou InlineUIContainer. Para obter mais informações sobre Table, consulte Visão geral da tabela.

Classes derivadas de embutidos

Executar

Run é usado para conter texto não formatado. Você pode esperar que objetos Run sejam usados extensivamente em conteúdo de fluxo. No entanto, na marcação, os elementos Run não precisam ser usados de forma explícita. Run é necessário para ser usado ao criar ou manipular documentos de fluxo usando código. Por exemplo, na marcação abaixo, o primeiro Paragraph especifica explicitamente o elemento Run enquanto o segundo não. Ambos os parágrafos geram uma saída idêntica.

<Paragraph>
  <Run>Paragraph that explicitly uses the Run element.</Run>
</Paragraph>

<Paragraph>
  This Paragraph omits the Run element in markup. It renders
  the same as a Paragraph with Run used explicitly. 
</Paragraph>

Nota

A partir do .NET Framework 4, a propriedade Text do objeto Run é uma propriedade de dependência. Você pode associar a propriedade Text a uma fonte de dados, como um TextBlock. A propriedade Text suporta totalmente a associação unidirecional. A propriedade Text também dá suporte à associação bidirecional, exceto para RichTextBox. Para obter um exemplo, consulte Run.Text.

Span

Span agrupa outros elementos de conteúdo em linha. Nenhuma renderização inerente é aplicada ao conteúdo dentro de um elemento Span. No entanto, elementos que herdam de Span incluindo Hyperlink, Bold, Italic e Underline aplicam a formatação ao texto.

Veja abaixo um exemplo de um Span sendo usado para conter conteúdo embutido, incluindo texto, um elemento Bold e um Button.

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>

A captura de tela a seguir mostra como este exemplo é renderizado.

Captura de tela: exemplo de Span renderizado Captura de tela: exemplo de intervalo renderizado

InlineUIContainer

InlineUIContainer permite que elementos UIElement (ou seja, um controle como Button) sejam inseridos em um elemento de conteúdo Inline. Esse elemento é o equivalente inline ao BlockUIContainer descrito acima. Veja abaixo um exemplo que usa InlineUIContainer para inserir um Button embutido em um Paragraph.

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>
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;
        }
    }
}

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

Nota

InlineUIContainer não precisa ser usado explicitamente na marcação. Se você omitir, um InlineUIContainer será criado de qualquer maneira quando o código for compilado.

Figure e Floater

Figure e Floater são usados para inserir conteúdo em Documentos de Fluxo com propriedades de posicionamento que podem ser personalizadas independentemente do fluxo de conteúdo primário. Figure ou elementos Floater geralmente são usados para realçar ou acentuar partes do conteúdo, hospedar imagens de suporte ou outro conteúdo dentro do fluxo de conteúdo principal ou injetar conteúdo livremente relacionado, como anúncios.

O exemplo a seguir mostra como inserir um Figure em um parágrafo de texto.

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>
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;
        }
    }
}

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

A ilustração a seguir mostra como este exemplo é renderizado.

Captura de tela: exemplo de Figure

Figure e Floater diferem de várias maneiras e são usados para cenários diferentes.

Figure:

  • Pode ser posicionado: você pode definir suas âncoras horizontais e verticais para posicioná-la em relação à página, ao conteúdo, à coluna ou ao parágrafo. Você também pode usar suas propriedades HorizontalOffset e VerticalOffset para especificar deslocamentos arbitrários.

  • É redimensionável para mais de uma coluna: você pode definir a altura e a largura de Figure para serem múltiplos da altura ou largura da página, do conteúdo ou da coluna. Observe que, no caso de página e conteúdo, múltiplos maiores que 1 não são permitidos. Por exemplo, você pode definir a largura de um Figure como "0,5 página" ou "conteúdo 0,25" ou "2 Coluna". Você também pode definir altura e largura como valores absolutos de pixel.

  • Sem paginação: se o conteúdo dentro de um Figure não se ajustar dentro do Figure, ele renderizará o conteúdo que couber e o conteúdo restante será perdido

Floater:

  • Não pode ser posicionado e renderizará onde quer que o espaço possa ser disponibilizado para ele. Não é possível definir o deslocamento ou ancorar um Floater.

  • Não é possível dimensionar para mais de uma coluna: por padrão, Floater é dimensionado para uma coluna. Ele tem uma propriedade Width que pode ser definida como um valor de pixel absoluto, mas se esse valor for maior que uma largura de coluna, ele será ignorado e o floater será dimensionado em uma coluna. Você pode dimensioná-la para menos de uma coluna definindo a largura de pixel correta, mas o dimensionamento não é relativo à coluna, portanto, "0.5Column" não é uma expressão válida para Floater largura. Floater não tem nenhuma propriedade de altura e sua altura não pode ser definida, sua altura depende do conteúdo

  • Floater realiza paginação: se o conteúdo na largura especificada se estender além de 1 altura de coluna, o Floater realizará a quebra e a paginação para a próxima coluna, a próxima página, etc.

Figure é um bom lugar para colocar conteúdo autônomo onde você deseja controlar o tamanho e o posicionamento e tem certeza de que o conteúdo se ajustará ao tamanho especificado. Floater é um bom lugar para colocar mais conteúdo de fluxo livre semelhante ao da página principal, mas separado dele.

LineBreak

LineBreak causa uma quebra de linha no fluxo de conteúdo. O exemplo a seguir demonstra o uso de LineBreak.

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>

A captura de tela a seguir mostra como este exemplo é renderizado.

Captura de tela do Captura de tela: exemplo de LineBreak

Elementos da coleção Flow

Em muitos dos exemplos acima, os BlockCollection e InlineCollection são usados para construir conteúdo de fluxo programaticamente. Por exemplo, para adicionar elementos a um Paragraph, você pode usar a sintaxe:

myParagraph.Inlines.Add(new Run("Some text"));

Isso adiciona uma Run à InlineCollection do Paragraph. Isso é o mesmo que o Run implícito encontrado dentro de um Paragraph na marcação:

<Paragraph>
Some Text
</Paragraph>

Como exemplo de uso do BlockCollection, o exemplo a seguir cria uma nova Section e usa o método Add para adicionar um novo Paragraph ao conteúdo Section.

Section secx = new Section();
secx.Blocks.Add(new Paragraph(new Run("A bit of text content...")));
Dim secx As New Section()
secx.Blocks.Add(New Paragraph(New Run("A bit of text content...")))

Além de adicionar itens a uma coleção de fluxos, você também pode remover itens. O exemplo a seguir exclui o último elemento Inline no Span.

spanx.Inlines.Remove(spanx.Inlines.LastInline);
spanx.Inlines.Remove(spanx.Inlines.LastInline)

O exemplo a seguir limpa todo o conteúdo (elementosInline) do Span.

spanx.Inlines.Clear();
spanx.Inlines.Clear()

Ao trabalhar com conteúdo de fluxo programaticamente, você provavelmente fará uso extensivo dessas coleções.

O uso de uma InlineCollection (Inlines) ou uma BlockCollection (Blocos) por um elemento dinâmico para conter os elementos filho dele depende de que tipo de elementos filho (Block ou Inline) podem ser contidos pelo pai. As regras de contenção para elementos de conteúdo de fluxo são resumidas no esquema de conteúdo na próxima seção.

Nota

Há um terceiro tipo de coleção usada com conteúdo dinâmico, a ListItemCollection, mas essa coleção só é usada com um List. Além disso, há várias coleções usadas com Table. Confira Visão Geral da Tabela para obter mais informações.

Esquema de conteúdo

Dado o número de elementos de conteúdo dinâmico diferentes, pode ser difícil controlar que tipo de elementos filho um elemento pai pode conter. O diagrama a seguir resume as regras de contenção para elementos de fluxo. As setas representam as possíveis relações pai/filho.

Diagrama : Esquema de contenção de conteúdo de fluxo

Como pode ser visto no diagrama acima, os filhos permitidos para um elemento não são necessariamente determinados por se ele é um elemento Block ou um elemento Inline. Por exemplo, um Span (um elemento Inline) só pode ter elementos filho Inline, enquanto um Figure (também um elemento Inline) só pode ter elementos filho Block. Portanto, um diagrama é útil para determinar rapidamente qual elemento pode ser contido em outro. Como exemplo, vamos usar o diagrama para determinar como construir o conteúdo de fluxo de um RichTextBox.

1. Um RichTextBox deve conter um FlowDocument que, por sua vez, deve conter um objeto derivado de Block. Abaixo está o segmento correspondente do diagrama acima.

Diagrama Diagrama: regras de contenção RichTextBox

Até agora, essa é a aparência que a marcação pode ter.

<RichTextBox>
  <FlowDocument>
    <!-- One or more Block-derived object… -->
  </FlowDocument>
</RichTextBox>

2. De acordo com o diagrama, há vários elementos Block para escolher, incluindo Paragraph, Section, Table, Liste BlockUIContainer (consulte as classes derivadas de bloco acima). Digamos que queremos um Table. De acordo com o diagrama acima, um Table contém um TableRowGroup contendo elementos TableRow, que contêm elementos TableCell, que por sua vez contêm um objeto derivado de Block. Abaixo está o segmento correspondente de Table obtido do diagrama acima.

Diagrama: Diagrama: esquema pai/filho para Table

Abaixo está a marcação correspondente.

<RichTextBox>
  <FlowDocument>
    <Table>
      <TableRowGroup>
        <TableRow>
          <TableCell>
            <!-- One or more Block-derived object… -->
          </TableCell>
        </TableRow>
      </TableRowGroup>
    </Table>
  </FlowDocument>
</RichTextBox>

3. Novamente, um ou mais elementos Block são necessários sob um TableCell. Para simplificar, vamos colocar um texto dentro da célula. Podemos fazer isso usando um Paragraph com um elemento Run. Abaixo estão os segmentos correspondentes do diagrama mostrando que um Paragraph pode usar um elemento Inline e que um Run (um elemento Inline) só pode usar texto sem formatação.

Diagrama de Diagrama: esquema pai/filho para Paragraph

Diagrama Diagrama: esquema pai/filho para Run

Abaixo está o exemplo inteiro na marcação.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>

Personalizando texto

Normalmente, o texto é o tipo mais predominante de conteúdo em um documento de fluxo. Embora os objetos introduzidos acima possam ser usados para controlar a maioria dos aspectos de como o texto é renderizado, há alguns outros métodos para personalizar o texto abordado nesta seção.

Decorações de Texto

Decorações de texto permitem que você aplique os efeitos de sublinhado, linha sobreposta, linha de base e tachado ao texto (consulte as figuras abaixo). Essas decorações são adicionadas usando a propriedade TextDecorations exposta por vários objetos, incluindo Inline, Paragraph, TextBlock e TextBox.

O exemplo a seguir mostra como definir a propriedade TextDecorations de um Paragraph.

<FlowDocument ColumnWidth="200">
  <Paragraph TextDecorations="Strikethrough">
    This text will render with the strikethrough effect.
  </Paragraph>
</FlowDocument>
Paragraph parx = new Paragraph(new Run("This text will render with the strikethrough effect."));
parx.TextDecorations = TextDecorations.Strikethrough;
Dim parx As New Paragraph(New Run("This text will render with the strikethrough effect."))
parx.TextDecorations = TextDecorations.Strikethrough

A figura a seguir mostra como este exemplo é renderizado.

Captura de tela: texto com efeito tachado padrão

As figuras a seguir mostram como as decorações de Sobrelinha, Linha de Base e Sublinhado são renderizadas, respectivamente.

Captura de tela: Captura de tela: TextDecorator Sobrelinha

Captura de tela : Efeito padrão da linha de base no texto

Captura de tela: Texto com efeito de sublinhado padrão

Tipografia

A propriedade Typography é exposta pela maioria dos conteúdos relacionados ao fluxo, incluindo TextElement, FlowDocument, TextBlock e TextBox. Essa propriedade é usada para controlar características tipográficas/variações de texto (ou seja, versalete ou maiúscula, aplicação de sobrescritos e subscritos, etc).

O exemplo a seguir mostra como definir o atributo Typography, usando Paragraph como o elemento de exemplo.

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

A figura a seguir mostra como este exemplo é renderizado.

Captura de tela mostrando o texto com tipografia alterada.

Em comparação, a figura a seguir mostra como um exemplo semelhante com propriedades tipográficas padrão é renderizado.

Captura de tela mostrando o texto com tipografia padrão.

O exemplo a seguir mostra como definir a propriedade Typography programaticamente.

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;
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

Consulte Tipografia no WPF para obter mais informações sobre tipografia.

Consulte também