Обучение
Схема обучения
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Этот браузер больше не поддерживается.
Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.
На внутреннем уровне коллекция среды выполнения Windows состоит из множества сложных подвижных частей. Но когда вы хотите передать объект коллекции в функцию среды выполнения Windows (WinRT) или реализовать собственные свойства или типы коллекции, то можете воспользоваться для этого функциями и базовыми классами C++/WinRT. Эти функции упростят весь процесс и позволят сократить затраты времени и усилий.
IVector — это интерфейс среды выполнения Windows, реализуемый любой коллекцией элементов произвольного доступа. Если же требуется реализовать сам IVector, необходимо также реализовать IIterable, IVectorView и IIterator. Даже если вам нужен пользовательский тип коллекции, это трудоемкий процесс. Но если у вас есть данные в std::vector (или в std::map, или в std::unordered_map) и вы хотите просто передать их в API среды выполнения Windows, то наверняка постараетесь избежать такой сложной работы, если это возможно. Это возможно, так как C++/WinRT поможет вам создавать коллекции эффективно и с минимальными усилиями.
Ознакомьтесь также с разделом Элементы управления XAML; привязка к коллекции C++/WinRT.
В этом разделе рассматривается сценарий, где вы хотите создать изначально пустую коллекцию, а затем заполнить ее.
Чтобы получить новый объект типа, который реализует коллекцию общего назначения, можно вызвать шаблон функции winrt::single_threaded_vector. Объект возвращается в виде интерфейса IVector, с помощью которого вызываются функции и свойства возвращенного объекта.
Если вы хотите скопировать и вставить этот пример непосредственно в главный файл исходного кода проекта консольного приложения Windows (C++/WinRT), сначала задайте параметр Не использовать предварительно скомпилированные заголовки в свойствах проекта.
// main.cpp
#include <winrt/Windows.Foundation.Collections.h>
#include <iostream>
using namespace winrt;
int main()
{
winrt::init_apartment();
Windows::Foundation::Collections::IVector<int> coll{ winrt::single_threaded_vector<int>() };
coll.Append(1);
coll.Append(2);
coll.Append(3);
for (auto const& el : coll)
{
std::cout << el << std::endl;
}
Windows::Foundation::Collections::IVectorView<int> view{ coll.GetView() };
}
Как показано в приведенном выше примере кода, после создания коллекции можно добавить элементы, выполнить их итерацию и, как правило, оперировать объектом как и любым объектом коллекции среды выполнения Windows, который вы получили из API. Если требуется неизменяемое представление коллекции, то можно вызвать IVector::GetView, как показано в примере. Приведенный выше шаблон для создания и использования коллекции подходит для простых сценариев, где вы хотите передать данные в API-интерфейс или получить данные из него. Вы можете передать IVector, или IVectorView куда угодно, где ожидается IIterable.
В примере кода выше вызов winrt::init_apartment инициализирует поток в среде выполнения Windows (по умолчанию — в многопотоковом подразделении). Вызов также инициализирует COM.
В этом разделе рассматривается сценарий, где вы хотите создать коллекцию и сразу заполнить ее.
Можно дополнительных временных затрат, связанных с вызовами Append в предыдущем примере кода. У вас уже может быть источник данных или вам может понадобиться добавить исходные данные перед созданием объекта коллекции среды выполнения Windows. Вот как это сделать.
auto coll1{ winrt::single_threaded_vector<int>({ 1,2,3 }) };
std::vector<int> values{ 1,2,3 };
auto coll2{ winrt::single_threaded_vector<int>(std::move(values)) };
for (auto const& el : coll2)
{
std::cout << el << std::endl;
}
Можно передать временный объект, содержащий данные, в winrt::single_threaded_vector, как и в coll1
выше. Или вы можете переместить std::vector (при условии, что вы не будете к нему больше обращаться) в функцию. В обоих случаях в функцию передается rvalue. Это позволяет компилятору действовать эффективно и избежать копирования данных. Если вы хотите узнать больше о значениях rvalue, ознакомьтесь с разделом Категории значений и ссылки.
Если вы хотите привязать элемент управления XAML к коллекции, это возможно. Но имейте в виду: чтобы правильно задать свойство ItemsControl.ItemsSource, необходимо присвоить ему значение типа IVector интерфейса IInspectable (или типа взаимодействия, например IBindableObservableVector).
Ниже приведен пример кода, который создает коллекцию типа, подходящего для привязывания, и добавляет в нее элемент. Контекст для этого примера кода можно найти в разделе Элементы управления XAML; привязка к коллекции C++/WinRT.
auto bookSkus{ winrt::single_threaded_vector<Windows::Foundation::IInspectable>() };
bookSkus.Append(winrt::make<Bookstore::implementation::BookSku>(L"Moby Dick"));
Вы можете создать коллекцию среды выполнения Windows на основе данных и получить представление о ней, готовое для передачи в API, вовсе ничего не копируя.
std::vector<float> values{ 0.1f, 0.2f, 0.3f };
Windows::Foundation::Collections::IVectorView<float> view{ winrt::single_threaded_vector(std::move(values)).GetView() };
В приведенных выше примерах создаваемую коллекцию можно привязать к элементу управления XAML, но эту коллекцию невозможно отслеживать.
Чтобы получить новый объект типа, который реализует отслеживаемую коллекцию, можно вызвать шаблон функции winrt::single_threaded_observable_vector с любым типом элемента. Но чтобы сделать эту коллекцию пригодной для привязки к элементу управления XAML, используйте тип элемента IInspectable.
Объект возвращается в виде интерфейса IObservableVector, с помощью которого вы (или элемент управления, к которому он привязан) вызываете функции и свойства возвращенного объекта.
auto bookSkus{ winrt::single_threaded_observable_vector<Windows::Foundation::IInspectable>() };
Примеры кода и дополнительные сведения о привязке элементов управления пользовательского интерфейса к отслеживаемой коллекции см. в разделе Элементы управления XAML; привязка к коллекции C++/WinRT.
Существуют версии ассоциативной коллекции из двух функций, которые мы рассмотрели.
При необходимости эти коллекции можно заполнить данными, передав в функцию значение rvalue типа std::map или std::unordered_map.
auto coll1{
winrt::single_threaded_map<winrt::hstring, int>(std::map<winrt::hstring, int>{
{ L"AliceBlue", 0xfff0f8ff }, { L"AntiqueWhite", 0xfffaebd7 }
})
};
std::map<winrt::hstring, int> values{
{ L"AliceBlue", 0xfff0f8ff }, { L"AntiqueWhite", 0xfffaebd7 }
};
auto coll2{ winrt::single_threaded_map<winrt::hstring, int>(std::move(values)) };
Слово "single_threaded" (однопоточный) в именах этих функций указывает, что они не обеспечивают параллельную обработку, другими словами, они не являются потокобезопасными. Упоминание потоков не связано с подразделениями, так как все объекты, возвращаемые из этих функций, являются гибкими (см. раздел Гибкие объекты в C++/WinRT). Просто эти объекты являются однопоточными. И вполне подходят, если вам нужно тем или иным способом передать данные через двоичный интерфейс приложения (ABI).
Если, чтобы обеспечить максимальную гибкость, вы хотите реализовать свою собственную пользовательскую коллекцию, необходимо выбрать легкий путь. Например, вот как будет выглядеть представление пользовательского вектора без использования базовых классов C++/WinRT.
...
using namespace winrt;
using namespace Windows::Foundation::Collections;
...
struct MyVectorView :
implements<MyVectorView, IVectorView<float>, IIterable<float>>
{
// IVectorView
float GetAt(uint32_t const) { ... };
uint32_t GetMany(uint32_t, winrt::array_view<float>) const { ... };
bool IndexOf(float, uint32_t&) { ... };
uint32_t Size() { ... };
// IIterable
IIterator<float> First() const { ... };
};
...
IVectorView<float> view{ winrt::make<MyVectorView>() };
Вместо этого гораздо проще получить представление пользовательского вектора с помощью шаблона структуры winrt::vector_view_base и просто реализовать функцию get_container, чтобы предоставить контейнер, содержащий ваши данные.
struct MyVectorView2 :
implements<MyVectorView2, IVectorView<float>, IIterable<float>>,
winrt::vector_view_base<MyVectorView2, float>
{
auto& get_container() const noexcept
{
return m_values;
}
private:
std::vector<float> m_values{ 0.1f, 0.2f, 0.3f };
};
Контейнер, возвращаемый функцией get_container, должен предоставить интерфейсы begin и end, которые ожидает winrt::vector_view_base. Как показано в примере выше, это обеспечивает std::vector. Но можно вернуть любой контейнер, удовлетворяющий этим условиям, в том числе собственный пользовательский контейнер.
struct MyVectorView3 :
implements<MyVectorView3, IVectorView<float>, IIterable<float>>,
winrt::vector_view_base<MyVectorView3, float>
{
auto get_container() const noexcept
{
struct container
{
float const* const first;
float const* const last;
auto begin() const noexcept
{
return first;
}
auto end() const noexcept
{
return last;
}
};
return container{ m_values.data(), m_values.data() + m_values.size() };
}
private:
std::array<float, 3> m_values{ 0.2f, 0.3f, 0.4f };
};
Ниже приведены базовые классы, которые C++/WinRT предоставляет для реализации пользовательских коллекций.
Ознакомьтесь с примерами кода выше.
struct MyVector :
implements<MyVector, IVector<float>, IVectorView<float>, IIterable<float>>,
winrt::vector_base<MyVector, float>
{
auto& get_container() const noexcept
{
return m_values;
}
auto& get_container() noexcept
{
return m_values;
}
private:
std::vector<float> m_values{ 0.1f, 0.2f, 0.3f };
};
struct MyObservableVector :
implements<MyObservableVector, IObservableVector<float>, IVector<float>, IVectorView<float>, IIterable<float>>,
winrt::observable_vector_base<MyObservableVector, float>
{
auto& get_container() const noexcept
{
return m_values;
}
auto& get_container() noexcept
{
return m_values;
}
private:
std::vector<float> m_values{ 0.1f, 0.2f, 0.3f };
};
struct MyMapView :
implements<MyMapView, IMapView<winrt::hstring, int>, IIterable<IKeyValuePair<winrt::hstring, int>>>,
winrt::map_view_base<MyMapView, winrt::hstring, int>
{
auto& get_container() const noexcept
{
return m_values;
}
private:
std::map<winrt::hstring, int> m_values{
{ L"AliceBlue", 0xfff0f8ff }, { L"AntiqueWhite", 0xfffaebd7 }
};
};
struct MyMap :
implements<MyMap, IMap<winrt::hstring, int>, IMapView<winrt::hstring, int>, IIterable<IKeyValuePair<winrt::hstring, int>>>,
winrt::map_base<MyMap, winrt::hstring, int>
{
auto& get_container() const noexcept
{
return m_values;
}
auto& get_container() noexcept
{
return m_values;
}
private:
std::map<winrt::hstring, int> m_values{
{ L"AliceBlue", 0xfff0f8ff }, { L"AntiqueWhite", 0xfffaebd7 }
};
};
struct MyObservableMap :
implements<MyObservableMap, IObservableMap<winrt::hstring, int>, IMap<winrt::hstring, int>, IMapView<winrt::hstring, int>, IIterable<IKeyValuePair<winrt::hstring, int>>>,
winrt::observable_map_base<MyObservableMap, winrt::hstring, int>
{
auto& get_container() const noexcept
{
return m_values;
}
auto& get_container() noexcept
{
return m_values;
}
private:
std::map<winrt::hstring, int> m_values{
{ L"AliceBlue", 0xfff0f8ff }, { L"AntiqueWhite", 0xfffaebd7 }
};
};
Обучение
Схема обучения
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization