Dynamics CRM モバイルアプリケーション開発 その 5

みなさん、こんにちは。

前回に引き続き、モバイルアプリケーション開発の紹介をします。
シリーズものですので、是非初回からご覧ください。

前回は取引先担当者の一覧を検索して表示するところまで実装
しました。今回ははじめに選択したレコードの詳細と関連する
完了した活動を表示してみます。

※今回も全ての列に値があるものと仮定しエラーハンドリングは
行っておりません。

モデルの拡張と追加

まず既存の Contact クラスにプロパティを追加します。
以下と同じになるようにしてください。

/// <summary>
/// 担当者用のクラス
/// </summary>
public class Contact
{
    // 担当者 ID
    public Guid Id { get; set; }
    // 姓名
    public string FullName { get; set; }
    // 電子メールアドレス
    public string EMailAddress1 { get; set; }
    // 電話番号
    public string Telephone1 { get; set; }
    // 会社名
    public string ParentCompany { get; set; }
    // 住所
    public string Address1 { get; set; }
}

次に活動用のクラスを追加します。

/// <summary>
/// 活動用のクラス
/// </summary>
public class Activity
{
    // 件名
    public string Subject { get; set; }
    // 完了日
    public string ActualEndDate { get; set; }
    // 活動の種類
    public string ActivityTypeCode { get; set; }
}

既存コードのアップデート

次に前回実装した btnSearch_Click メソッドに対して、取引先
担当者の ID を持つように変更を加えます。

メソッド内の以下の場所に黄色で示したラインを追加します。
これでリストビューの各アイテムがレコードの ID を保持します。

// 検索結果からリスト作成
foreach(var result in results.Entities)
{
    Contact contact = new Contact()
    {
        Id = (Guid)result["contactid"],
        FullName = result["fullname"].ToString(),
        EMailAddress1 = result["emailaddress1"].ToString()
    };

    contacts.Add(contact);
}

画面の追加

下準備が整いましたので、今回表示する取引先担当者の詳細と
完了した活動を表示するための画面を MainPage.xam に追加
します。以下の XAML を前回追加した Grid の下に追加します。

<!-- レコードグリッド -->
<Grid Grid.Column="1" >
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!-- 取引先担当者情報 -->
    <Grid Margin="24,60">
        <StackPanel x:Name="spContactCard">
            <TextBlock  Text="{Binding FullName}" FontSize="30" />
            <TextBlock  Text="{Binding Telephone1}" FontSize="30" />
            <TextBlock  Text="{Binding EMailAddress1}" FontSize="30" />
            <TextBlock  Text="{Binding Address1}" FontSize="30" />
            <TextBlock  Text="{Binding ParentCompany}" FontSize="30" />
        </StackPanel>
    </Grid>
    <!-- 活動 -->
    <Grid Grid.Row="1" Margin="24,0">
        <ListView x:Name="lvActivities">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <StackPanel>
                            <TextBlock Text="{Binding ActivityTypeCode}" />
                            <TextBlock Text="{Binding Subject}" />
                            <TextBlock Text="{Binding ActualEndDate}"  />
                        </StackPanel>
                        <!--<Line Style='{StaticResource Line_List}'/>-->
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Grid>

コードビハインドの更新

最後に取引先担当者リストビューのアイテムをクリックした際に
呼ばれるメソッドを更新します。lvContacts_ItemClick メソッドに
以下のコードを追加します。パターンは前回とほぼ同じですが、
Retrieve メソッドを使って取引先担当者の詳細を取得しています。

// クリックしたアイテムを Contact に変換
Contact contact = e.ClickedItem as Contact;

// より詳細を取得するため Retrieve を実行
Entity entity = await proxy.Retrieve("contact", contact.Id, new ColumnSet("telephone1", "parentcustomerid", "address1_composite"));

// 値を設定
contact.Telephone1 = entity["telephone1"].ToString();
contact.Address1 = entity["address1_composite"].ToString();
// 関連は EntityReference に変化後、Name プロパティを取得
contact.ParentCompany = (entity["parentcustomerid"] as EntityReference).Name;

// 取引先担当者情報に設定
spContactCard.DataContext = contact;

