Links de conteúdo em controles de texto

Links de conteúdo fornecem uma maneira de inserir dados avançados em seus controles de texto, o que permite que um usuário encontre e use mais informações sobre uma pessoa ou um local sem sair do contexto de seu aplicativo.

Importante

Os recursos do Windows que habilitam links de conteúdo não estão disponíveis em versões do Windows posteriores ao Windows 10 versão 1903. Os links de conteúdo para controles de texto XAML não funcionarão nas versões do Windows posteriores à 1903.

Quando o usuário estabelece como prefixo de uma entrada o símbolo de arroba (@) em uma RichEditBox, uma lista de sugestões de pessoas e/ou locais que corresponde à entrada é exibida. Em seguida, por exemplo, quando o usuário seleciona um local, um ContentLink para esse local é inserido no texto. Quando o usuário invoca o link de conteúdo da RichEditBox, um submenu é mostrado com um mapa e informações adicionais sobre o local.

APIs importantes: ContentLink class, ContentLinkInfo class, RichEditTextRange class

Observação

As APIs para links de conteúdo estão espalhadas pelos seguintes namespaces: Windows.UI.Xaml.Controls, Windows.UI.Xaml.Documents e Windows.UI.Text.

Há duas maneiras distintas de usar links de conteúdo:

  1. Em uma RichEditBox, o usuário pode abrir um seletor para adicionar um link de conteúdo por meio da prefixação de texto com um símbolo @. O link de conteúdo é armazenado como parte do conteúdo de texto avançado.
  2. Em um TextBlock ou RichTextBlock, o link de conteúdo é um elemento de texto com uso e comportamento como um hiperlink.

Veja a aparência de links de conteúdo por padrão em uma RichEditBox e em um TextBlock.

content link in rich edit boxcontent link in text block

Diferenças em uso, renderização e comportamento são abordadas em detalhes nas seções a seguir. Esta tabela dá uma rápida comparação das principais diferenças entre um link de conteúdo em uma RichEditBox e um bloco de texto.

Recurso RichEditBox bloco de texto
Uso Instância ContentLinkInfo Elemento de texto ContentLink
Cursor Determinado pelo tipo de link de conteúdo, não pode ser alterado Determinado pela propriedade Cursor, null por padrão
ToolTip Não é renderizado Mostra o texto secundário

O uso mais comum de um link de conteúdo é permitir que um usuário adicione informações rapidamente por meio da prefixação de um nome de pessoa ou local com um símbolo de e comercial (@) no texto. Quando habilitada em uma RichEditBox, isso abre um seletor e permite que o usuário insira uma pessoa de sua lista de contatos ou um local nas proximidades, dependendo do que você habilitou.

O link de conteúdo pode ser salvo com o conteúdo de texto avançado. Você pode extraí-lo para usar em outras partes do seu aplicativo. Por exemplo, em um aplicativo de email, você pode extrair as informações da pessoa e usá-las para preencher a caixa Para com um endereço de email.

Observação

O seletor de link de conteúdo é um aplicativo que faz parte do Windows, portanto, ele é executado em um processo separado do seu aplicativo.

Para habilitar links de conteúdo em uma RichEditBox, adicione um ou mais provedores de link de conteúdo à coleção RichEditBox.ContentLinkProviders. Há 2 provedores de link de conteúdo incorporados na estrutura XAML.

Importante

O valor padrão da propriedade RichEditBox.ContentLinkProviders é null, não é uma coleção vazia. Você precisa criar explicitamente o ContentLinkProviderCollection antes de adicionar provedores de link de conteúdo.

Veja como adicionar os provedores de link de conteúdo em XAML.

<RichEditBox>
    <RichEditBox.ContentLinkProviders>
        <ContentLinkProviderCollection>
            <ContactContentLinkProvider/>
            <PlaceContentLinkProvider/>
        </ContentLinkProviderCollection>
    </RichEditBox.ContentLinkProviders>
</RichEditBox>

Você também pode adicionar provedores de link de conteúdo em um estilo e aplicá-lo a várias RichEditBoxes desta forma.

<Page.Resources>
    <Style TargetType="RichEditBox" x:Key="ContentLinkStyle">
        <Setter Property="ContentLinkProviders">
            <Setter.Value>
                <ContentLinkProviderCollection>
                    <PlaceContentLinkProvider/>
                    <ContactContentLinkProvider/>
                </ContentLinkProviderCollection>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

<RichEditBox x:Name="RichEditBox01" Style="{StaticResource ContentLinkStyle}" />
<RichEditBox x:Name="RichEditBox02" Style="{StaticResource ContentLinkStyle}" />

