テキスト コントロールのコンテンツ リンクContent links in text controls

コンテンツ リンクを使用すると、テキスト コントロールにリッチ データを埋め込むことができます。これによってユーザーは、アプリのコンテキストから離れることなく、人物や場所に関する詳しい情報を見つけることができます。Content links provide a way to embed rich data in your text controls, which lets a user find and use more information about a person or place without leaving the context of your app.

RichEditBox でユーザーがアンパサンド (@) 記号を使用してエントリにプレフィックスを付けると、そのエントリに一致する人々および/または場所の候補のリストが表示されます。When the user prefixes an entry with an ampersand (@) symbol in a RichEditBox, they’re shown a list of people and/or place suggestions that matches the entry. 次に、たとえば、ユーザーが場所を選択すると、その場所の ContentLink がテキストに挿入されます。Then, for example, when the user picks a place, a ContentLink for that place is inserted into the text. ユーザーが RichEditBox からコンテンツ リンクを呼び出すと、その場所に関する地図と追加情報を示したポップアップが表示されます。When the user invokes the content link from the RichEditBox, a flyout is shown with a map and additional info about the place.

重要な API:ContentLink クラスContentLinkInfo クラスRichEditTextRange クラスImportant APIs: ContentLink class, ContentLinkInfo class, RichEditTextRange class

注意

コンテンツ リンク用の API は、次の名前空間にまたがっています。Windows.UI.Xaml.Controls、Windows.UI.Xaml.Documents、Windows.UI.Text。The APIs for content links are spread across the following namespaces: Windows.UI.Xaml.Controls, Windows.UI.Xaml.Documents, and Windows.UI.Text.

コンテンツ リンクを使用する方法には、以下の 2 種類があります。There are two distinct ways to use content links:

  1. RichEditBox では、ユーザーはピッカーを開いてテキストの先頭に @ 記号を付けて指定し、コンテンツ リンクを追加できます。In a RichEditBox, the user can open a picker to add a content link by prefixing text with an @ symbol. コンテンツ リンクは、リッチ テキスト コンテンツの一部として保存されます。The content link is stored as part the rich text content.
  2. TextBlock または RichTextBlock では、コンテンツ リンクは、使用法や動作がハイパーリンクとよく似たテキスト要素です。In a TextBlock or RichTextBlock, the content link is a text element with usage and behavior much like a Hyperlink.

既定でコンテンツ リンクが RichEditBox と TextBlock でどのように表示されるかを示します。Here's how content links look by default in a RichEditBox and in a TextBlock.

リッチ エディット ボックスでのコンテンツ リンク テキスト ブロックでのコンテンツ リンクcontent link in rich edit box content link in text block

使用状況、レンダリング、および動作の相違点については、次のセクションで詳しく説明します。Differences in usage, rendering, and behavior are covered in detail in the following sections. 次の表は、RichEditBox のコンテンツ リンクとテキスト ブロックの主な相違点を比較した早見表です。This table gives a quick comparison of the main differences between a content link in a RichEditBox and a text block.

機能Feature RichEditBoxRichEditBox テキスト ブロックtext block
使用方法Usage ContentLinkInfo インスタンスContentLinkInfo instance ContentLink テキスト要素ContentLink text element
CursorCursor コンテンツ リンクの種類によって決まり、変更することはできませんDetermined by type of content link, can't be changed Cursor プロパティによって決まります。既定では null ですDetermined by Cursor property, null by default
ToolTipToolTip 表示されませんNot rendered セカンダリ テキストを表示しますShows secondary text

コンテンツ リンクの最も一般的な用途は、ユーザーがテキスト内の人物または場所の名前の先頭にアンパサンド (@) 記号を付けることによって、情報をすばやく追加できるようにすることです。The most common use of a content link is to let a user quickly add information by prefixing a person or place name with an ampersand (@) symbol in their text. RichEditBox で有効になっている場合、ピッカーが開き、ユーザーは有効にした内容に応じて、連絡先リストまたは近くの場所から人物を挿入できます。When enabled in a RichEditBox, this opens a picker and lets the user insert a person from their contact list, or a nearby place, depending on what you’ve enabled.

