Windows Phone アプリで複数の SharePoint リストを使用する

複数の SharePoint リストのデータを使用する Windows Phone アプリを作成します。

アプリでは、いくつかの方法で複数の SharePoint リストを使用できます。 Windows Phone SharePoint リスト アプリケーション テンプレートに基づいて Windows Phone アプリを作成する場合は、ターゲット SharePoint リストを 1 つ指定しますが、出力されるプロジェクトのアーキテクチャーには複数のリストを統合できるだけの十分な拡張性があります。

重要

Windows Phone 8 用のアプリを開発する場合は、Visual Studio 2010 Express ではなく Visual Studio Express 2012 を使用する必要があります。 開発環境を除き、この記事のすべての情報は、Windows Phone 8 用アプリと Windows Phone 7 用アプリを作成する場合に適用されます。 > 詳細については、「 方法: SharePoint 用モバイル アプリを開発するための環境を設定する」を参照してください。

同じスキーマに基づく SharePoint リストが関係するソリューションの作成

同じスキーマに基づく SharePoint リストが 2 つある場合は、Windows Phone SharePoint リスト アプリケーション テンプレートによって実装されるクラスを利用し、各リストに固有の、それらのクラスのオブジェクトを作成できます。

連絡先リスト テンプレートに基づいて 2 つの SharePoint リストがあるとします。 たとえば、マーケティング チームという名前の 1 つのリストには、組織のマーケティング チームのメンバーが含まれており、もう 1 つのリストであるエンジニアリング チームにはエンジニアリング チームのメンバーが含まれています。 Windows Phone SharePoint リスト アプリケーション テンプレートを使用してプロジェクトを作成し、プロジェクトのベースとなるターゲット リストとして Marketing Team リストを指定すると、プロジェクト内の App.xaml.cs ファイルの App クラスの実装に ListDataProvider クラスのインスタンス (既定では DataProvider という名前) が作成されます。 このオブジェクトは、リスト (つまり、マーケティング チーム) リストをアプリのデータ ソースとして表し、リスト内の項目にアクセスして操作する操作を提供します。 また、アプリの基になるリストに対して ListViewModel クラスのインスタンスも作成されます。 このオブジェクトには、ListDataProvider クラスの特定のインスタンスに設定できるプロパティ メンバー (DataProvider という名前もあります) があり、ListViewModel クラス インスタンスのデータ ソースを確立します。

プロジェクトに ListDataProvider クラスの追加インスタンスを作成して、 App.xaml.cs ファイル内の 2 番目のリスト (エンジニアリング チーム) のデータ ソースとして機能させることができます。 このオブジェクトは、以下のコード サンプルでは SecondaryDataProvider という名前になっています。

private static ListDataProvider m_SecondaryDataProvider;

public static ListDataProvider SecondaryDataProvider
{
    get
    {
        if (m_SecondaryDataProvider != null)
            return m_SecondaryDataProvider;

        m_SecondaryDataProvider = new ListDataProvider();
        m_SecondaryDataProvider.ListTitle = "Engineering Team";
        m_SecondaryDataProvider.SiteUrl = new Uri("http://contoso:2012/sites/samplesite/");

        return m_SecondaryDataProvider;
    }
}

次に、 ListViewModel クラスの別のオブジェクト (たとえば、 SecondaryViewModel という名前) をインスタンス化し、次のコードに示すように、 SecondaryDataProvider オブジェクトをその DataProvider プロパティに割り当てることができます。

private static ListViewModel m_SecondaryViewModel;

public static ListViewModel SecondaryViewModel
{
    get
    {
        if (m_SecondaryViewModel == null)
            m_SecondaryViewModel = new ListViewModel { DataProvider = App.SecondaryDataProvider };

        return m_SecondaryViewModel;
    }
    set
    {
        m_SecondaryViewModel = value;
    }
}

2 つのリストの同じフィールドとビューが目的に適している場合 (また、2 つのリストに同じ列とフィールドがある場合)、ListDataProvider クラス (ListDataProvider.cs ファイル内) の実装に変更を加える必要はありません。

ただし、プロジェクトの 2 番目のリストからのデータを表示または変更するには、この SecondaryViewModel にバインドおよび構成されたビュー フォームをプロジェクトに追加する必要があります。 たとえば、"SecondaryViews" という名前のフォルダーをプロジェクトに追加し、そのフォルダーに SecondaryList.xaml ファイルを追加し、プロジェクト内のプライマリ リストのテンプレートによって生成された既定の List.xaml ファイルと同様のマークアップを追加できます。 SecondaryList.xaml ファイル内の 要素の属性の識別値x:Classを指定することで、セカンダリ リスト フォームとアプリ内のPhoneApplicationPageプライマリ リスト フォームを区別する必要があることに注意してください。

<phone:PhoneApplicationPage
    x:Class="MultipleSPListApp.SecondaryViews.ListForm"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
    shell:SystemTray.IsVisible="True" x:Name = "ListViewPage">
...
</phone:PhoneApplicationPage>

