Collegamenti a contenuto nei controlli di testo

I collegamenti a contenuto consentono di incorporare dati complessi nei controlli di testo, permettendo così agli utenti di trovare e usare altre informazioni su una persona o un luogo senza uscire dal contesto dell'app.

Importante

Le funzionalità di Windows che abilitano i collegamenti al contenuto non sono disponibili nelle versioni di Windows successive a Windows 10 versione 1903. I collegamenti al contenuto per i controlli di testo XAML non funzioneranno nelle versioni di Windows successive alla 1903.

Quando l'utente antepone il simbolo della chiocciola (@) ai dati immessi in un controllo RichEditBox, viene visualizzato un elenco di suggerimenti di persone e/o luoghi corrispondenti. Quando l'utente seleziona un luogo, ad esempio, nel testo viene quindi inserito un elemento ContentLink per tale luogo. Quando l'utente richiama il collegamento a contenuto da RichEditBox, viene visualizzato un riquadro a comparsa con una mappa e informazioni aggiuntive sul luogo.

API importanti: Classe ContentLink, Classe ContentLinkInfo, Classe RichEditTextRange

Nota

Le API per i collegamenti di contenuto vengono distribuite negli spazi dei nomi seguenti: Windows.UI.Xaml.Controls, Windows.UI.Xaml.Documents e Windows.UI.Text.

Sono disponibili due modi diversi per usare i collegamenti a contenuto:

  1. In RichEditBox, l'utente può aprire una selezione per aggiungere un collegamento a contenuto anteponendo un simbolo @ al testo. Il collegamento a contenuto viene archiviato come parte del contenuto RTF.
  2. In TextBlock o RichTextBlock, il collegamento a contenuto è un elemento di testo con utilizzo e comportamento simili a un elemento Hyperlink.

Ecco l'aspetto predefinito dei collegamenti a contenuto in RichEditBox e in TextBlock.

content link in rich edit boxcontent link in text block

Le differenze nell'utilizzo, nel rendering e nel comportamento sono descritte in dettaglio nelle sezioni seguenti. Questa tabella offre un rapido confronto delle principali differenze tra un collegamento a contenuto in un controllo RichEditBox e in un blocco di testo.

Funzionalità RichEditBox Blocco di testo
Utilizzo Istanza di ContentLinkInfo Elemento di testo ContentLink
Cursore Dipende dal tipo di collegamento a contenuto e non è modificabile Dipende dalla proprietà Cursor e per impostazione predefinita è null
ToolTip Il rendering non viene eseguito Mostra il testo secondario

Un collegamento a contenuto viene generalmente usato per consentire a un utente di aggiungere rapidamente informazioni anteponendo il simbolo @ al nome di una persona o di un luogo nel testo. Quando è abilitato in RichEditBox, apre una selezione e consente all'utente di inserire una persona dall'elenco dei contatti o un luogo nelle vicinanze, a seconda della funzionalità che hai abilitato.

Il collegamento a contenuto può essere salvato con il contenuto RTF ed essere estratto per essere usato in altre parti dell'app. In un'app di posta elettronica, ad esempio, potresti estrarre le informazioni sulla persona e usarle per popolare la casella A con un indirizzo di posta elettronica.

Nota

La selezione del collegamento a contenuto è un'app che fa parte di Windows e viene quindi eseguita in un processo separato rispetto alla tua app.

Per abilitare i collegamenti a contenuto in un controllo RichEditBox, aggiungi uno o più provider di collegamenti a contenuto alla raccolta RichEditBox.ContentLinkProviders. Nel framework XAML sono disponibili 2 provider di collegamenti a contenuto predefiniti.

Importante

Il valore predefinito per la proprietà RichEditBox.ContentLinkProviders è null, non una raccolta vuota. Prima di aggiungere provider di collegamenti a contenuto, devi creare esplicitamente ContentLinkProviderCollection.

Ecco come aggiungere i provider di collegamenti a contenuto in XAML.

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

Puoi anche aggiungere i provider di collegamenti a contenuto in uno stile e applicarlo a più controlli RichEditBox come mostrato di seguito.

<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}" />

Ecco come aggiungere provider di collegamenti a contenuto nel codice.

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

L'aspetto di un collegamento a contenuto dipende da primo piano, sfondo e icona. In un controllo RichEditBox puoi modificare i colori predefiniti impostando le proprietà ContentLinkForegroundColor e ContentLinkBackgroundColor.