コンテンツ リンクは、リッチ テキスト コンテンツで保存でき、抽出してアプリの他の部分で使用することができます。The content link can be saved with the rich text content, and you can extract it to use in other parts of your app. たとえば、メール アプリで個人情報を抽出し、それを使用して [終了] ボックスにメール アドレスを設定することができます。For example, in an email app, you might extract the person info and use it to populate the To box with an email address.

注意

コンテンツ リンク ピッカーは、Windows の一部であるアプリであるため、アプリと別のプロセスで実行されます。The content link picker is an app that’s part of Windows, so it runs in a separate process from your app.

RichEditBox でコンテンツ リンクを有効にするには、1 つまたは複数のコンテンツ リンク プロバイダーを RichEditBox.ContentLinkProviders コレクションに追加します。You enable content links in a RichEditBox by adding one or more content link providers to the RichEditBox.ContentLinkProviders collection. XAML フレームワークに組み込まれているコンテンツ リンク プロバイダーが 2 つあります。There are 2 content link providers built into the XAML framework.

重要

RichEditBox.ContentLinkProviders プロパティの既定値は null であり、空のコレクションではありません。The default value for the RichEditBox.ContentLinkProviders property is null, not an empty collection. コンテンツ リンク プロバイダーを追加する前に、ContentLinkProviderCollection を明示的に作成する必要があります。You need to explicity create the ContentLinkProviderCollection before you add content link providers.

XAML でコンテンツ リンク プロバイダーを追加する方法を示します。Here’s how to add the content link providers in XAML.

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

スタイルにコンテンツ リンク プロバイダーを追加し、次のように複数の RichEditBoxes に適用することもできます。You can also add content link providers in a Style and apply it to multiple RichEditBoxes like this.

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

コードでコンテンツ リンク プロバイダーを追加する方法を示します。Here's how to add content link providers in code.

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

コンテンツ リンクの外観は、フォアグラウンド、バックグラウンド、およびアイコンによって決まります。The appearance of a content link is determined by its foreground, background, and icon. RichEditBox で、ContentLinkForegroundColor プロパティおよび ContentLinkBackgroundColor プロパティを設定して既定の色を変更できます。In a RichEditBox, you can set the ContentLinkForegroundColor and ContentLinkBackgroundColor properties to change the default colors.

カーソルを設定することはできません。You can't set the cursor. カーソルは、コンテンツ リンクの種類に基づいて RichEditbox によって表示されます (ユーザー リンクの場合はユーザー カーソル、場所リンクの場合はピン カーソル)。The cursor is rendered by the RichEditbox based on the type of content link - a Person cursor for a person link, or a Pin cursor for a place link.

ContentLinkInfo オブジェクトThe ContentLinkInfo object

ユーザーがユーザー ピッカーまたは場所ピッカーから選択すると、システムは ContentLinkInfo オブジェクトを作成し、それを現在の RichEditTextRangeContentLinkInfo プロパティに追加します。When the user makes a selection from the people or places picker, the system creates a ContentLinkInfo object and adds it to the ContentLinkInfo property of the current RichEditTextRange.