関連付けられている分離コード ファイル SecondaryList.xaml.cs で、 へのすべての参照を App.MainViewModel への参照に App.SecondaryViewModel置き換えます。 たとえば、ファイルのコンストラクターを次のようにしてください。

public ListForm()
{
    InitializeComponent();
    this.DataContext = App.SecondaryViewModel;
}

また、分離コード ファイル内のすべての参照を へのApp.DataProviderApp.SecondaryDataProvider参照に置き換え、適切なセカンダリ XAML ページを指すようにナビゲーション パスを更新します。 セカンダリの新しいフォーム (たとえば、プロジェクトの SecondaryViews フォルダーの SecondaryNewForm.xaml など) をプロジェクトに追加した場合、OnNewButtonClick イベントの SecondaryList.xaml.cs ファイル内のハンドラーは次のコードのようになります。

private void OnNewButtonClick(object sender, EventArgs e)
{
    // Instantiate a new instance of NewItemViewModel and go to NewForm.
    App.SecondaryViewModel.CreateItemViewModelInstance = new NewItemViewModel { DataProvider = App.SecondaryDataProvider };
    NavigationService.Navigate(new Uri("/SecondaryViews/SecondaryNewForm.xaml", UriKind.Relative));
}

最後に、List.xaml ファイルの ApplicationBar にボタンを追加して、SecondaryList.xaml ページを表示できます。

<phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
        <shell:ApplicationBarIconButton x:Name="btnNew" IconUri="/Images/appbar.new.rest.png" Text="New" Click="OnNewButtonClick"/>
        <shell:ApplicationBarIconButton x:Name="btnRefresh" IconUri="/Images/appbar.refresh.rest.png" Text="Refresh" IsEnabled="True" Click="OnRefreshButtonClick"/>
        <!--Add the following button to navigate to the secondary list (Engineering Team).-->
        <shell:ApplicationBarIconButton x:Name="btnSecondaryList" IconUri="/Images/appbar.upload.rest.png" Text="Engineering" IsEnabled="True" Click="OnSecondaryListButtonClick"/>
    </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

関連付けられたコード分離ファイル List.xaml.cs に、Listxaml ファイルで宣言した OnSecondaryListButtonClick イベントのハンドラーを追加します。

private void OnSecondaryListButtonClick(object sender, EventArgs e)
{
    NavigationService.Navigate(new Uri("/SecondaryViews/SecondaryList.xaml", UriKind.Relative));
}

これでアプリのユーザーは、Marketing Team リストと Engineering Team リストの間を移動できるようになります。 基になるリスト スキーマは同じであるため、テンプレートによって生成される既定の DataProvider オブジェクトと MainViewModel オブジェクトと、追加された SecondaryDataProvider オブジェクトと SecondaryViewModel オブジェクトは 、ListDataProvider.cs ファイルに変更を加えることなく、すべてのデータ トランザクションを処理します。

異なるスキーマに基づく SharePoint リストが関係するソリューションの作成

前のセクションの方法はある程度まで (つまり、同じスキーマに基づく SharePoint リストの場合) 有効ですが、同じスキーマに基づかないか、同じ列とフィールドを含んでいない複数の SharePoint リストを処理するカスタマイズの場合、開発者は Windows Phone SharePoint リスト アプリケーション テンプレートの ListDataProvider クラスを使用できます。

前のセクション同様、マーケティング チームのメンバーを含んだ (Contacts リストテンプレートに基づく) Marketing Team という名前の SharePoint リストがあるとします。 また、表 1 に示す列とフィールドを含んだ (Custom リスト テンプレートに基づく) Orders という名前の 2 つ目のリストもあるとします。

表 1. Orders リストの列とフィールド

Column フィールドの種類 必須
Product (すなわち、タイトル) 1 行テキスト (Text) はい
単価 通貨 はい
数量 Number 不要 (既定値は 0)
注文値 計算値 (単価 * 数量) いいえ
注文日 日付/時刻 (Datetime) いいえ
注文状況 選択肢 いいえ
顧客 1 行テキスト (Text) いいえ

前のセクションの例と同様、別個の ListDataProvider オブジェクトと別の ListViewModel オブジェクトをインスタンス化して、Orders リストを管理できます。 次のコード サンプルでは、インスタンス化された ListDataProvider オブジェクトの名前を OrdersListDataProvider としています。

private static ListDataProvider m_OrdersListDataProvider;

public static ListDataProvider OrdersListDataProvider
{
    get
    {
        if (m_OrdersListDataProvider != null)
            return m_OrdersListDataProvider;

        m_OrdersListDataProvider = new ListDataProvider();
        m_OrdersListDataProvider.ListTitle = "Orders";
        m_OrdersListDataProvider.SiteUrl = new Uri("http://contoso:2012/sites/samplesite/"); // Specify a URL here for your server.

        return m_OrdersListDataProvider;
    }
}

また、次のコード サンプルでは、Orders リストのインスタンス化された ListViewModel オブジェクトの名前を OrdersListViewModel としています。