Non puoi impostare il cursore. Il rendering del cursore viene eseguito da RichEditbox in base al tipo di collegamento a contenuto: cursore Person per un collegamento a una persona o cursore Pin per un collegamento a un luogo.

Oggetto ContentLinkInfo

Quando l'utente effettua una scelta nella selezione contatti o luoghi, il sistema crea un oggetto ContentLinkInfo e lo aggiunge alla proprietà ContentLinkInfo dell'oggetto RichEditTextRange corrente.

L'oggetto ContentLinkInfo contiene le informazioni usate per visualizzare, richiamare e gestire il collegamento a contenuto.

  • DisplayText: stringa visualizzata quando viene eseguito il rendering del collegamento a contenuto. In un controllo RichEditBox l'utente può modificare il testo di un collegamento a contenuto dopo che è stato creato, modificando così il valore di questa proprietà.
  • SecondaryText: stringa visualizzata nella descrizione comando di un collegamento a contenuto sottoposto a rendering.
    • In un collegamento a contenuto di tipo luogo creato dalla selezione contiene l'indirizzo del luogo, se disponibile.
  • Uri: collegamento ad altre informazioni sull'oggetto del collegamento a contenuto. Questo URI può aprire un'app installata o un sito Web.
  • Id: contatore di sola lettura per ogni singolo controllo, creato dal controllo RichEditBox. Viene usato per tenere traccia di ContentLinkInfo durante azioni come l'eliminazione o la modifica. Se ContentLinkInfo viene tagliato e re-incollato nel controllo, ottiene un nuovo ID. I valori ID sono incrementali.
  • LinkContentKind: stringa che descrive il tipo di collegamento a contenuto. I tipi di contenuto predefiniti sono Places e People. Per il valore viene fatta distinzione tra maiuscole e minuscole.

LinkContentKind è importante in diverse situazioni.

  • Quando un utente copia un collegamento a contenuto da RichEditBox e lo incolla in un altro controllo RichEditBox, entrambi i controlli devono avere un ContentLinkProvider per tale tipo di contenuto. In caso contrario, il collegamento viene incollato come testo.
  • Puoi usare LinkContentKind in un gestore dell'evento ContentLinkChanged per determinare l'operazione da eseguire con un collegamento a contenuto quando lo usi in altre parti dell'app. Per altre informazioni, vedi la sezione Esempi.
  • LinkContentKind influisce sul modo in cui il sistema pare l'URI quando viene richiamato il collegamento. L'argomento verrà approfondito nella discussione sull'avvio di URI che segue.

Avvio di URI

La proprietà Uri è molto simile alla proprietà NavigateUri di un elemento Hyperlink. Quando un utente fa clic, l'URI viene avviato nel browser predefinito o nell'app registrata per il protocollo specificato nel valore di Uri.

Il comportamento specifico per i 2 tipi predefiniti di contenuto del collegamento è descritto di seguito.

Effettua

La selezione luoghi crea un controllo ContentLinkInfo con radice dell'URI https://maps.windows.com/. Questo collegamento può essere aperto in 3 modi:

  • Se LinkContentKind = "Places", viene aperta una scheda informazioni in un riquadro a comparsa. Il riquadro a comparsa è simile a quello della selezione del collegamento a contenuto. Fa parte di Windows e viene eseguito in un processo separato rispetto alla tua app.
  • Se LinkContentKind è diverso da "Places", viene tentata l'apertura dell'app Mappe alla posizione specificata. Questa situazione può verificarsi, ad esempio, se hai modificato LinkContentKind nel gestore dell'evento ContentLinkChanged.
  • Se l'URI non può essere aperto nell'app Mappe, la mappa viene aperta nel browser predefinito. Questo in genere accade quando le impostazioni App per siti Web dell'utente non consentono l'apertura dell'URI con l'app Mappe.
Persone

La selezione contatti crea un controllo ContentLinkInfo con un URI che usa il protocollo ms-people.

  • Se LinkContentKind = "People", viene aperta una scheda informazioni in un riquadro a comparsa. Il riquadro a comparsa è simile a quello della selezione del collegamento a contenuto. Fa parte di Windows e viene eseguito in un processo separato rispetto alla tua app.
  • Se LinkContentKind è diverso da "People", viene aperta l'app Contatti. Questa situazione può verificarsi, ad esempio, se hai modificato LinkContentKind nel gestore dell'evento ContentLinkChanged.

Suggerimento

