Элементы управления XAML; привязка к коллекции C++/WinRTXAML items controls; bind to a C++/WinRT collection

Коллекция, которая может быть эффективно привязана к элементам управления XAML, называется отслеживаемой.A collection that can be effectively bound to a XAML items control is known as an observable collection. Эта идея основана на шаблоне проектирования программного обеспечения, известном как шаблон наблюдателя.This idea is based on the software design pattern known as the observer pattern. В этом разделе показано, как реализовывать отслеживаемые коллекции в C++/WinRT и привязывать к ним элементы управления XAML (вводные сведения см. в разделе Привязка данных).This topic shows how to implement observable collections in C++/WinRT, and how to bind XAML items controls to them (for background info, see Data binding).

Если вы хотите следовать инструкциям в этом разделе, рекомендуется сначала создать проект, который описан в разделе Элементы управления XAML; привязка к свойству C++/WinRT.If you want to follow along with this topic, then we recommend that you first create the project that's described in XAML controls; bind to a C++/WinRT property. В этом разделе добавляется дополнительный код для этого проекта, а также дополняются основные понятия, приведенные в том разделе.This topic adds more code to that project, and it adds to the concepts explained in that topic.

Важно!

Основные понятия и термины, которые помогают понять, как использовать и создавать классы среды выполнения с помощью C++/WinRT, описаны в разделах Использование интерфейсов API с помощью C++/WinRT и Создание интерфейсов API с помощью C++/WinRT.For essential concepts and terms that support your understanding of how to consume and author runtime classes with C++/WinRT, see Consume APIs with C++/WinRT and Author APIs with C++/WinRT.

Что означает понятие отслеживаемая для коллекции?What does observable mean for a collection?

Если класс среды выполнения, представляющий коллекцию, вызывает событие IObservableVector<T>::VectorChanged при добавлении или удалении из него элементов, значит, этот класс среды выполнения представляет собой отслеживаемую коллекцию.If a runtime class that represents a collection chooses to raise the IObservableVector<T>::VectorChanged event whenever an element is added to it or removed from it, then the runtime class is an observable collection. Элементы управления XAML могут привязываться к этим событиям и обрабатывать их путем получения обновленной коллекции и последующего самообновления для отображения текущих элементов.A XAML items control can bind to, and handle, these events by retrieving the updated collection and then updating itself to show the current elements.

Примечание

Сведения об установке и использовании расширения C++/WinRT для Visual Studio (VSIX) и пакета NuGet (которые вместе обеспечивают поддержку шаблона проекта и сборки) см. в разделе о поддержке C++/WinRT в Visual Studio.For info about installing and using the C++/WinRT Visual Studio Extension (VSIX) and the NuGet package (which together provide project template and build support), see Visual Studio support for C++/WinRT.

Добавление коллекции BookSkus в BookstoreViewModelAdd a BookSkus collection to BookstoreViewModel

В разделе Элементы управления XAML; привязка к свойству C++/WinRT мы добавили свойство типа BookSku к нашей модели главного представления.In XAML controls; bind to a C++/WinRT property, we added a property of type BookSku to our main view model. На этом шаге мы используем стандартный шаблон функции winrt::single_threaded_observable_vector, который поможет нам реализовать отслеживаемую коллекцию BookSku для той же модели представления.In this step, we'll use the winrt::single_threaded_observable_vector factory function template to help us implement an observable collection of BookSku on the same view model.

Объявите новое свойство в BookstoreViewModel.idl.Declare a new property in BookstoreViewModel.idl.

// BookstoreViewModel.idl
...
runtimeclass BookstoreViewModel
{
    BookSku BookSku{ get; };
    Windows.Foundation.Collections.IObservableVector<BookSku> BookSkus{ get; };
}
...

Примечание

Обратите внимание, что в приведенном выше листинге MIDL 3.0 типом свойства BookSkus является IObservableVectorBookSku.In the MIDL 3.0 listing above, note that the type of the BookSkus property is IObservableVector of BookSku. В следующем подразделе этого раздела мы привяжем источник элементов ListBox к BookSkus.In the next section of this topic, we'll be binding the items source of a ListBox to BookSkus. Список — это элемент управления элементами. Чтобы правильно задать свойство ItemsControl.ItemsSource, необходимо присвоить значение типа IObservableVector (или IVector) или типа взаимодействия, например IBindableObservableVector.A list box is an items control, and to correctly set the ItemsControl.ItemsSource property, you need to set it to a value of type IObservableVector, or IVector, or of an interoperability type such as IBindableObservableVector.

Предупреждение

Код, представленный в этом разделе, относится к C++/WinRT 2.0.190530.8 и более поздних версий.The code shown in this topic applies to C++/WinRT version 2.0.190530.8 and higher. Если вы используете более раннюю версию, нужно внести в приведенный код несколько незначительных изменений.If you're using an earlier version, then you'll need to make some minor tweaks to the code shown. В приведенном выше листинге MIDL 3.0 измените значение свойства BookSkus на IObservableVector интерфейса IInspectable.In the MIDL 3.0 listing above, change the BookSkus property to IObservableVector of IInspectable. А затем также используйте в соей реализации IInspectable (а не BookSku).And then use IInspectable (instead of BookSku) in your implementation, too.

Сохраните проект и выполните сборку.Save and build. Скопируйте заглушки метода доступа из BookstoreViewModel.h и BookstoreViewModel.cpp в папку \Bookstore\Bookstore\Generated Files\sources (дополнительные сведения см. в предыдущем разделе, Элементы управления XAML; привязка к свойству C++/WinRT).Copy the accessor stubs from BookstoreViewModel.h and BookstoreViewModel.cpp in the \Bookstore\Bookstore\Generated Files\sources folder (for more details, see the previous topic, XAML controls; bind to a C++/WinRT property). Реализуйте эти заглушки метода доступа следующим образом.Implement those accessor stubs like this.

// 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 к свойству BookSkusBind a ListBox to the BookSkus property

Откройте файл MainPage.xaml, который содержит разметку XAML для главной страницы пользовательского интерфейса.Open MainPage.xaml, which contains the XAML markup for our main UI page. Добавьте следующую разметку внутри того же элемента StackPanel, что и Button.Add the following markup inside the same StackPanel as the Button.

<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 для добавления книги в коллекцию.In MainPage.cpp, add a line of code to the Click event handler to append a book to the collection.

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

Теперь выполните сборку и запустите проект.Now build and run the project. Нажмите кнопку, чтобы запустить обработчик события Click.Click the button to execute the Click event handler. Мы увидели, что реализация Append вызывает событие, чтобы сообщить пользовательскому интерфейсу о том, что коллекция изменилась, а ListBox повторно запрашивает коллекцию, чтобы обновить свое собственное значение Items.We saw that the implementation of Append raises an event to let the UI know that the collection has changed; and the ListBox re-queries the collection to update its own Items value. Так же, как и раньше, меняется название одной из книг, и это изменение отражается как на кнопке, так и в списке.Just as before, the title of one of the books changes; and that title change is reflected both on the button and in the list box.

Важные APIImportant APIs