テキスト制御のコンテンツ リンク

コンテンツ リンクにより、テキスト コントロールにリッチ データを埋め込むことができます。これによってユーザーは、アプリのコンテキストから離れることなく、人物や場所に関する詳しい情報を見つけることができます。

重要

コンテンツ リンクを可能にする Windows の機能は、Windows 10 バージョン 1903 より後のバージョンの Windows では利用できません。 XAML テキスト コントロールのコンテンツ リンクは、バージョン 1903 より後のバージョンの Windows では機能しません。

RichEditBox でユーザーがアット マーク (@) を使用してエントリにプレフィックスを付けると、そのエントリに一致する人々および/または場所の候補のリストが表示されます。 たとえば、ユーザーが場所を選択すると、その場所の ContentLink がテキストに挿入されます。 ユーザーが RichEditBox からコンテンツ リンクを呼び出すと、ポップアップがマップと場所に関する追加情報と共に表示されます。

重要な API: ContentLink クラスContentLinkInfo クラスRichEditTextRange クラス

Note

コンテンツ リンクの API は、Windows.UI.Xaml.Controls、Windows.UI.Xaml.Documents、Windows.UI.Text の各名前空間に分散されます。

コンテンツ リンクを使用するには、次の 2 つの異なる方法があります。

  1. RichEditBox では、ユーザーはピッカーを開き、テキストの前に @ 記号を付けることでコンテンツ リンクを追加できます。 コンテンツ リンクは、リッチ テキスト コンテンツの一部として格納されます。
  2. TextBlock または RichTextBlock では、コンテンツ リンクはハイパーリンクと同様の使用法と動作を持つテキスト要素です。

RichEditBox と TextBlock のコンテンツ リンクの既定の外観を次に示します。

content link in rich edit boxcontent link in text block

使用方法、レンダリング、動作の違いについては、次のセクションで詳しく説明します。 次の表は、RichEditBox のコンテンツ リンクとテキスト ブロックのメインの違いを簡単に比較したものです。

機能 RichEditBox テキスト ブロック
使用方法 ContentLinkInfo のインスタンス ContentLink テキスト要素
Cursor コンテンツ リンクの種類によって決まる、変更できません Cursor プロパティによって決定され、既定では null です
ToolTip レンダリングされていない セカンダリ テキストを表示する

コンテンツ リンクの最も一般的な用途は、ユーザーがテキストにアンパサンド (@) 記号を付けることで、ユーザーに情報をすばやく追加できるようにすることです。 RichEditBox で有効にすると、ピッカーが開き、ユーザーは、有効にした内容に応じて、連絡先リストまたは近くの場所からユーザーを挿入できます。

コンテンツ リンクはリッチ テキスト コンテンツと共に保存でき、それを抽出してアプリの他の部分で使用できます。 たとえば、メール アプリでは、ユーザー情報を抽出し、それを使用して [宛先] ボックスにメール アドレスを設定できます。

Note

コンテンツ リンク ピッカーは Windows の一部であるアプリであるため、アプリとは別のプロセスで実行されます。

RichEditBox でコンテンツ リンクを有効にするには、1 つ以上のコンテンツ リンク プロバイダーを RichEditBox.ContentLinkProviders コレクションに追加します。 XAML フレームワークには、2 つのコンテンツ リンク プロバイダーが組み込まれています。

重要

RichEditBox.ContentLinkProviders プロパティの既定値は null であり、空のコレクションではありません。 コンテンツ リンク プロバイダーを追加する前に、ContentLinkProviderCollection を明示的に作成する必要があります。

XAML でコンテンツ リンク プロバイダーを追加する方法を次に示します。

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

このように、スタイルにコンテンツ リンク プロバイダーを追加し、それを複数の RichEditBox に適用することもできます。

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

コードでコンテンツ リンク プロバイダーを追加する方法を次に示します。

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

コンテンツ リンクの外観は、前景、背景、アイコンによって決まります。 RichEditBox では、ContentLinkForegroundColor プロパティと ContentLinkBackgroundColor プロパティを設定して、既定の色を変更できます。