Veja como adicionar os provedores de link de conteúdo em código.

RichEditBox editor = new RichEditBox();
editor.ContentLinkProviders = new ContentLinkProviderCollection
{
    new ContactContentLinkProvider(),
    new PlaceContentLinkProvider()
};

A aparência de um link de conteúdo é determinada pelo seu primeiro plano, segundo plano e ícone. Em uma RichEditBox, você pode definir as propriedades ContentLinkForegroundColor e ContentLinkBackgroundColor para alterar as cores padrão.

Você não pode definir o cursor. O cursor é renderizado pela RichEditbox com base no tipo de link de conteúdo – um cursor Pessoa para um link de pessoa ou um cursor Pin para um link de lugar.

O objeto ContentLinkInfo

Quando o usuário faz uma seleção no seletor de pessoas ou locais, o sistema cria um objeto ContentLinkInfo e o adiciona à propriedade ContentLinkInfo do atual RichEditTextRange.

O objeto ContentLinkInfo contém as informações usadas para exibir, invocar e gerenciar o link de conteúdo.

  • DisplayText – Cadeia de caracteres que é mostrada quando o link de conteúdo é renderizado. Em uma RichEditBox, o usuário pode editar o texto de um link de conteúdo após ser criado, o que altera o valor dessa propriedade.
  • SecondaryText: essa cadeia de caracteres é mostrada na tooltip de um link de conteúdo renderizado.
    • Em um link de conteúdo de lugar criado pelo seletor, ele contém o endereço da localização, se disponível.
  • URI – O link para obter mais informações sobre o assunto do link de conteúdo. Esse URI pode abrir um aplicativo instalado ou um site.
  • ID – Contador somente leitura, por controle, criado pelo controle RichEditBox. Ele é usado para acompanhar esse ContentLinkInfo durante ações como excluir ou editar. Se ContentLinkInfo for recortar e colar no controle, ele receberá uma nova ID. Valores de ID são incrementais.
  • LinkContentKind – Cadeia de caracteres que descreve o tipo de link de conteúdo. Os tipos de conteúdo internos são Locais e Contatos. O valor diferencia maiúsculas de minúsculas.

Existem várias situações em que o LinkContentKind é importante.

  • Quando um usuário copia um link de conteúdo de RichEditBox e cola em outra RichEditBox, ambos os controles devem ter um ContentLinkProvider para esse tipo de conteúdo. Caso contrário, o link é colado como texto.
  • Você pode usar LinkContentKind em um manipulador de eventos ContentLinkChanged para determinar o que fazer com um link de conteúdo quando você usá-lo em outras partes do seu aplicativo. Veja a seção Exemplo para mais informações.
  • O LinkContentKind influencia como o sistema abre o URI quando o link é invocado. Veremos isso na discussão de inicialização do URI em seguida.

Inicialização de URI

A propriedade URI funciona como a propriedade NavigateUri de um hiperlink. Quando um usuário clica nela, ela inicia o URI no navegador padrão ou no aplicativo que está registrado para o protocolo especificado no valor do URI.

O comportamento específico dos 2 tipos de conteúdo de link é descrito aqui.

Locais

O seletor de Locais cria um ContentLinkInfo com uma raiz de URI de https://maps.windows.com/. Este link pode ser aberto de 3 modos:

  • Se LinkContentKind = "Locais", ele abre um cartão de informações em um submenu. O submenu é semelhante ao submenu do seletor de link de conteúdo. Ele faz parte do Windows e é executado em um processo separado do seu aplicativo.
  • Se LinkContentKind não for "Locais", ele tenta abrir o aplicativo Mapas na localização especificada. Por exemplo, isso poderá acontecer se você tiver modificado LinkContentKind no manipulador de eventos ContentLinkChanged.
  • Se o URI não puder ser aberto no aplicativo Mapas, o mapa será aberto no navegador padrão. Isso normalmente acontece quando as configurações aplicativos para sites do usuário não permitirem abrir o URI com o aplicativo Mapas.
Pessoas

O seletor de pessoas cria um ContentLinkInfo com um URI que usa o protocolo ms-people.

  • Se LinkContentKind = "Pessoas", ele abre um cartão de informações em um submenu. O submenu é semelhante ao submenu do seletor de link de conteúdo. Ele faz parte do Windows e é executado em um processo separado do seu aplicativo.
  • Se LinkContentKind não for "People", ele abrirá o aplicativo Pessoas. Por exemplo, isso poderá acontecer se você tiver modificado LinkContentKind no manipulador de eventos ContentLinkChanged.

Dica