private static ListViewModel m_OrdersListViewModel;

public static ListViewModel OrdersListViewModel
{
    get
    {
        if (m_OrdersListViewModel == null)
            m_OrdersListViewModel = new ListViewModel { DataProvider = App.OrdersListDataProvider };

        return m_OrdersListViewModel;
    }
    set
    {
        m_OrdersListViewModel = value;
    }
}

Orders リストのスキーマは Marketing Team リストのスキーマと異なります。 違いに対応するには、 コードを ListDataProvider.cs ファイル (特に CamlQueryBuilder クラス) に追加します。

public static class CamlQueryBuilder
{
    static Dictionary<string, string> ViewXmls = new Dictionary<string, string>()
    {
      {"View1",   @"<View><Query><OrderBy><FieldRef Name='Title' />
                    <FieldRef Name='FirstName'  /></OrderBy></Query><RowLimit>30</RowLimit><ViewFields>{0}</ViewFields></View>"},
      {"View2",   @"<View><Query><OrderBy><FieldRef Name='ID' /></OrderBy></Query><RowLimit>30</RowLimit>
     <ViewFields>{0}</ViewFields></View>"}
    };

    static string View1Fields = @"<FieldRef Name='Title'/><FieldRef Name='FirstName'/>
   <FieldRef Name='JobTitle'/><FieldRef Name='Email'/><FieldRef Name='Comments'/>";
    static string View2Fields = @"<FieldRef Name='Title'/><FieldRef Name='Unit_x0020_Price'/><FieldRef Name='Quantity'/>
            <FieldRef Name='Order_x0020_Value'/><FieldRef Name='Order_x0020_Date'/>
            <FieldRef Name='Status'/><FieldRef Name='Customer'/>";

    public static CamlQuery GetCamlQuery(string viewName)
    {
        string viewXml = ViewXmls[viewName];
        // Add ViewFields to the ViewXml depending on the view.
        switch (viewName)
        {
            case "View2":
                viewXml = string.Format(viewXml, View2Fields);
                break;
            case "View1":
            default:
                viewXml = string.Format(viewXml, View1Fields);
                break;
        }
        return new CamlQuery { ViewXml = viewXml };
    }
}

ここでは、"View2" のキー値を持つ 2 番目のエントリが、 Orders リストの ViewXmlsDictionary オブジェクトに追加されます。 (CamlQueryBuilder クラスの ViewXmlsDictionary に追加されたエントリのキー値は、テンプレート内のキャッシュ ロジックが適切に動作するためには、(ソリューション内で) 一意である必要があることに注意してください)。 文字列変数 ( View1FieldsView2Fields) は、各ビューのフィールドの一覧を格納するために使用されます。 GetCamlQuery メソッドに渡される viewName パラメーターの値に応じて、適切な CAML クエリ XML 文字列が作成されます。

次に、前のセクションと同様に、リストのビュー フォームを作成し、今回 は OrdersListViewModel オブジェクトと OrdersListDataProvider オブジェクトにバインドできます。 たとえば、OrdersList.xaml という名前の List フォームの XAML は、アプリのプライマリ リストのテンプレートによって生成される List.xaml ファイル内のマークアップと似ていますが、リストを表示する PivotItem コントロールに名前を付け、リストボックスの ItemsSource 属性に対するバインド宣言を設定する点が異なります。 次のマークアップと同様に、リスト 項目を "View2" にレンダリングするコントロール (ページのルート グリッドのマークアップのみが表示されます)。

    <Grid x:Name="LayoutRoot" Background="Transparent" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls">
        <!--Pivot Control-->
        <ProgressBar x:Name="progressBar" Opacity="1" HorizontalAlignment="Center" VerticalAlignment="Top"
               Height="30" Width="470" IsIndeterminate="{Binding IsBusy}" Visibility="{Binding ShowIfBusy}" />
        <Grid x:Name="ContentPanel" Grid.Row="0" Width="470">
            <controls:Pivot Name="Views" Title="Orders" LoadedPivotItem="OnPivotItemLoaded">
                <!--Pivot item-->
                <controls:PivotItem Name="View2" Header="All Orders">
                    <!--Double line list with text wrapping-->
                    <ListBox x:Name="lstBox1" Margin="0,0,-12,0" SelectionChanged="OnSelectionChanged" ItemsSource="{Binding [View2]}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Vertical" Margin="10">
                                    <TextBlock Name="txtTitle" Text="{Binding [Title]}" TextWrapping="NoWrap"
                                          Style="{StaticResource PhoneTextTitle2Style}" />
                                    <TextBlock Name="txtUnitPrice" Text="{Binding [Unit_x0020_Price]}"
                                         TextWrapping="NoWrap" Style="{StaticResource PhoneTextNormalStyle}" />
                                    <TextBlock Name="txtQuantity" Text="{Binding [Quantity]}"
                                         TextWrapping="NoWrap" Style="{StaticResource PhoneTextNormalStyle}" />
                                </StackPanel>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </controls:PivotItem>
            </controls:Pivot>
        </Grid>
    </Grid>

適切な XAML マークアップを作成する便利な方法は、Windows Phone SharePoint リスト アプリケーション テンプレートを使用して、Orders リストに基づいて別のプロジェクトを生成し、そのプロジェクトから複数のリストを含むプロジェクトに生成された XAML をコピーし、PivotItem コントロールの名前 (既定値は "View1") を "View2" に変更し、ListBox コントロールのバインド宣言を変更することです。 また、適切な ListViewModel オブジェクトと DataProvider オブジェクト ( OrdersListViewModelOrdersListDataProvider など) を指定するには、関連付けられた分離コード ファイル内のすべての参照を変更する必要もあります。

この方法が有効なのは、関連付けられた分離コード ファイル (この場合の名前は OrdersList.xaml.cs) では、 ListDataProvider オブジェクト (ここでは、 OrdersListDataProvider) のメソッドを呼び出してリスト データにアクセスするさまざまなイベント ハンドラーが、使用する適切なビューを指定する方法として PivotItem コントロールの名前を使用するからです。 たとえば、 OnPivotItemLoaded イベント ハンドラーは、 ListViewModel クラスからインスタンス化された OrdersListViewModel オブジェクトの LoadData メソッドを呼び出し (このメソッドは、その後 OrdersListDataProvider オブジェクトの LoadData メソッドを呼び出します)、 PivotItem コントロールの名前 (ここでは、"View2") を ViewName パラメーターの値としてそのメソッドに渡します。 この同じ値は、上の CamlQueryBuilder クラスの変更された実装の例に示すように、最終的に ( viewName パラメーターの値として) GetCamlQuery メソッドに渡されます。

異なるスキーマに基づく SharePoint リストが関係するソリューションの代替方法

前のセクションに示す方法の代替方法として、Windows Phone SharePoint リスト アプリケーション テンプレートを使用し、指定された SharePoint リストに基づく Microsoft Visual Studio 2010 ソリューションで Windows Phone アプリ プロジェクトを作成して、他のリストに基づいて構築されたプロジェクトをその同じソリューションに追加することができます。 この方法では、テンプレートを利用して各 SharePoint リストに特有のフォームを生成することができます。 その後、必要に応じてソリューションをカスタマイズし、ユーザーがリストを対話的に操作する方法を制御できます。 このセクションの手順では、その方法を示します。

以下の手順では、(カスタム リスト テンプレートに基づく) Orders という名前の SharePoint リストがあり、前のセクションの表 1 に示されるような列とフィールドの種類があると想定しています。 また、表 2 に示す列とフィールドの種類を含んだ Customers という名前の (カスタム リスト テンプレートに基づいた) 別の SharePoint リストがあると想定しています。

表 2. Customers リストの列とフィールド

Column フィールドの種類 必須
顧客名 (すなわち、タイトル) 1 行テキスト (Text) はい
連絡先番号 1 行テキスト (Text) いいえ
電子メール アドレス 1 行テキスト (Text) いいえ
会社 1 行テキスト (Text) いいえ

以下の手順では、これらのリストを両方とも使用する Windows Phone アプリを作成します。 アプリのプライマリ リストは Customers リストです。 指定した顧客の詳細を表示フォームで表示すると、フォームにボタンが表示されるので、ユーザーはその顧客に関連付けられているすべての注文 (Orders リストから) を表示することができます。

ソリューションのためのコンポーネント プロジェクトを作成する

  1. 表 2 に示す列およびフィールドの種類に基づいて定義された SharePoint リストを指定して、Windows Phone SharePoint リスト アプリケーション テンプレートを使用することによって Windows Phone アプリを作成します。 このセクションの手順では、プロジェクトのリストの名前を "Customers"、プロジェクトの名前を "CustomersSPListApp" と想定しています (Windows Phone SharePoint リスト アプリケーション テンプレートに基づいてアプリを作成する方法については、「方法: Windows Phone SharePoint リスト アプリを作成する」を参照してください)。

  2. Visual Studio で、[ファイル][追加][新しいプロジェクト] の順に選択します。

    [ 新しいプロジェクトの追加] ダイアログ ボックスが表示されます。

  3. [ 新しいプロジェクトの追加] ダイアログ ボックスの [ Visual C#] ノードの下で、[ Silverlight for Windows Phone] ノードを選択します。

  4. [ テンプレート] ウィンドウで、Windows Phone SharePoint リスト アプリケーション テンプレートを選択します。

  5. アプリに名前をつけて (例: OrdersSPListApp)、[OK] を選択します。

  6. 方法: Windows Phone SharePoint リスト アプリを作成する」で説明されている手順に従って、別のWindows Phone アプリ プロジェクトを作成します。表 1 に示されている列とフィールドの種類に基づいて定義された SharePoint リストをプロジェクトのターゲット リストとして指定します。 これでソリューションには、"CustomersSPListApp" と "OrdersSPListApp" という名前 (この手順での命名規則に従っている場合) の 2 つのプロジェクトが存在することになります。

  7. [ソリューション エクスプローラー] で、CustomerSPListApp プロジェクト ノードを選択します。

  8. [ プロジェクト] メニューで、[ 参照の追加] を選択します。

    [参照の追加] ダイアログ ボックスが表示されます。

  9. [ プロジェクト] タブで、ソリューションの OrdersSPListApp プロジェクトを選択して [ OK] ボタンを選択します。 そのプロジェクトが、CustomersSPListApp プロジェクトの [ 参照] ノードの下に追加されます。

次に、ソリューション内の 2 つのプロジェクトを構成します。 基本的には、(Orders リストに基づく) OrdersSPListApp プロジェクトが (Customers リストに基づく) CustomerSPListApp プロジェクトの "検索" プロジェクトとして動作するように構成します。

OrdersSPListApp プロジェクトを構成するには

  1. OrdersSPListApp プロジェクトのビュー フォームのナビゲーション パスを、プロジェクト ("OrdersSPListApp") のプライマリ名前空間と "component" 指定が含まれるように変更します。 たとえば、OrdersSPListApp プロジェクトの List.xaml.cs ファイルの OnNewButtonClick イベントのハンドラーで、NavigationService オブジェクトの Navigate メソッドの呼び出しを次から変更します。

    NavigationService.Navigate(new Uri("/Views/NewForm.xaml", UriKind.Relative));
    

    この呼び出しを次のように変更します。

    NavigationService.Navigate(new Uri("/OrdersSPListApp;component/Views/NewForm.xaml", UriKind.Relative));
    

    これらの変更を行うのに最も簡単な方法は、OrdersSPListApp プロジェクトで [ クイック置換] コマンドを使用する方法です。

  2. [ ソリューション エクスプローラー] で、OrdersSPListApp プロジェクト ノードを選択します。

  3. Ctrl+H を押して [ クイック置換] ダイアログ ボックスを表示します。

  4. [ 検索文字列] テキスト ボックスで、次のテキストを示されるとおり正確に指定します。

    Uri("/Views/
    
  5. [ 置換後の文字列] テキスト ボックスで、次のテキストを示されるとおり正確に指定します。

    Uri("/OrdersSPListApp;component/Views/
    
  6. [ 検索先] ドロップダウン リストで [ 現在のプロジェクト] ドロップダウン リストが選択されていることを確認します。

  7. [ すべて置換] を選択します。

  8. プロジェクトの変更されたすべてのファイルを保存します。

  9. OrdersSPListApp プロジェクトの App.xaml.cs ファイルにメンバー プロパティを追加します。 ソリューション エクスプローラーの OrdersSPListApp プロジェクト ノードで、App.xaml ファイルを選択します。

  10. F7 キーを押して、関連する分離コード ファイル App.xaml.cs を開いて編集します。

  11. App 部分クラスを実装する (左かっこと右かっこで区切られた) コード ブロックの範囲内に、次のコードを追加します。

    public static string CustomerName { get; set; }
    
  12. ソリューション エクスプローラーの OrdersSPListApp プロジェクト ノードで、List.xaml ファイルを選択します。

  13. F7 キーを押して、関連する分離コード ファイル List.xaml.cs を開いて編集します。

  14. ファイルの OnNavigatedTo イベント ハンドラーを変更して、手順 4 で宣言した CustomerName 変数の値を設定する NavigationContext オブジェクトの QueryString プロパティを解析します。 ユーザーが使用しやすいように、 PivotItem コントロールの Header プロパティを顧客名と一致するように設定することもできます。 変更したハンドラーは次のようになります。

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
    
        if (this.NavigationContext.QueryString.ContainsKey("CustomerName"))
        {
            App.CustomerName = NavigationContext.QueryString["CustomerName"];
        }
    
        // Also set the value of the Header property for the PivotItem to match the customer name.
        if (!string.IsNullOrWhiteSpace(App.CustomerName))
        {
            this.View1.Header = App.CustomerName;
        }
    
        App.MainViewModel.ViewDataLoaded += new EventHandler<ViewDataLoadedEventArgs>(OnViewDataLoaded);
        App.MainViewModel.InitializationCompleted += new EventHandler<InitializationCompletedEventArgs>(OnViewModelInitialization);
    }
    
  15. List.xaml.cs ファイルの OnPivotItemLoaded イベント ハンドラーの LoadData メソッドの呼び出しで、CustomerName 変数を引数として追加します。 実装される OnPivotItemLoaded イベント ハンドラーは、次のようになります。

    private void OnPivotItemLoaded(object sender, PivotItemEventArgs e)
    {
        if (!App.MainViewModel.IsInitialized)
        {
            //Initialize ViewModel and Load Data for PivotItem upon initialization.
            App.MainViewModel.Initialize();
        }
        else
        {
            //Load Data for the currently loaded PivotItem.
            App.MainViewModel.LoadData(e.Item.Name, App.CustomerName);
        }
    }
    

    テンプレートの ListViewModel クラスの LoadData メソッドは、オプションのパラメーターを受け入れることができるように定義されます。

  16. また、 OnViewModelInitialization イベント ハンドラーの LoadData メソッドに、呼び出しに含まれる引数として CustomerName 変数を追加します。 実装される OnViewModelInitialization イベント ハンドラーは次のようになります。

    private void OnViewModelInitialization(object sender, InitializationCompletedEventArgs e)
    {
        this.Dispatcher.BeginInvoke(() =>
        {
            //If initialization has failed, show error message and return.
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message, e.Error.GetType().Name, MessageBoxButton.OK);
                return;
            }
            App.MainViewModel.LoadData(((PivotItem)Views.SelectedItem).Name, App.CustomerName);
            this.DataContext = (sender as ListViewModel);
        });
    }
    
  17. List.xaml.cs ファイルの OnRefreshButtonClick イベント ハンドラーの RefreshData メソッドの呼び出しで、CustomerName 変数を引数として追加します。 実装される OnRefreshButtonClick イベント ハンドラーは次のようになります。

    private void OnRefreshButtonClick(object sender, EventArgs e)
    {
        if (Views.SelectedItem == null)
            return;
    
        if (!App.MainViewModel.IsInitialized)
        {
            //Initialize ViewModel and Load Data for PivotItem upon completion.
            App.MainViewModel.Initialize();
        }
        else
        {   //Refresh Data for the currently loaded PivotItem.
            App.MainViewModel.RefreshData(((PivotItem)Views.SelectedItem).Name, App.CustomerName);
        }
    }
    

    LoadData メソッドに関しては、 RefreshData メソッドもオプション パラメーターを受け入れることができるように定義されます。 上の 3 つの手順では、テンプレートによって生成されるイベント ハンドラーに対する唯一の変更は、呼び出しに含まれる引数として CustomerName 変数が LoadData または RefreshData メソッドに追加されることです。

  18. ユーザーがアプリの [注文] リストの [リスト] フォームの [ 新規 ] ボタンを選択すると、ユーザーに表示される注文の一覧が顧客名に基づいてフィルター処理されているため、[新しい] フォームの [顧客] フィールドに顧客の名前が既に含まれている必要があります。 フィルター処理されたリストから追加された新しい注文は、リストがフィルター処理される顧客名に関連付ける必要があります。 CustomerName 変数の値を New フォームに渡すには、次のコードに示すように、OnNewButtonClick イベントを変更して、新しいフォームへのナビゲーション パスにクエリ文字列として値を含めます。

    private void OnNewButtonClick(object sender, EventArgs e)
    {
        //Instantiate a new instance of NewItemViewModel and go to NewForm.
        App.MainViewModel.CreateItemViewModelInstance = new NewItemViewModel { DataProvider = App.DataProvider };
    
        if (!string.IsNullOrWhiteSpace(App.CustomerName))
        {
            NavigationService.Navigate(new Uri("/OrdersSPListApp;component/Views/NewForm.xaml?CustomerName=" +
                                                                                App.CustomerName, UriKind.Relative));
        }
        else
        {
            NavigationService.Navigate(new Uri("/OrdersSPListApp;component/Views/NewForm.xaml", UriKind.Relative));
        }
    }
    
  19. 新しいフォームの OnNavigatedTo イベント ハンドラーで、クエリ文字列に顧客名が含まれているかどうかチェックし、名前が変数になっている場合は、それをフォームの ViewModel の Customer フィールドに割り当てます。 ソリューション エクスプローラーの OrdersSPListApp プロジェクトで、NewForm.xaml ファイルを選択し、F7 キーを押して、関連する分離コード ファイル NewForm.xaml.cs を開いて編集します。

  20. 次のコードと一致するように、ファイルで OnNavigatedTo イベント ハンドラーを変更します。

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
    
        if (this.NavigationContext.QueryString.ContainsKey("CustomerName"))
        {
            this.viewModel["Customer"] = NavigationContext.QueryString["CustomerName"];
        }
    
        viewModel.ItemCreated += new EventHandler<ItemCreatedEventArgs>(OnItemCreated);
    }
    