カーソルを設定することはできません。 カーソルは、コンテンツ リンクの種類 (人物リンクの場合は Person カーソル、場所リンクの場合はピン カーソル) に基づいて RichEditbox によってレンダリングされます。

ContentLinkInfo オブジェクト

ユーザーがユーザーまたは場所の選択ウィンドウから選択を行うと、システムによって ContentLinkInfo オブジェクトが作成され、現在の RichEditTextRangeContentLinkInfo プロパティに追加されます。

ContentLinkInfo オブジェクトには、コンテンツ リンクの表示、呼び出し、管理に使用される情報が含まれています。

  • DisplayText – コンテンツ リンクがレンダリングされるときに表示される文字列です。 RichEditBox では、ユーザーはコンテンツ リンクの作成後にテキストを編集できます。これにより、このプロパティの値が変更されます。
  • SecondaryText – この文字列は、レンダリングされたコンテンツ リンクのツールチップに表示されます。
    • ピッカーによって作成された [場所] コンテンツ リンクには、場所のアドレス (使用可能な場合) が含まれます。
  • Uri – コンテンツ リンクの件名に関する詳細情報へのリンク。 この URI は、インストールされているアプリまたは Web サイトを開くことができます。
  • Id - これは、RichEditBox コントロールによって作成された、コントロールごとの読み取り専用のカウンターです。 これは、削除や編集などのアクション中にこの ContentLinkInfo を追跡するために使用されます。 ContentLinkInfo が切り取られてコントロールに貼り付けられると、新しい Id が取得されます。ID 値は増分されます。
  • LinkContentKind – コンテンツ リンクの種類を記述する文字列。 組み込みのコンテンツ タイプは、 場所連絡先です。 この値は大文字と小文字の区別があります。

LinkContentKind が重要となる状況がいくつかあります。

  • ユーザーが RichEditBox からコンテンツ リンクをコピーして別の RichEditBox に貼り付ける場合、両方のコントロールにそのコンテンツ タイプの ContentLinkProvider が必要です。 そうでない場合、リンクはテキストとして貼り付けられます。
  • ContentLinkChanged イベント ハンドラーで LinkContentKind を使用して、アプリの他の部分でコンテンツ リンクを使用する場合のコンテンツ リンクの操作を決定できます。 詳細については、「例」のセクションを参照してください。
  • LinkContentKind は、リンクが呼び出されたときにシステムが URI を開く方法に影響します。 これは、次に起動する URI の説明で確認できます。

URI の起動

Uri プロパティは、ハイパーリンクの NavigateUri プロパティと類似しています。 ユーザーがクリックすると、既定のブラウザーまたは Uri 値で指定された特定のプロトコルに登録されているアプリで URI が起動されます。

ここでは、組み込まれている 2 種類のリンク コンテンツの具体的な動作について説明します。

場所

Places ピッカーは、https://maps.windows.com/ の Uri ルートを使用して ContentLinkInfo を作成します。 このリンクは、次の 3 つの方法で開くことができます。

  • LinkContentKind = "Places" の場合は、ポップアップにカード情報が開きます。 ポップアップは、コンテンツ リンク ピッカーのポップアップに類似しています。 これは Windows の一部であり、アプリとは別のプロセスで実行されます。
  • LinkContentKind が "Places" でない場合は、指定した場所に Maps アプリを開こうとします。 たとえば、これは、ContentLinkChanged イベント ハンドラーで LinkContentKind を変更した場合に発生する可能性があります。
  • Maps アプリで URI を開くことができない場合、マップは既定のブラウザーで開かれます。 これは通常、ユーザーの [Web サイト用アプリ] 設定で、マップ アプリで URI を開くことができない場合に発生します。
ユーザー

People ピッカーは、ms-people プロトコルを使用する URI を持つ ContentLinkInfo を作成します。

  • LinkContentKind = "People" の場合は、ポップアップにカード情報が開きます。 ポップアップは、コンテンツ リンク ピッカーのポップアップに類似しています。 これは Windows の一部であり、アプリとは別のプロセスで実行されます。
  • LinkContentKind が "People" でない場合は、People アプリが開きます。 たとえば、これは、ContentLinkChanged イベント ハンドラーで LinkContentKind を変更した場合に発生する可能性があります。