// 完了した活動を取得
string fetch = String.Format(@"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='activitypointer'>
<attribute name='activitytypecode' />
<attribute name='subject' />
<attribute name='activityid' />
<attribute name='actualend' />
<order attribute='actualend' descending='false' />
<filter type='and'>
<condition attribute='statecode' operator='eq' value='1' />
</filter>
<link-entity name='contact' from='contactid' to='regardingobjectid' alias='aa'>
<filter type='and'>
<condition attribute='contactid' operator='eq' value='{0}' />
</filter>
</link-entity>
</entity>
</fetch>", contact.Id);

// RetrieveMultiple の実行
var results = await proxy.RetrieveMultiple(new FetchExpression(fetch));

// リストビュー用のリストを作成
List<Activity> activities = new List<Activity>();

// 検索結果からリスト作成
foreach (var result in results.Entities)
{
    Activity activity = new Activity()
    {
        Subject = result["subject"].ToString(),
        // 日付部分だけを文字列をしてフォーマットして出力
        ActualEndDate = ((DateTime)result["actualend"]).ToString("d"),
        ActivityTypeCode = result["activitytypecode"].ToString()
    };

    activities.Add(activity);
}

// リストをリストビューに設定
lvActivities.ItemsSource = activities;

動作確認

アプリケーションを実行して動作確認します。尚、担当者に
完了した活動が紐づいていないと活動は表示されないため
事前にいくつかの活動を追加して、完了させてください。

image

また住所はあとで地図連携をするので実在のものに変更
しました。

1. F5 を押下してアプリケーションを起動します。

2. 「越」で検索します。

image

3. 検索結果をクリックします。右側に選択したレコードの詳細と
活動が表示されることを確認します。

image

他アプリケーションとの連動

Dynamics CRM の開発とは直接の関係がありませんが、ストア
アプリの重要機能の一つとしてアプリケーション連携は外せない
ため、今回は Skype と電子メール、地図の連携を紹介します。

シナリオとしては、取引先担当者の電話番号をクリックした際
Skype を起動して発信することと、電子メールアドレスを選択
した際、電子メールアプリケーションが、住所をクリックすると
地図アプリケーションが起動することです。

1. まず Mainpage.xaml に指定した電話番号と電子メールを
表示する TextBlock にタップイベントを指定します。

<TextBlock  Text="{Binding Telephone1}" FontSize="30" Tapped="Telephone_Tapped" />
<TextBlock  Text="{Binding EMailAddress1}" FontSize="30" Tapped="Email_Tapped" />
<TextBlock  Text="{Binding Address1}" FontSize="30" Tapped="Address_Tapped" />

2. MainPage.xaml.cs コードビハインドファイルに、紐づく
Telephone_Tapped メソッドを追加します。

/// <summary>
/// ユーザーが電話番号をタップした際に呼び出されます。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void Telephone_Tapped(object sender, TappedRoutedEventArgs e)
{
    await Launcher.LaunchUriAsync(new Uri("skype:" + (sender as TextBlock).Text));
}

3. Launcher の参照を解決するため、以下 using を追加します。

using Windows.System;

4. 同様に Email_Tapped メソッドも追加します。

/// <summary>
/// ユーザーが電子メールをタップした際に呼び出されます。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void Email_Tapped(object sender, TappedRoutedEventArgs e)
{
    await Launcher.LaunchUriAsync(new Uri("mailto:?to=" + (sender as TextBlock).Text + "&subject=" + "件名"));
}

5. 地図の分も追加します。

/// <summary>
/// ユーザーが住所をタップした際に呼び出されます。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void Address_Tapped(object sender, TappedRoutedEventArgs e)
{
    // 不要な改行と空白は %20 に置き換え
    await Launcher.LaunchUriAsync(new Uri("bingmaps:?where=" + (sender as TextBlock).Text.Replace(" ", "%20").Replace("\r\n", "%20")));
}

※ BingMap の仕様は以下を参照してください。
https://msdn.microsoft.com/ja-jp/library/windows/apps/jj635237.aspx

動作確認

再度プログラムを実行して動作を確認してください。

まとめ

今回は Retrieve を利用したレコードの取得をメインに
紹介しました。次回は新規に活動を作成して完了させる
部分を実装します。

- 中村 憲一郎