  21. OrdersSPListApp プロジェクトの ListDataProvider.cs ファイルの CamlQueryBuilder クラスで、ORDERs リストから項目を取得するために使用する CAML クエリの Customer フィールドに WHERE 句を追加し、(CustomerName 変数から) 指定された顧客名に基づいてリストをフィルター処理します。 そのクラスの GetCamlQuery メソッドに、顧客名を渡すためのパラメーターを追加します。 変更された CamlQueryBuilder クラスは次のようになります。

    public static class CamlQueryBuilder
    {
        static Dictionary<string, string> ViewXmls = new Dictionary<string, string>()
        {
            {"View1", @"<View><Query>{0}</Query><RowLimit>30</RowLimit><ViewFields>{1}</ViewFields></View>"}
        };
    
        static string ViewFields = @"<FieldRef Name='Title'/><FieldRef Name='Unit_x0020_Price'/><FieldRef Name='Quantity'/><FieldRef Name='Order_x0020_Value'/><FieldRef Name='Order_x0020_Date'/><FieldRef Name='Status'/><FieldRef Name='Customer'/>";
    
        public static CamlQuery GetCamlQuery(string viewName, string customerName)
        {
            string queryClause = string.Empty;
    
            // Create appropriate Query Clause, depending on customerName parameter.
            if (string.IsNullOrWhiteSpace(customerName))
            {
                queryClause = "<OrderBy><FieldRef Name='ID' /></OrderBy>";
            }
            else
            {
                queryClause = string.Format("<Where><Eq><FieldRef Name='Customer' /><Value Type='Text'>{0}</Value></Eq></Where>", customerName);
            }
    
            // Add Query Clause and ViewFields to ViewXml.
            string viewXml = ViewXmls[viewName];
            viewXml = string.Format(viewXml, queryClause, ViewFields);
    
            return new CamlQuery { ViewXml = viewXml };
        }
    }
    
  22. ListDataProvider.cs ファイルの LoadDataFromServer メソッドを変更して CustomerName 引数を確認し、引数を GetCamlQuery メソッドに渡します。 変更されたメソッドは次のようになります。

    private void LoadDataFromServer(string ViewName, Action<LoadViewCompletedEventArgs>
                                                  loadItemCompletedCallback, params object[] filterParameters)
    {
        string customerName = string.Empty;
        string cacheKey = ViewName;
    
        // Parse the optional parameters:
        if (filterParameters.Length > 0)
        {
            customerName = filterParameters[0].ToString();
            cacheKey += "-" + customerName;
        }
    
        CamlQuery query = CamlQueryBuilder.GetCamlQuery(ViewName, customerName);
        ListItemCollection items = Context.Web.Lists.GetByTitle(ListTitle).GetItems(query);
        Context.Load(items);
        Context.Load(items, listItems => listItems.Include(item => item.FieldValuesAsText));
    
        Context.ExecuteQueryAsync(
            delegate(object sender, ClientRequestSucceededEventArgs args)
            {
                base.CacheView(cacheKey, items);
                loadItemCompletedCallback(new LoadViewCompletedEventArgs { ViewName = ViewName, Items = base.GetCachedView(cacheKey) });
            },
            delegate(object sender, ClientRequestFailedEventArgs args)
            {
                loadItemCompletedCallback(new LoadViewCompletedEventArgs { Error = args.Exception });
            });
    }
    
  23. 同様に、ListDataProvider.cs ファイルの LoadData メソッドを変更して CustomerName パラメーターを処理します。

    public override void LoadData(string ViewName, Action<LoadViewCompletedEventArgs>
                                                               loadViewCompletedCallback, params object[] filterParameters)
    {
        string customerName = string.Empty;
        string cacheKey = ViewName;
    
        // Parse the optional parameters:
        if (filterParameters.Length > 0)
        {
            customerName = filterParameters[0].ToString();
            cacheKey += "-" + customerName;
        }
    
        List<ListItem> CachedItems = GetCachedView(cacheKey);
        if (CachedItems != null)
        {
            loadViewCompletedCallback(new LoadViewCompletedEventArgs { ViewName = ViewName, Items = CachedItems });
            return;
        }
    
        LoadDataFromServer(ViewName, loadViewCompletedCallback, filterParameters);
    }
    
  24. OrdersSPListApp プロジェクトの List.xaml ファイルの ApplicationBar 要素に [ キャンセル] ボタンを追加します。 [ ソリューション エクスプローラー] の OrdersSPListApp ノードの下で、List.xaml ファイルを選択し、デザイナーで編集できるように SHIFT+F7 を押してそのファイルを開きます。

  25. 次のマークアップに示すように、XAML を追加して、 <phone:PhoneApplicationPage.ApplicationBar> タグ内で [ キャンセル] ボタンを宣言します。

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton x:Name="btnNew"
                     IconUri="/Images/appbar.new.rest.png" Text="New" Click="OnNewButtonClick"/>
            <shell:ApplicationBarIconButton x:Name="btnRefresh" IconUri="/Images/appbar.refresh.rest.png"
                     Text="Refresh" IsEnabled="True" Click="OnRefreshButtonClick"/>
            <shell:ApplicationBarIconButton x:Name="btnCancel" IconUri="/Images/appbar.cancel.rest.png" Text="Cancel" IsEnabled="True" Click="OnCancelButtonClick" />
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>
    
