XAML 項目控制;綁定到 C++/WinRT 集合

一個能有效綁定到 XAML 項目控制項的集合稱為 可觀察 集合。 這個想法基於一種稱為 觀察者模式的軟體設計模式。 本主題說明如何在 C++/WinRT 中實作可觀察集合,以及如何將 XAML 項目控制項綁定到它們(背景資訊請參見 資料綁定)。

如果你想跟著這個主題走,建議你先建立 XAML 控制項描述的專案;綁定到 C++/WinRT 屬性。 這個主題為該專案增加了更多程式碼,也豐富了該主題中所解釋的概念。

這很重要

關於支持你如何使用 C++/WinRT 撰寫執行時類別的基本概念與術語,請參見 Consume API with C++/WinRTAuthor API with C++/WinRT

對於集合來說, 可觀察 性是什麼意思?

如果代表集合的執行階段類別選擇在每當有元素加入或從中移除時引發 IObservableVector<T>::VectorChanged 事件,則該執行階段類別就是可觀察集合。 XAML 項目控制項可以透過取得更新後的集合,然後自行更新以顯示目前元素來綁定並處理這些事件。

Note

關於安裝及使用 C++/WinRT Visual Studio 擴充套件(VSIX)及 NuGet 套件(共同提供專案範本與建置支援)的資訊,請參閱 Visual Studio 對 C++/WinRT 的支援

將 BookSkus 收藏加入 BookstoreViewModel

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

這很重要

使用 C++/WinRT 繫結至集合時,會比使用 C# 稍微複雜一些。 在上述 MIDL 3.0 清單中,請注意 BookSkus 屬性的類型是 BookSkuIObservableVector。 在本主題的下一節,我們將將 ListBox 的來源項目綁定到 BookSkus。 清單框是項目控制項,要正確設定 ItemsControl.ItemsSource 屬性,你需要將其設為 IObservableVectorIVector 類型,或是互通型別如 IBindableObservableVector。 否則,{x:Bind} 會產生 E_INVALIDARG,而 {Binding} 會靜默失敗。

Warning

本主題所示程式碼適用於 C++/WinRT 版本 2.0.190530.8 或更新版本。 如果你用的是較早版本,就需要對顯示的程式碼做些小調整。 在上述 MIDL 3.0 列表中,將 BookSkus 屬性改為 IInspectableIObservableVector。 然後在實作中也用 IInspectable (取代 BookSku)。

存檔並建造。 將 \Bookstore\Bookstore\Generated Files\sources 資料夾中 BookstoreViewModel.hBookstoreViewModel.cpp 的存取子存根複製過來(如需詳細資訊,請參閱上一個主題:XAML 控制項;繫結至 C++/WinRT 屬性)。 像這樣實作那些 accessor stub。

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

將 ListBox 綁定到 BookSkus 屬性

開啟 MainPage.xaml,其中包含我們主要UI頁面的 XAML 標記。 在與按鈕相同的堆疊面板內加入以下標記。

<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中,為 Click 事件處理 程序新增一行程式碼,將書籍附加到集合中。

// 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"));
}
...

現在建置並執行專案。 點擊按鈕執行 點擊 事件處理程序。 我們看到 Append 的實作會觸發事件,讓 UI 知道集合已經變更;而 ListBox 則會重新查詢集合以更新自身 的 Items 值。 和之前一樣,其中一本書的書名也改變了;而這個標題的變更會同時反映在按鈕和列表框中。

重要 API