Verzamelingen met C++/WinRT

Intern gezien heeft een Windows Runtime-verzameling veel complexe onderdelen. Maar als u een verzamelingsobject wilt doorgeven aan een Windows Runtime functie of als u uw eigen verzamelingseigenschappen en verzamelingstypen wilt implementeren, zijn er functies en basisklassen in C++/WinRT ter ondersteuning van u. Deze functies nemen de complexiteit uit uw handen en besparen u veel overhead in tijd en moeite.

IVector is de Windows Runtime interface die wordt geïmplementeerd door een verzameling elementen met willekeurige toegang. Als u IVector zelf zou implementeren, moet u ook IIterable, IVectorView en IIterator implementeren. Zelfs als u een aangepast verzamelingstype nodig hebt , is dat veel werk. Maar als u gegevens in een std::vector (of een std::map of een std::unordered_map) hebt en u dat alleen wilt doorgeven aan een Windows Runtime-API, wilt u zo mogelijk voorkomen dat u dat werkniveau uitvoert. En het vermijden van dit is mogelijk, omdat C++/WinRT u helpt om verzamelingen efficiënt en met weinig inspanning te maken.

Zie ook besturingselementen voor XAML-items; bind aan een C++/WinRT-verzameling.

Helper-functies voor verzamelingen

Verzameling voor algemeen gebruik, leeg

In deze sectie wordt het scenario behandeld waarin u een verzameling wilt maken die in eerste instantie leeg is; en vul deze vervolgens in na het maken.

Als u een nieuw object wilt ophalen van een type dat een verzameling voor algemeen gebruik implementeert, kunt u de functiesjabloon winrt::single_threaded_vector aanroepen. Het object wordt geretourneerd als een IVector en dat is de interface waarmee u de functies en eigenschappen van het geretourneerde object aanroept.

Als u de volgende codevoorbeelden rechtstreeks wilt kopiëren en plakken in het hoofdbroncodebestand van een Windows Console Application (C++/WinRT)-project, stelt u dan eerst Voorgecompileerde headers niet gebruiken in bij de projecteigenschappen.

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

Zoals u in het bovenstaande codevoorbeeld kunt zien, kunt u na het maken van de verzameling elementen toevoegen, deze herhalen en het object over het algemeen behandelen zoals elk Windows Runtime verzamelingsobject dat u mogelijk hebt ontvangen van een API. Als u een onveranderbare weergave over de verzameling nodig hebt, kunt u IVector::GetView aanroepen, zoals wordt weergegeven. Het bovenstaande patroon, van het maken en gebruiken van een verzameling, is geschikt voor eenvoudige scenario's waarin u gegevens wilt doorgeven aan of gegevens uit een API wilt ophalen. U kunt een IVector of een IVectorView overal doorgeven waar een IIterable wordt verwacht.

In het bovenstaande codevoorbeeld initialiseert de aanroep van winrt::init_apartment de thread in de Windows Runtime standaard als multithreaded apartment. De aanroep initialiseert ook COM.

Verzameling voor algemeen gebruik, geprimeerd uit gegevens

In deze sectie wordt het scenario behandeld waarin u een verzameling wilt maken en deze tegelijkertijd wilt vullen.

U kunt de overhead van de aanroepen van Append in het vorige codevoorbeeld vermijden. Mogelijk hebt u de brongegevens al of wilt u de brongegevens vullen voordat u het Windows Runtime verzamelingsobject maakt. Dit doet u als volgt.

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

U kunt een tijdelijk object met uw gegevens doorgeven aan winrt::single_threaded_vector, zoals hierboven coll1. Of u kunt een std::vector (ervan uitgaande dat u deze niet opnieuw opent) naar de functie verplaatsen. In beide gevallen geeft u een rvalue door aan de functie. Hierdoor kan de compiler efficiënt zijn en voorkomen dat de gegevens worden gekopieerd. Als u meer wilt weten over rvalues, raadpleegt u waardecategorieën en verwijzingen naar deze categorieën.

Als u een besturingselement voor XAML-items aan uw verzameling wilt koppelen, kunt u dat. Houd er echter rekening mee dat u de eigenschap ItemsControl.ItemsSource correct wilt instellen op een waarde van het type IVector van IInspectable (of van een interoperabiliteitstype zoals IBindableObservableVector).

Hier volgt een codevoorbeeld dat een verzameling van een type produceert dat geschikt is voor binding en een element eraan toevoegt. U vindt de context voor dit codevoorbeeld in XAML-itembesturingselementen; binden aan een C++/WinRT-verzameling.

auto bookSkus{ winrt::single_threaded_vector<Windows::Foundation::IInspectable>() };
bookSkus.Append(winrt::make<Bookstore::implementation::BookSku>(L"Moby Dick"));

U kunt een Windows Runtime verzameling maken op basis van gegevens en er een weergave van maken die klaar is om door te geven aan een API, allemaal zonder iets te kopiëren.

std::vector<float> values{ 0.1f, 0.2f, 0.3f };
Windows::Foundation::Collections::IVectorView<float> view{ winrt::single_threaded_vector(std::move(values)).GetView() };

In de bovenstaande voorbeelden kan de verzameling die we maken, worden gebonden aan een besturingselement voor XAML-items; maar de verzameling is niet waarneembaar.

Waarneembare verzameling

Als u een nieuw object wilt ophalen van een type dat een waarneembare verzameling implementeert, roept u de winrt::single_threaded_observable_vector functiesjabloon aan met elk elementtype. Maar als u een waarneembare verzameling geschikt wilt maken voor binding met een besturingselement voor XAML-items, gebruikt u IInspectable als het elementtype.

Het object wordt geretourneerd als een IObservableVector en dat is de interface waarmee u (of het besturingselement waaraan het is gebonden) de functies en eigenschappen van het geretourneerde object aanroept.

auto bookSkus{ winrt::single_threaded_observable_vector<Windows::Foundation::IInspectable>() };

Zie XAML-itembesturingselementen; binden aan een C++/WinRT-verzameling voor meer informatie en codevoorbeelden over het binden van besturingselementen van uw gebruikersinterface (UI) aan een observeerbare verzameling.

Associatieve verzameling (kaart)

Er zijn associatieve verzamelingsversies van de twee functies die we hebben bekeken.

U kunt deze verzamelingen desgewenst primeren met gegevens door te geven aan de functie een rvalue van het type std::map of 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)) };

Met één thread

De 'single-threaded' in de namen van deze functies geeft aan dat ze geen gelijktijdigheid bieden, met andere woorden, ze zijn niet thread-veilig. De vermelding van threads is niet gerelateerd aan appartementen, omdat de objecten die zijn geretourneerd door deze functies allemaal agile zijn (zie Agile-objecten in C++/WinRT). Het is alleen dat de objecten één thread hebben. En dat is helemaal geschikt als u alleen gegevens wilt doorgeven op één manier of de andere via de binaire interface (ABI) van de toepassing.

Basisklassen voor verzamelingen

Als u voor volledige flexibiliteit uw eigen verzameling op maat wilt implementeren, kunt u dat beter niet op de moeilijke manier doen. Dit is bijvoorbeeld hoe een aangepaste vectorweergave eruit zou zien zonder de hulp van de basisklassen van 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>() };

In plaats daarvan is het veel eenvoudiger om uw aangepaste vectorweergave af te leiden van de winrt::vector_view_base struct-sjabloon en de get_container-functie alleen te implementeren om de container met uw gegevens beschikbaar te maken.

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

De container die door get_container wordt geretourneerd, moet de begin - en eindinterface opgeven die winrt::vector_view_base verwacht. Zoals wordt weergegeven in het bovenstaande voorbeeld, biedt std::vector dat. Maar u kunt elke container retourneren die aan hetzelfde contract voldoet, inclusief uw eigen aangepaste container.

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

Dit zijn de basisklassen die C++/WinRT biedt om u te helpen aangepaste verzamelingen te implementeren.

winrt::vector_view_base

Zie de bovenstaande codevoorbeelden.

winrt::vector_base

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

winrt::observable_vector_base

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

winrt::map_view_base

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

winrt::map_base

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

winrt::observable_map_base

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

Belangrijke API's