ヒント

アプリから他のアプリや Web サイトを開く方法の詳細については、「URI を使ったアプリの起動」の下にあるトピックを参照してください。

呼び出された

ユーザーがコンテンツ リンクを呼び出すと、Uri を起動する既定の 動作が発生する前に ContentLinkInvoked イベントが発生します。 このイベントを処理して、既定の動作をオーバーライドまたは取り消すことができます。

この例では、Place コンテンツ リンクの既定の起動動作をオーバーライドする方法を示します。 場所情報カード、マップ アプリ、または既定の Web ブラウザーでマップを開くのではなく、イベントを Handled としてマークし、アプリ内 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

ContentLinkChanged イベントを使用すると、コンテンツ リンクが追加、変更、または削除されたときに通知を受け取ることができます。 これにより、テキストからコンテンツ リンクを抽出し、アプリ内の他の場所で使用できます。 これについては、後の「例」セクションで説明します。

ContentLinkChangedEventArgs のプロパティ:

  • ChangedKind - この ContentLinkChangeKind 列挙型は ContentLink 内のアクションです。 たとえば、ContentLink が挿入、削除、または編集された場合です。
  • Info - アクションのターゲットである ContentLinkInfo。

このイベントは、ContentLinkInfo アクションごとに発生します。 たとえば、ユーザーが複数のコンテンツ リンクを一度にコピーして RichEditBox に貼り付けると、追加された項目ごとにこのイベントが発生します。 または、ユーザーが複数のコンテンツ リンクを同時に選択して削除すると、削除されたアイテムごとにこのイベントが発生します。

このイベントは、TextChanging イベントの後、および TextChanged イベントの前に RichEditBox で発生します。

RichEditTextRange.ContentLink プロパティを使用すると、リッチ エディット ドキュメントからコンテンツ リンクを取得できます。 TextRangeUnit 列挙には、テキスト範囲を移動するときに使用する単位としてコンテンツ リンクを指定する ContentLink 値があります。

この例では、RichEditBox 内のすべてのコンテンツ リンクを列挙し、ユーザーをリストに抽出する方法を示します。

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

TextBlock または RichTextBlock コントロールでコンテンツ リンクを使用するには、(Windows.UI.Xaml.Documents 名前空間の) ContentLink テキスト要素を使用します。

テキスト ブロック内の ContentLink の一般的なソースは次のとおりです。

  • RichTextBlock コントロールから抽出したピッカーによって作成されたコンテンツ リンク。
  • コードで作成する場所のコンテンツ リンク。

その他の状況では、通常、Hyperlink テキスト要素が適しています。

コンテンツ リンクの外観は、前景、背景、カーソルによって決まります。 テキスト ブロックでは、Foreground (TextElement から) プロパティと Background プロパティを設定して、既定の色を変更できます。

既定では、ユーザーがコンテンツ リンクの上にマウス ポインターを置くと、ハンド カーソルが表示されます。 RichEditBlock とは異なり、テキスト ブロック コントロールはリンクの種類に基づいてカーソルを自動的に変更しません。 Cursor プロパティを設定すると、リンクの種類やその他の要因に基づいてカーソルを変更できます。

TextBlock で使用される ContentLink の例を次に示します。 ContentLinkInfo はコードで作成され、XAML で作成された ContentLink テキスト要素の Info プロパティに割り当てられます。

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

ヒント

テキスト コントロールで ContentLink を XAML のその他のテキスト要素と一緒に使用する場合、スパン コンテナーにコンテンツを配置してスパンに xml:space="preserve" 属性を適用すると、ContentLink とその他の要素間に空白を保持します。

この例では、ユーザーはユーザーを入力したり、コンテンツ リンクを RickTextBlock に配置したりできます。 ContentLinkChanged イベントを処理してコンテンツ リンクを抽出し、ユーザーリストまたは場所リストで最新の状態に保ちます。

リストの項目テンプレートでは、ContentLink テキスト要素と共に TextBlock を使用してコンテンツ リンク情報を表示します。 ListView は項目ごとに独自の背景を提供するため、ContentLink の背景は透明に設定されます。

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