Para obter mais informações sobre como abrir outros aplicativos e sites de seu aplicativo, confira os tópicos em Iniciar um aplicativo com um URI.

Invocado

Quando o usuário invoca um link de conteúdo, o evento ContentLinkInvoked é acionado antes que o comportamento padrão de iniciar o URI ocorra. Você pode manipular esse evento para substituir ou cancelar o comportamento padrão.

Este exemplo mostra como você pode substituir o comportamento padrão de inicialização o de um link de conteúdo de Local. Em vez de abrir o mapa em um cartão de informações de lugar, no aplicativo Mapas ou um navegador da Web padrão, você pode marcar o evento como Handled e abrir o mapa em um controle interno de aplicativo WebView.

<RichEditBox x:Name="editor"
             ContentLinkInvoked="editor_ContentLinkInvoked">
    <RichEditBox.ContentLinkProviders>
        <ContentLinkProviderCollection>
            <PlaceContentLinkProvider/>
        </ContentLinkProviderCollection>
    </RichEditBox.ContentLinkProviders>
</RichEditBox>

<WebView x:Name="webView1"/>
private void editor_ContentLinkInvoked(RichEditBox sender, ContentLinkInvokedEventArgs args)
{
    if (args.ContentLinkInfo.LinkContentKind == "Places")
    {
        args.Handled = true;
        webView1.Navigate(args.ContentLinkInfo.Uri);
    }
}

ContentLinkChanged

Você pode usar o evento ContentLinkChanged para ser notificado quando um link de conteúdo é adicionado, modificado ou removido. Isso permite que você extraia o link de conteúdo do texto e o use em outros locais no seu aplicativo. Isto é exibido posteriormente na seção Exemplos.

As propriedades do ContentLinkChangedEventArgs são:

  • ChangedKind – Essa enumeração ContentLinkChangeKind é a ação dentro do ContentLink. Por exemplo, se o ContentLink é inserido, removido ou editado.
  • Info – ContentLinkInfo que era o destino da ação.

Esse evento é gerado para cada ação ContentLinkInfo. Por exemplo, se o usuário copia e cola vários links de conteúdo em RichEditBox ao mesmo tempo, esse evento é gerado para cada item adicionado. Ou, se o usuário seleciona e exclui vários links de conteúdo ao mesmo tempo, esse evento é gerado para cada item excluído.

Esse evento é acionado em RichEditBox após o evento TextChanging e antes do evento TextChanged.

Você pode usar a propriedade RichEditTextRange.ContentLink para obter um link de conteúdo de um documento de edição. A enumeração TextRangeUnit tem o valor ContentLink para especificar o link de conteúdo como uma unidade para usar ao navegar em um intervalo de texto.

Este exemplo mostra como você pode enumerar todos os links de conteúdo em uma RichEditBox e extrair as pessoas em uma lista.

<StackPanel Width="300">
    <RichEditBox x:Name="Editor" Height="200">
        <RichEditBox.ContentLinkProviders>
            <ContentLinkProviderCollection>
                <ContactContentLinkProvider/>
                <PlaceContentLinkProvider/>
            </ContentLinkProviderCollection>
        </RichEditBox.ContentLinkProviders>
    </RichEditBox>

    <Button Content="Get people" Click="Button_Click"/>

    <ListView x:Name="PeopleList" Header="People">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="ContentLinkInfo">
                <TextBlock>
                    <ContentLink Info="{x:Bind}" Background="Transparent"/>
                </TextBlock>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackPanel>
private void Button_Click(object sender, RoutedEventArgs e)
{
    PeopleList.Items.Clear();
    RichEditTextRange textRange = Editor.Document.GetRange(0, 0) as RichEditTextRange;

    do
    {
        // The Expand method expands the Range EndPosition 
        // until it finds a ContentLink range. 
        textRange.Expand(TextRangeUnit.ContentLink);
        if (textRange.ContentLinkInfo != null
            && textRange.ContentLinkInfo.LinkContentKind == "People")
        {
            PeopleList.Items.Add(textRange.ContentLinkInfo);
        }
    } while (textRange.MoveStart(TextRangeUnit.ContentLink, 1) > 0);
}

Para usar um link de conteúdo em um controle TextBlock ou RichTextBlock, use o elemento de texto ContentLink (no namespace Windows.UI.Xaml.Documents).

Fontes típicas para um ContentLink em um bloco de texto são:

  • Um link de conteúdo criado por um seletor extraído de um controle RichTextBlock.
  • Um link de conteúdo para um local que você criar no seu código.

Para outras situações, um elemento de texto de hiperlink é geralmente apropriado.