Per altre informazioni sull'apertura di altre app e siti Web dall'app, vedi gli argomenti in Avviare un'app con un URI.

Chiamata

Quando l'utente richiama un collegamento a contenuto, l'evento ContentLinkInvoked viene generato prima del comportamento predefinito di avvio dell'URI. Puoi gestire questo evento per annullare il comportamento predefinito o eseguirne l'override.

Questo esempio mostra come puoi eseguire l'override del comportamento di avvio predefinito per un collegamento a contenuto di tipo luogo. Invece di aprire la mappa in una scheda informazioni relativa al luogo, nell'app Mappe o nel Web browser predefinito, contrassegna l'evento come gestito e apri la mappa in un controllo WebView in-app.

<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

Puoi usare l'evento ContentLinkChanged per ricevere una notifica quando viene aggiunto, modificato o rimosso un collegamento a contenuto. Ciò consente di estrarre il collegamento a contenuto dal testo e usarlo in altre posizioni dell'app, come illustrato più avanti nella sezione Esempi.

Di seguito sono illustrate le proprietà di ContentLinkChangedEventArgs.

  • ChangedKind: enumerazione ContentLinkChangeKind contenente l'azione all'interno di ContentLink, ad esempio l'inserimento, la rimozione o la modifica di ContentLink.
  • Info: controllo ContentLinkInfo destinazione dell'azione.

Questo evento viene generato per ogni azione su ContentLinkInfo. Se l'utente copia e incolla contemporaneamente diversi collegamenti a contenuto in RichEditBox, ad esempio, questo evento viene generato per ogni elemento aggiunto. Se invece l'utente seleziona ed elimina contemporaneamente diversi collegamenti a contenuto, l'evento viene generato per ogni elemento eliminato.

Questo evento viene generato in RichEditBox dopo l'evento TextChanging e prima dell'evento TextChanged.

Puoi usare la proprietà RichEditTextRange.ContentLink per ottenere un collegamento a contenuto da un documento di modifica RTF. Il valore ContentLink dell'enumerazione TextRangeUnit consente di specificare il collegamento a contenuto come un'unità da usare durante lo spostamento in un intervallo di testo.

Questo esempio mostra come enumerare tutti i collegamenti a contenuto in un controllo RichEditBox ed estrarre i contatti in un elenco.

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

Per usare un collegamento a contenuto in un controllo TextBlock o RichTextBlock, usa l'elemento di testo ContentLink dallo spazio dei nomi Windows.UI.Xaml.Documents.

Le origini di un controllo ContentLink in un blocco di testo sono in genere le seguenti:

  • Un collegamento a contenuto creato da una selezione ed estratto da un controllo RichTextBlock.
  • Un collegamento a contenuto per un luogo creato nel codice.

Per altre situazioni è in genere appropriato un elemento di testo Hyperlink.

L'aspetto di un collegamento a contenuto dipende da primo piano, sfondo e cursore. In un blocco di testo puoi modificare i colori predefiniti impostando le proprietà Foreground (da TextElement) e Background.

Per impostazione predefinita, quando l'utente passa il puntatore sul collegamento a contenuto viene visualizzato il cursore Hand. A differenza di RichEditBlock, i controlli blocco di testo non cambiano automaticamente il cursore in base al tipo di collegamento. Puoi impostare la proprietà Cursor per modificare il cursore in base al tipo di collegamento o ad altri fattori.

Ecco un esempio di ContentLink usato in TextBlock. ContentLinkInfo viene creato nel codice e assegnato alla proprietà Info dell'elemento di testo ContentLink creato in 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;
}

Suggerimento

Quando usi ContentLink in un controllo di testo con altri elementi di testo in XAML, inserisci il contenuto in un contenitore Span e applica l'attributo xml:space="preserve" a Span per mantenere lo spazio vuoto tra ContentLink e gli altri elementi.

Esempi

In questo esempio, un utente può inserire un collegamento a contenuto di tipo persona o luogo in un controllo RickTextBlock. L'evento ContentLinkChanged viene gestito per estrarre i collegamenti a contenuto e mantenerli aggiornati in un elenco di contatti o di luoghi.

Nei modelli di elemento per gli elenchi, usa un controllo TextBlock con un elemento di testo ContentLink per visualizzare le informazioni relative al collegamento a contenuto. Dato che lo sfondo per ogni elemento è fornito da ListView, lo sfondo di ContentLink viene impostato su 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);
    }
}