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 包(它们共同提供项目模板和生成支持)的信息,请参阅 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 属性的类型 BookSku的 IObservableVector。 在本主题的下一部分中,我们将将 ListBox 的项源绑定到 BookSkus。 列表框是项控件,为了正确设置 ItemsControl.ItemsSource 属性,需要将其设为类型为 IObservableVectorIVector或如 IBindableObservableVector的互操作类型的值。 否则, {x:Bind} 将生成 E_INVALIDARG,并且 {Binding} 会以无提示方式失败。

警告

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

保存并生成。 从 BookstoreViewModel.h 文件夹中的 BookstoreViewModel.cpp\Bookstore\Bookstore\Generated Files\sources 复制属性存根(有关详细信息,请参阅上一主题,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 标记。 在与 按钮相同的 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"));
}
...

现在生成并运行项目。 点击按钮以运行 点击 事件处理程序。 我们看到,Append 的实现引发了一个事件,通知 UI 集合已更改;随后,ListBox 会重新查询集合,以便更新其 的值。 就像以前一样,其中一本书的标题发生了变化:并且标题更改同时反映在按钮和列表框中。

重要 API