A aparência de um link de conteúdo é determinada pelo seu primeiro plano, segundo plano e cursor. Em um bloco de texto, você pode definir as propriedades Foreground (no TextElement) e Background para alterar as cores padrão.

Por padrão, o cursor Mão é mostrado quando o usuário passa sobre o link de conteúdo. Ao contrário de RichEditBlock, controles de bloco de texto não mudam o cursor automaticamente com base no tipo de link. Você pode definir a propriedade Cursor para alterar o cursor com base no tipo de link ou outros fatores.

Veja um exemplo de um ContentLink usado em um TextBlock. O ContentLinkInfo é criado no código e atribuído à propriedade Info do elemento de texto ContentLink que é criado em XAML.

<StackPanel>
    <TextBlock>
        <Span xml:space="preserve">
            <Run>This volcano erupted in 1980: </Run><ContentLink x:Name="placeContentLink" Cursor="Pin"/>
            <LineBreak/>
        </Span>
    </TextBlock>

    <Button Content="Show" Click="Button_Click"/>
</StackPanel>
private void Button_Click(object sender, RoutedEventArgs e)
{
    var info = new Windows.UI.Text.ContentLinkInfo();
    info.DisplayText = "Mount St. Helens";
    info.SecondaryText = "Washington State";
    info.LinkContentKind = "Places";
    info.Uri = new Uri("https://maps.windows.com?cp=46.1912~-122.1944");
    placeContentLink.Info = info;
}

Dica

Quando você usa um ContentLink em um controle de texto com outros elementos de texto no XAML, coloque o conteúdo em um contêiner Span e aplicar o atributo xml:space="preserve" para manter o espaço em branco entre o ContentLink e os outros elementos.

Exemplos

Neste exemplo, um usuário pode inserir um link de conteúdo de pessoa ou lugar em um RickTextBlock. Manipule o evento ContentLinkChanged para extrair os links de conteúdo e mantê-los atualizados em uma lista de pessoas ou lista de locais.

Nos modelos de item para as listas, você usa um TextBlock com um elemento de texto ContentLink para mostrar as informações de link de conteúdo. O ListView fornece sua própria tela de fundo para cada item, para que a tela de fundo ContentLink está definida como Transparent.

<StackPanel Orientation="Horizontal" Grid.Row="1">
    <RichEditBox x:Name="Editor"
                 ContentLinkChanged="Editor_ContentLinkChanged"
                 Margin="20" Width="300" Height="200"
                 VerticalAlignment="Top">
        <RichEditBox.ContentLinkProviders>
            <ContentLinkProviderCollection>
                <ContactContentLinkProvider/>
                <PlaceContentLinkProvider/>
            </ContentLinkProviderCollection>
        </RichEditBox.ContentLinkProviders>
    </RichEditBox>

    <ListView x:Name="PeopleList" Header="People">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="ContentLinkInfo">
                <TextBlock>
                    <ContentLink Info="{x:Bind}"
                                 Background="Transparent"
                                 Cursor="Person"/>
                </TextBlock>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

    <ListView x:Name="PlacesList" Header="Places">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="ContentLinkInfo">
                <TextBlock>
                    <ContentLink Info="{x:Bind}"
                                 Background="Transparent"
                                 Cursor="Pin"/>
                </TextBlock>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackPanel>
private void Editor_ContentLinkChanged(RichEditBox sender, ContentLinkChangedEventArgs args)
{
    var info = args.ContentLinkInfo;
    var change = args.ChangeKind;
    ListViewBase list = null;

    // Determine whether to update the people or places list.
    if (info.LinkContentKind == "People")
    {
        list = PeopleList;
    }
    else if (info.LinkContentKind == "Places")
    {
        list = PlacesList;
    }

    // Determine whether to add, delete, or edit.
    if (change == ContentLinkChangeKind.Inserted)
    {
        Add();
    }
    else if (args.ChangeKind == ContentLinkChangeKind.Removed)
    {
        Remove();
    }
    else if (change == ContentLinkChangeKind.Edited)
    {
        Remove();
        Add();
    }

    // Add content link info to the list. It's bound to the
    // Info property of a ContentLink in XAML.
    void Add()
    {
        list.Items.Add(info);
    }

    // Use ContentLinkInfo.Id to find the item,
    // then remove it from the list using its index.
    void Remove()
    {
        var items = list.Items.Where(i => ((ContentLinkInfo)i).Id == info.Id);
        var item = items.FirstOrDefault();
        var idx = list.Items.IndexOf(item);

        list.Items.RemoveAt(idx);
    }
}