Шаблон функции winrt::single_threaded_observable_vector (C++/WinRT)
Шаблон функции, который создает и возвращает объект типа, реализующего наблюдаемую коллекцию. Объект возвращается как IObservableVector, и это интерфейс, через который вы вызываете функции и свойства возвращаемого объекта.
При необходимости можно передать существующее значение std::vectorrvalue в функцию— передать временный объект или вызвать std::move для lvalue.
Дополнительные сведения и примеры кода см. в разделе "Коллекции" с помощью C++/WinRT.
Синтаксис
template <typename T, typename Allocator = std::allocator<T>>
winrt::Windows::Foundation::Collections::IObservableVector<T> single_threaded_observable_vector(std::vector<T, Allocator>&& values = {})
Параметры шаблона
typename T
Тип элементов коллекции.
typename Allocator
Тип распределителя вектора, из которого инициализируется коллекция, если передать его, в противном случае — распределитель по умолчанию.
Параметры
values
Необязательная ссылка на rvalue типа std::vector , из которой инициализировать элементы объекта коллекции.
Возвращаемое значение
Объект IObservableVector , представляющий новый объект коллекции.
Требования
Минимальный поддерживаемый пакет SDK: пакет SDK Windows версии 10.0.17763.0 (Windows 10, версия 1809)
Пространство имен: winrt
Заголовок: %WindowsSdkDir%IncludeWindowsTargetPlatformVersion<>\cppwinrt\winrt\base.h (включен по умолчанию)
Если у вас есть более ранняя версия пакета SDK для Windows
Если у вас нет пакета SDK Windows версии 10.0.17763.0 (Windows 10, версия 1809) или более поздней версии, вам потребуется реализовать собственный отслеживаемый шаблон вектора, чтобы служить полезной, универсальной реализацией IObservableVectorT<>. Ниже приведен список класса с именем single_threaded_observable_vector< T>. Вы можете легко переключиться с типа ниже на winrt::single_threaded_observable_vector, если вы используете версию пакета SDK Windows, содержащего его.
// single_threaded_observable_vector.h
#pragma once
namespace winrt::Bookstore::implementation
{
using namespace Windows::Foundation::Collections;
template <typename T>
struct single_threaded_observable_vector : implements<single_threaded_observable_vector<T>,
IObservableVector<T>,
IVector<T>,
IVectorView<T>,
IIterable<T>>
{
event_token VectorChanged(VectorChangedEventHandler<T> const& handler)
{
return m_changed.add(handler);
}
void VectorChanged(event_token const cookie)
{
m_changed.remove(cookie);
}
T GetAt(uint32_t const index) const
{
if (index >= m_values.size())
{
throw hresult_out_of_bounds();
}
return m_values[index];
}
uint32_t Size() const noexcept
{
return static_cast<uint32_t>(m_values.size());
}
IVectorView<T> GetView()
{
return *this;
}
bool IndexOf(T const& value, uint32_t& index) const noexcept
{
index = static_cast<uint32_t>(std::find(m_values.begin(), m_values.end(), value) - m_values.begin());
return index < m_values.size();
}
void SetAt(uint32_t const index, T const& value)
{
if (index >= m_values.size())
{
throw hresult_out_of_bounds();
}
++m_version;
m_values[index] = value;
m_changed(*this, make<args>(CollectionChange::ItemChanged, index));
}
void InsertAt(uint32_t const index, T const& value)
{
if (index > m_values.size())
{
throw hresult_out_of_bounds();
}
++m_version;
m_values.insert(m_values.begin() + index, value);
m_changed(*this, make<args>(CollectionChange::ItemInserted, index));
}
void RemoveAt(uint32_t const index)
{
if (index >= m_values.size())
{
throw hresult_out_of_bounds();
}
++m_version;
m_values.erase(m_values.begin() + index);
m_changed(*this, make<args>(CollectionChange::ItemRemoved, index));
}
void Append(T const& value)
{
++m_version;
m_values.push_back(value);
m_changed(*this, make<args>(CollectionChange::ItemInserted, Size() - 1));
}
void RemoveAtEnd()
{
if (m_values.empty())
{
throw hresult_out_of_bounds();
}
++m_version;
m_values.pop_back();
m_changed(*this, make<args>(CollectionChange::ItemRemoved, Size()));
}
void Clear() noexcept
{
++m_version;
m_values.clear();
m_changed(*this, make<args>(CollectionChange::Reset, 0));
}
uint32_t GetMany(uint32_t const startIndex, array_view<T> values) const
{
if (startIndex >= m_values.size())
{
return 0;
}
uint32_t actual = static_cast<uint32_t>(m_values.size() - startIndex);
if (actual > values.size())
{
actual = values.size();
}
std::copy_n(m_values.begin() + startIndex, actual, values.begin());
return actual;
}
void ReplaceAll(array_view<T const> value)
{
++m_version;
m_values.assign(value.begin(), value.end());
m_changed(*this, make<args>(CollectionChange::Reset, 0));
}
IIterator<T> First()
{
return make<iterator>(this);
}
private:
std::vector<T> m_values;
event<VectorChangedEventHandler<T>> m_changed;
uint32_t m_version{};
struct args : implements<args, IVectorChangedEventArgs>
{
args(CollectionChange const change, uint32_t const index) :
m_change(change),
m_index(index)
{
}
CollectionChange CollectionChange() const
{
return m_change;
}
uint32_t Index() const
{
return m_index;
}
private:
Windows::Foundation::Collections::CollectionChange const m_change{};
uint32_t const m_index{};
};
struct iterator : implements<iterator, IIterator<T>>
{
explicit iterator(single_threaded_observable_vector<T>* owner) noexcept :
m_version(owner->m_version),
m_current(owner->m_values.begin()),
m_end(owner->m_values.end())
{
m_owner.copy_from(owner);
}
void abi_enter() const
{
if (m_version != m_owner->m_version)
{
throw hresult_changed_state();
}
}
T Current() const
{
if (m_current == m_end)
{
throw hresult_out_of_bounds();
}
return*m_current;
}
bool HasCurrent() const noexcept
{
return m_current != m_end;
}
bool MoveNext() noexcept
{
if (m_current != m_end)
{
++m_current;
}
return HasCurrent();
}
uint32_t GetMany(array_view<T> values)
{
uint32_t actual = static_cast<uint32_t>(std::distance(m_current, m_end));
if (actual > values.size())
{
actual = values.size();
}
std::copy_n(m_current, actual, values.begin());
std::advance(m_current, actual);
return actual;
}
private:
com_ptr<single_threaded_observable_vector<T>> m_owner;
uint32_t const m_version;
typename std::vector<T>::const_iterator m_current;
typename std::vector<T>::const_iterator const m_end;
};
};
}
Функция Append показывает, как вызывать событие IObservableVector<T>::VectorChanged.
m_changed(*this, make<args>(CollectionChange::ItemInserted, Size() - 1));
Аргументы события указывают на то, что был вставлен элемент, а также на то, каков его индекс (в данном случае это последний элемент). Эти аргументы позволяют элементу управления XAML реагировать на событие и обновляться оптимальным способом.
Вот как вы создадите экземпляр типа, определенного выше. Вместо вызова шаблона функции winrt::single_threaded_observable_vector фабрики создается объект коллекции путем вызова winrt::make.
#include "single_threaded_observable_vector.h"
...
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable> m_bookSkus;
...
m_bookSkus = winrt::make<winrt::Bookstore::implementation::single_threaded_observable_vector<winrt::Windows::Foundation::IInspectable>>();
См. также раздел
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по