ContentLinkInfo オブジェクトには、コンテンツ リンクを表示、起動、および管理するための情報が含まれています。The ContentLinkInfo object contains the information used to display, invoke, and manage the content link.

  • DisplayText– これは、コンテンツ リンクが表示されるときに表示される文字列です。DisplayText – This is the string that is shown when the content link is rendered. RichEditBox では、ユーザーはコンテンツ リンクを作成後にそのテキストを編集することができます。これにより、このプロパティの値が変更されます。In a RichEditBox, the user can edit the text of a content link after it’s created, which alters the value of this property.
  • SecondaryText – この文字列は、表示されたコンテンツ リンクのヒントに表示されます。SecondaryText – This string is shown in the ToolTip of a rendered content link.
    • ピッカーによって作成された Place コンテンツ リンクでは、使用可能な場合、この文字列に場所の住所が含まれます。In a Place content link created by the picker, it contains the address of the location, if available.
  • Uri – コンテンツ リンクのサブジェクトの詳細へのリンク。Uri – The link to more information about the subject of the content link. この Uri は、インストール済みのアプリまたは Web サイトを開くことができます。This Uri can open an installed app or a website.
  • Id - これは、RichEditBox コントロールによって作成されたコントロールごとの読み取り専用カウンタです。Id - This is a read-only, per control, counter created by the RichEditBox control. これは、削除または編集などの操作中にこの ContentLinkInfo を追跡するために使用します。It’s used to track this ContentLinkInfo during actions such as delete or edit. ContentLinkInfo が切り取られてコントロールに貼り付けられると、新しい Id が取得されます。Id の値は増分されます。If the ContentLinkInfo is cut and paste back into the control, it will get a new Id. Id values are incremental.
  • LinkContentKind – コンテンツ リンクの種類を説明する文字列。LinkContentKind – A string that describes the type of the content link. 組み込みのコンテンツの種類は_場所_と_連絡先_です。The built-in content types are Places and Contacts. この値では、大文字と小文字を区別します。The value is case sensitive.

LinkContentKind が重要になることがあります。There are several situations where the LinkContentKind is important.

  • ユーザーが RichEditBox からコンテンツ リンクをコピーし、別の RichEditBox に貼り付けると、両方のコントロールにそのコンテンツの種類の ContentLinkProvider が必要になります。When a user copies a content link from a RichEditBox and pastes it into another RichEditBox, both controls must have a ContentLinkProvider for that content type. 存在しない場合、リンクはテキストとして貼り付けられます。If not, the link is pasted as text.
  • ContentLinkChanged イベント ハンドラーで LinkContentKind を使用して、アプリの他の部分で使用する場合のコンテンツ リンクに対する処理を決定することができます。You can use LinkContentKind in a ContentLinkChanged event handler to determine what to do with a content link when you use it in other parts of your app. 詳しくは、「例」セクションをご覧ください。See the Example section for more info.
  • LinkContentKind は、リンクが呼び出されたときにシステムが Uri を開く方法に影響します。The LinkContentKind influences how the system opens the Uri when the link is invoked. これについては、次に起動される Uri のディスカッションで説明します。We’ll see this in the discussion of Uri launching next.

Uri の起動Uri launching

Uri プロパティは、ハイパーリンクの NavigateUri プロパティと同様に機能します。The Uri property works much like the NavigateUri property of a Hyperlink. ユーザーがクリックすると、既定のブラウザーで、または Uri 値で指定された特定のプロトコルに登録されているアプリで Uri を起動します。When a user clicks it, it launches the Uri in the default browser, or in the app that's registered for the particular protocol specified in the Uri value.

ここでは、2 種類の組み込みリンク コンテンツの具体的な動作について説明します。The specific behavior for the 2 built in kinds of link content are described here.

PlacesPlaces

Places ピッカーは、Uri ルート https://maps.windows.com/ で ContentLinkInfo を作成します。The Places picker creates a ContentLinkInfo with a Uri root of https://maps.windows.com/. このリンクは以下の 3 つの方法で開くことができます。This link can be opened in 3 ways:

  • LinkContentKind = "Places" である場合、ポップアップで情報カードが開かれます。If LinkContentKind = "Places", it opens an info card in a flyout. ポップアップは、コンテンツ リンク ピッカーのポップアップに似ています。The flyout is similar to the content link picker flyout. これは Windows の一部であり、アプリと別のプロセスで実行されます。It’s part of Windows, and runs in a separate process from your app.
  • LinkContentKind が "Places" でない場合、これはマップ アプリを指定の場所に開こうとします。If LinkContentKind is not "Places", it attempts to open the Maps app to the specified location. たとえば、これは ContentLinkChanged イベント ハンドラーで LinkContentKind を変更した場合に発生する可能性があります。For example, this can happen if you’ve modified the LinkContentKind in the ContentLinkChanged event handler.
  • マップ アプリで Uri を開くことができない場合、マップは既定のブラウザーで開かれます。If the Uri can’t be opened in the Maps app, the map is opened in the default browser. これは通常、ユーザーの _Web サイト用のアプリ_設定でマップ アプリを使用して Uri を開くことができない場合に発生します。This typically happens when the user's Apps for websites settings don’t allow opening the Uri with the Maps app.
PeoplePeople

People ピッカーは、ms-people プロトコルを使用する Uri で ContentLinkInfo を作成します。The People picker creates a ContentLinkInfo with a Uri that uses the ms-people protocol.

  • LinkContentKind = "People" である場合、ポップアップで情報カードが開かれます。If LinkContentKind = "People", it opens an info card in a flyout. ポップアップは、コンテンツ リンク ピッカーのポップアップに似ています。The flyout is similar to the content link picker flyout. これは Windows の一部であり、アプリと別のプロセスで実行されます。It’s part of Windows, and runs in a separate process from your app.
  • LinkContentKind が "People" でない場合、People アプリが開きます。If LinkContentKind is not "People", it opens the People app. たとえば、これは ContentLinkChanged イベント ハンドラーで LinkContentKind を変更した場合に発生する可能性があります。For example, this can happen if you’ve modified the LinkContentKind in the ContentLinkChanged event handler.

ヒント

アプリから他のアプリや Web サイトを開く方法の詳細については、「URI を使ったアプリの起動」の下にあるトピックを参照してください。For more info about opening other apps and websites from your app, see the topics under Launch an app with a Uri.

InvokedInvoked

ユーザーがコンテンツ リンクを呼び出すと、URI の起動の既定の動作が発生する前に ContentLinkInvoked イベントが発生します。When the user invokes a content link, the ContentLinkInvoked event is raised before the default behavior of launching the Uri happens. このイベントを処理して既定の動作を上書きするか、または取り消すことができます。You can handle this event to override or cancel the default behavior.

この例では、Place コンテンツ リンクの既定の起動動作を上書きする方法を示します。This example shows how you can override the default launching behavior for a Place content link. 場所情報カード、マップ アプリ、または既定の Web ブラウザーでマップを開く代わりに、イベントを処理済みとしてマークし、アプリ内の WebView コントロールでマップを開きます。Instead of opening the map in a Place info card, Maps app, or default web browser, you mark the event as Handled and open the map in an in-app WebView control.

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

ContentLinkChangedContentLinkChanged

ContentLinkChanged イベントを使用して、コンテンツのリンクが追加、変更、または削除されたときに通知を受信することができます。You can use the ContentLinkChanged event to be notified when a content link is added, modified, or removed. これにより、テキストからコンテンツ リンクを抽出し、アプリの他の場所で使用できるようになります。This lets you extract the content link from the text and use it in other places in your app. これについては後で「例」のセクションで説明します。This is shown later in the Examples section.

ContentLinkChangedEventArgs のプロパティは以下のとおりです。The properties of the ContentLinkChangedEventArgs are:

  • ChangedKind - この ContentLinkChangeKind 列挙型は ContentLink 内の操作です。ChangedKind - This ContentLinkChangeKind enum is the action within the ContentLink. たとえば、ContentLink が挿入、削除、または編集された場合の操作です。For example, if the ContentLink is inserted, removed, or edited.
  • Info - 操作のターゲットであった ContentLinkInfo。Info - The ContentLinkInfo that was the target of the action.

このイベントは ContentLinkInfo 操作ごとに発生します。This event is raised for each ContentLinkInfo action. たとえば、ユーザーが一度に複数のコンテンツ リンクをコピーして RichEditBox に貼り付けると、このイベントは追加された各項目で発生します。For example, if the user copies and pastes several content links into the RichEditBox at once, this event is raised for each added item. または、ユーザーが同時にいくつかのコンテンツ リンクを選択して削除した場合、このイベントは削除された各項目で発生します。Or if the user selects and deletes several content links at the same time, this event is raised for each deleted item.