  26. [ ソリューション エクスプローラー] で List.xaml ファイルが選択された状態で F7 を押し、関連付けられた分離コード ファイル List.xaml.cs を編集用に開きます。

  27. ListForm 部分クラスを実装する (左かっこと右かっこで区切られた) コード ブロック内に、 OnCancelButtonClick イベントの次のハンドラーを追加します。

    private void OnCancelButtonClick(object sender, EventArgs e)
    {
        NavigationService.Navigate(new Uri("/CustomersSPListApp;component/Views/DisplayForm.xaml", UriKind.Relative));
    }
    
  28. プロジェクトにファイルを保存します。

残りの操作は、CustomersSPListApp プロジェクトの表示フォームに、指定された顧客に関連付けられている注文を表示するためのボタンを追加することです。

CustomersSPListApp プロジェクトを構成するには

  1. [ ソリューション エクスプローラー] の CustomersSPListApp プロジェクトのノードの下で、DisplayForm.xaml ファイルを選択します。

  2. デザイナーで編集するため、 Shift + F7 を押して (またはファイルをダブルクリックして) ファイルを開きます。

  3. 次のマークアップに示すように、リスト項目の最後のフィールドの最後の StackPanel コントロール コンテナーの後に、含まれる StackPanel コントロール内の Button コントロールの XAML 宣言を追加します。

