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 扩展 (VSIX) 和 NuGet 包(两者共同提供项目模板,并生成支持)的信息,请参阅适用于 C++/WinRT 的 Visual Studio 支持

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

注意

在上述 MIDL 3.0 列表中,注意 BookSkus 属性的类型是 BookSkuIObservableVector。 在本主题的下一节中,我们会将 ListBox 的项目源绑定到 BookSkus。 列表框是项控件,用于正确设置 ItemsControl.ItemsSource 属性,你需要将其设置为某个类型为 IObservableVectorIVector 的值,或者某个互操作性类型(例如 IBindableObservableVector)的值。

警告

本主题中显示的代码适用于 C++/WinRT 2.0.190530.8 或更高版本。 如果使用更低版本,则需对所示代码进行一些细微调整。 在上述 MIDL 3.0 列表中,请将 BookSkus 属性更改为 IInspectableIObservableVector。 然后,在实现中也使用 IInspectable(而不是 BookSku)。

保存并生成。 复制 \Bookstore\Bookstore\Generated Files\sources 文件夹中 BookstoreViewModel.hBookstoreViewModel.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;
}
...

将 ListBox 绑定到 BookSkus 属性

打开 MainPage.xaml,其中包含主 UI 页面的 XAML 标记。 在与 Button 相同的 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 中,将一行代码添加到 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"));
}
...

立即生成并运行该项目。 单击该按钮以执行 Click 事件处理程序。 我们看到了追加的实现引发了让 UI 知道该集合已发生更改的事件;而且 ListBox 重新查询了集合以更新其自己的“项目”值。 和以前一样,其中一本书籍的标题发生了更改;而且该标题更改反映在按钮上和列表框中。

重要的 API