このイベントは、TextChanging イベントの前、TextChanged イベントの前に RichEditBox で発生します。This event is raised on the RichEditBox after the TextChanging event and before the TextChanged event.

RichEditTextRange.ContentLink プロパティを使用して、リッチ エディット ドキュメントからコンテンツ リンクを取得することができます。You can use the RichEditTextRange.ContentLink property to get a content link from a rich edit document. TextRangeUnit 列挙型には値 ContentLink が含まれており、テキストの範囲を移動するときに使用する単位としてコンテンツ リンクを指定します。The TextRangeUnit enumeration has the value ContentLink to specify the content link as a unit to use when navigating a text range.

この例では、すべてのコンテンツ リンクを RichEditBox に列挙し、ユーザーをリストに抽出する方法を示します。This example shows how you can enumerate all the content links in a RichEditBox, and extract the people into a list.

<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 コントロールでコンテンツ リンクを使用するには、ContentLink テキスト要素 (Windows.UI.Xaml.Documents 名前空間から) を使用します。To use a content link in a TextBlock or RichTextBlock control, you use the ContentLink text element (from the Windows.UI.Xaml.Documents namespace).

テキスト ブロック内の ContentLink の標準的なソースは次のとおりです。Typical sources for a ContentLink in a text block are:

  • RichTextBlock コントロールから抽出したピッカーによって作成されたコンテンツ リンク。A content link created by a picker that you extracted from a RichTextBlock control.
  • コードで作成する場所のコンテンツ リンク。A content link for a place that you create in your code.

その他の状況では、通常、ハイパーリンク テキスト要素が適しています。For other situations, a Hyperlink text element is usually appropriate.

コンテンツ リンクの外観は、フォアグラウンド、バックグラウンド、およびカーソルによって決まります。The appearance of a content link is determined by its foreground, background, and cursor. テキスト ブロックで、Foreground (from TextElement) プロパティおよび Background プロパティを設定して既定の色を変更できます。In a text block, you can set the Foreground (from TextElement) and Background properties to change the default colors.

既定で、ユーザーがコンテンツ リンクにマウス カーソルを置くと の形のカーソルが表示されます。By default, the Hand cursor is shown when the user hovers over the content link. RichEditBlock とは異なり、テキスト ブロックのコントロールは、リンクの種類に基づいて自動的にカーソルを変更しません。Unlike RichEditBlock, text block controls don't change the cursor automatically based on the link type. カーソル プロパティを設定して、リンクの種類またはその他の要因に基づいてカーソルを変更することができます。You can set the Cursor property to change the cursor based on link type or other factors.

TextBlock で使用される ContentLink の例を示します。Here's an example of a ContentLink used in a TextBlock. ContentLinkInfo はコードで作成され、XAML で作成される ContentLink テキスト要素の情報プロパティに割り当てられます。The ContentLinkInfo is created in code and assigned to the Info property of the ContentLink text element that's created in XAML.

<StackPanel>
    <TextBlock>
        <Span xml:space="preserve">
            <Run>This valcano 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 とその他の要素間に空白を保持します。When you use a ContentLink in a text control with other text elements in XAML, place the content in a Span container and apply the xml:space="preserve" attribute to the Span to keep the white space between the ContentLink and other elements.

Examples

この例では、ユーザーは人物や場所を入力したり、RickTextBlock にコンテンツ リンクを配置したりできます。In this example, a user can enter a person or place content link into a RickTextBlock. ContentLinkChanged イベントを処理して、コンテンツ リンクを抽出し、人物または場所のリストでそれらを最新に保ちます。You handle the ContentLinkChanged event to extract the content links and keep them up-to-date in either a people list or places list.

リストの項目テンプレートで、ContentLink テキスト要素とともに TextBlock を使用し、コンテンツ リンク情報を表示します。In the item templates for the lists, you use a TextBlock with a ContentLink text element to show the content link info. ListView は項目ごとに独自の背景を提供するため、ContentLink のバックグラウンドは透明に設定されます。The ListView provides its own background for each item, so the ContentLink background is set to 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);
    }
}