    <Grid x:Name="LayoutRoot" Background="Transparent" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls">
        <StackPanel>
            <ProgressBar Background="Red" x:Name="progressBar" Opacity="1" HorizontalAlignment="Center"
              VerticalAlignment="Top" Height="15" Width="470" IsIndeterminate="{Binding IsBusy}"
                Visibility="{Binding ShowIfBusy}" />
            <ScrollViewer HorizontalScrollBarVisibility="Auto" Height="700">
                <Grid x:Name="ContentPanel" Width="470">
                    <StackPanel Margin="0,5,0,5">
                        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">
                            <TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
                                            Style="{StaticResource PhoneTextNormalStyle}">Title :</TextBlock>
                            <TextBlock Width="310" HorizontalAlignment="Left" Name="txtTitle"
                                    Text="{Binding [Title]}" TextWrapping="Wrap" Style="{StaticResource PhoneTextSubtleStyle}" />
                                    </StackPanel>
                        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">
                            <TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
                                        Style="{StaticResource PhoneTextNormalStyle}">Contact Number :</TextBlock>
                            <TextBlock Width="310" HorizontalAlignment="Left" Name="txtContact_x0020_Number"
                                        Text="{Binding [Contact_x0020_Number]}" TextWrapping="Wrap"
                                        Style="{StaticResource PhoneTextSubtleStyle}" />
                        </StackPanel>
                        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">
                            <TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
                                      Style="{StaticResource PhoneTextNormalStyle}">E-mail Address :</TextBlock>
                            <TextBlock Width="310" HorizontalAlignment="Left" Name="txtE_x002d_mail_x0020_Address"
                                  Text="{Binding [E_x002d_mail_x0020_Address]}" TextWrapping="Wrap"
                                              Style="{StaticResource PhoneTextSubtleStyle}" />
                        </StackPanel>
                        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">
                            <TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
                                      Style="{StaticResource PhoneTextNormalStyle}">Company :</TextBlock>
                            <TextBlock Width="310" HorizontalAlignment="Left" Name="txtCompany"
                                      Text="{Binding [Company]}" TextWrapping="Wrap" Style="{StaticResource PhoneTextSubtleStyle}" />
                        </StackPanel>
                        <StackPanel Margin="0,60,0,5"><Button Content="Get Orders" Height="70" Name="OrdersButton" Width="400" Click="OnButtonOrdersClick" /></StackPanel>
                    </StackPanel>
                </Grid>
            </ScrollViewer>
        </StackPanel>
    </Grid>
    
  4. [ ソリューション エクスプローラー] で DisplayForm.xaml ファイルが選択された状態で、 F7 を押し、関連付けられた分離コード ファイル DisplayForm.xaml.cs を編集用に開きます。

  5. DisplayForm 部分クラスを実装する (左かっこと右かっこで区切られた) コード ブロック内に、 OnButtonOrdersClick イベントの次のハンドラーを追加します。

    private void OnOrdersButtonClick(object sender, RoutedEventArgs e)
    {
        this.NavigationService.Navigate(new Uri("/OrdersSPListApp;component/Views/List.xaml?CustomerName=" +
                                                                     viewModel["Title"], UriKind.Relative));
    }
    
  6. ファイルを保存します。

ソリューションを構築して Windows Phone エミュレーターに展開すると、Customers リストのリスト フォームが表示されます。 指定された顧客の表示フォームを表示する項目をリストで選択すると、その顧客に関連付けられている注文を取得するためのボタンが表示されます (図 1)。

図 1. 顧客表示フォーム

顧客表示フォーム

この表示フォームの [ 注文の取得] ボタンを選択すると、その顧客の注文がソリューションの OrdersSPListApp プロジェクトのリスト フォームに表示されます (図 2)。

図 2. Orders リスト フォーム

Orders リスト フォーム

このフォーム (Orders リストのリスト フォーム) から、顧客の注文を追加、編集、または削除できます。 [キャンセル] ボタンを選択すると、Customers リストのリスト フォームに戻ります。 1 つの Phone アプリで、2 つの SharePoint リストのリスト項目を管理できます。

関連項目