XAML アイテム コントロール: C++/WinRT コレクションへのバインド
XAML アイテム コントロールに効果的にバインドできるコレクションは、"監視可能な" コレクションと呼ばれます。 この概念は、"オブザーバー パターン" と呼ばれるソフトウェアの設計パターンに基づいています。 このトピックでは、C++/WinRT で監視可能なコレクションを実装する方法と、これらに XAML コントロールをバインドする方法を示します (背景情報については、「データ バインディング」をご覧ください)。
このトピックを理解するには、「XAML コントロール: C++/WinRT プロパティへのバインド」に記載されているプロジェクトを最初に作成することをお勧めします。 このトピックでは、そのプロジェクトにさらにコードを追加し、そのトピックで説明されている概念が補足されます。
重要
C++/WinRT でランタイム クラスを使用および作成する方法についての理解をサポートするために重要な概念と用語については、「C++/WinRT での API の使用」と「C++/WinRT での作成者 API」を参照してください。
コレクションに対する "監視可能" の意味とは
コレクションを表すランタイム クラスによって、要素が追加または削除されるたびに IObservableVector<T>::VectorChanged イベントが発生する場合、ランタイム クラスは監視可能なコレクションです。 XAML アイテム コントロールでは、更新されたコレクションを取得して、現在の要素を表示するためにそれ自体を更新することで、これらのイベントをバインドし、処理することができます。
注意
C++/WinRT Visual Studio Extension (VSIX) と NuGet パッケージ (両者が連携してプロジェクト テンプレートとビルドをサポート) のインストールと使用については、Visual Studio での C++/WinRT のサポートに関する記事を参照してください。
BookstoreViewModel に BookSkus コレクションを追加する
「XAML コントロール: C++/WinRT プロパティへのバインド」では、BookSku 型のプロパティをメイン ビュー モデルに追加しました。. この手順では、winrt::single_threaded_observable_vector ファクトリ関数テンプレートを使用します。これは、同じビュー モデルに対して BookSku の監視可能なコレクションを実装するのに役に立ちます。
BookstoreViewModel.idl
で新しいプロパティを宣言します。
// BookstoreViewModel.idl
...
runtimeclass BookstoreViewModel
{
BookSku BookSku{ get; };
Windows.Foundation.Collections.IObservableVector<BookSku> BookSkus{ get; };
}
...
注意
上記の MIDL 3.0 のリストでは、BookSkus プロパティの型が BookSku の IObservableVector であることに注意してください。 このトピックの次のセクションでは、ListBox の項目ソースを BookSkus にバインドします。 リスト ボックスは項目コントロールです。ItemsControl.ItemsSource プロパティを正しく設定するには、それを IObservableVector 型の値、IVector 型の値、または IBindableObservableVector などの相互運用性型の値に設定する必要があります。
警告
このトピックで示すコードの適用対象は、C++/WinRT バージョン 2.0.190530.8 以降です。 それより前のバージョンを使っている場合は、示されているコードを若干調整する必要があります。 上記の MIDL 3.0 のリストでは、BookSkus プロパティを IInspectable の IObservableVector に変更します。 その後、実装でも (BookSku の代わりに) IInspectable を使います。
保存してビルドします。 \Bookstore\Bookstore\Generated Files\sources
フォルダー内の BookstoreViewModel.h
および BookstoreViewModel.cpp
からアクセサー スタブをコピーします (詳細については、前のトピック「XAML コントロール: C++/WinRT プロパティへのバインド」を参照してください)。 それらのアクセサー スタブを次のように実装します。
// BookstoreViewModel.h
...
struct BookstoreViewModel : BookstoreViewModelT<BookstoreViewModel>
{
BookstoreViewModel();
Bookstore::BookSku BookSku();
Windows::Foundation::Collections::IObservableVector<Bookstore::BookSku> BookSkus();
private:
Bookstore::BookSku m_bookSku{ nullptr };
Windows::Foundation::Collections::IObservableVector<Bookstore::BookSku> m_bookSkus;
};
...
// BookstoreViewModel.cpp
...
BookstoreViewModel::BookstoreViewModel()
{
m_bookSku = winrt::make<Bookstore::implementation::BookSku>(L"Atticus");
m_bookSkus = winrt::single_threaded_observable_vector<Bookstore::BookSku>();
m_bookSkus.Append(m_bookSku);
}
Bookstore::BookSku BookstoreViewModel::BookSku()
{
return m_bookSku;
}
Windows::Foundation::Collections::IObservableVector<Bookstore::BookSku> BookstoreViewModel::BookSkus()
{
return m_bookSkus;
}
...
BookSkus プロパティに ListBox をバインドする
MainPage.xaml
を開くと、メイン UI ページの XAML マークアップが含まれています。 同じ StackPanel 内に次のマークアップをボタンとして追加します。
<ListBox ItemsSource="{x:Bind MainViewModel.BookSkus}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:BookSku">
<TextBlock Text="{x:Bind Title, Mode=OneWay}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
MainPage.cpp
で、クリック イベント ハンドラーにコードの行を追加してブックをコレクションに追加します。
// MainPage.cpp
...
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
MainViewModel().BookSku().Title(L"To Kill a Mockingbird");
MainViewModel().BookSkus().Append(winrt::make<Bookstore::implementation::BookSku>(L"Moby Dick"));
}
...
ここでプロジェクトをビルドして実行します。 ボタンをクリックして Click イベント ハンドラーを実行します。 Append の実装では、コレクションが変更されたことを UI に通知するイベントが発生することがわかります。ListBox はコレクションを再クエリして、独自の Items 値を更新します。 前と同じように、1 つのブックのタイトルが変わります。また、ボタンとリスト ボックスの両方にタイトルの変更が反映されます。