Raccolte con C++/WinRTCollections with C++/WinRT

Internamente, una raccolta di Windows Runtime dispone di molte parti mobili complicate.Internally, a Windows Runtime collection has a lot of complicated moving parts. Tuttavia, quando vuoi passare un oggetto raccolta a una funzione di Windows Runtime o implementare proprietà e tipi di raccolta personalizzati, sono disponibili nuove funzioni e classi di base C++/WinRT che possono aiutarti.But when you want to pass a collection object to a Windows Runtime function, or to implement your own collection properties and collection types, there are functions and base classes in C++/WinRT to support you. Queste funzionalità eliminano le complessità e consentono di risparmiare molto tempo e fatica.These features take the complexity out of your hands, and save you a lot of overhead in time and effort.

IVector è l'interfaccia di Windows Runtime implementata da qualsiasi raccolta di elementi ad accesso casuale.IVector is the Windows Runtime interface implemented by any random-access collection of elements. Se implementassi IVector tu stesso, dovresti implementare anche IIterable, IVectorView e IIterator.If you were to implement IVector yourself, you'd also need to implement IIterable, IVectorView, and IIterator. Anche se avessi bisogno di un tipo di raccolta personalizzato avresti molto lavoro da svolgere.Even if you need a custom collection type, that's a lot of work. Se invece disponi di dati in uno std::vector (oppure uno std::map o uno std::unordered_map) e vuoi solo passarli a un'API di Windows Runtime, preferirai, se è possibile, evitare tutto quel lavoro.But if you have data in a std::vector (or a std::map, or a std::unordered_map) and all you want to do is pass that to a Windows Runtime API, then you'd want to avoid doing that level of work, if possible. In effetti è possibile, perché C++/WinRT ti aiuta a creare raccolte in modo efficiente e con un minimo sforzo.And avoiding it is possible, because C++/WinRT helps you to create collections efficiently and with little effort.

Vedi anche Controlli di elementi XAML, binding a una raccolta C++/WinRT.Also see XAML items controls; bind to a C++/WinRT collection.

Funzioni di supporto per le raccolteHelper functions for collections

Raccolta per uso generico, vuotaGeneral-purpose collection, empty

Questa sezione descrive lo scenario in cui si desidera creare una raccolta che è inizialmente vuota e quindi popolarla dopo la creazione.This section covers the scenario where you wish to create a collection that's initially empty; and then populate it after creation.

Per recuperare un nuovo oggetto di un tipo che implementa una raccolta per uso generico, è possibile chiamare il modello di funzione winrt::single_threaded_vector.To retrieve a new object of a type that implements a general-purpose collection, you can call the winrt::single_threaded_vector function template. L'oggetto viene restituito come un'IVector e si tratta dell'interfaccia tramite cui vengono chiamate funzioni e proprietà dell'oggetto restituito.The object is returned as an IVector, and that's the interface via which you call the returned object's functions and properties.

Se vuoi copiare e incollare i seguenti esempi di codice direttamente nel file di codice sorgente principale di un progetto Applicazione console Windows (C++/WinRT) , imposta prima di tutto Senza intestazioni precompilate nelle proprietà del progetto.If you want to copy-paste the following code examples directly into the main source code file of a Windows Console Application (C++/WinRT) project, then first set Not Using Precompiled Headers in project properties.

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

Come puoi vedere nell'esempio di codice precedente, dopo aver creato la raccolta è possibile aggiungere elementi, eseguire iterazioni su essi e in genere trattare l'oggetto come si farebbe con qualsiasi oggetto raccolta di Windows Runtime ricevuto da un'API.As you can see in the code example above, after creating the collection you can append elements, iterate over them, and generally treat the object as you would any Windows Runtime collection object that you might have received from an API. Se hai bisogno di una visualizzazione immutabile sulla raccolta, puoi chiamare IVector::GetView, come mostrato.If you need an immutable view over the collection, then you can call IVector::GetView, as shown. Il modello illustrato in precedenza, di creazione e uso di una raccolta, è appropriato per scenari semplici in cui si vuole passare dati o recuperare dati da un'API.The pattern shown above—of creating and consuming a collection—is appropriate for simple scenarios where you want to pass data into, or get data out of, an API. Puoi passare un'IVector, o un'IVectorView, ovunque sia prevista un'IIterable.You can pass an IVector, or an IVectorView, anywhere an IIterable is expected.

La chiamata a winrt::init_apartment nell'esempio di codice riportato sopra inizializza il thread in Windows Runtime in un apartment a thread multipli per impostazione predefinita.In the code example above, the call to winrt::init_apartment initializes the thread in the Windows Runtime; by default, in a multithreaded apartment. La chiamata inizializza anche COM.The call also initializes COM.

Raccolta per uso generico, preparata con i datiGeneral-purpose collection, primed from data

Questa sezione descrive lo scenario in cui si desidera creare una raccolta e popolarla contemporaneamente.This section covers the scenario where you wish to create a collection and populate it at the same time.

È possibile evitare il sovraccarico delle chiamate ad Append nell'esempio di codice precedente.You can avoid the overhead of the calls to Append in the previous code example. I dati di origine possono essere già disponibili oppure si più preferire popolarli prima di creare l'oggetto raccolta di Windows Runtime.You may already have the source data, or you may prefer to populate the source data in advance of creating the Windows Runtime collection object. Ecco come farlo.Here's how to do that.

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

Puoi passare un oggetto temporaneo che contiene i dati a winrt::single_threaded_vector, come con coll1 sopra.You can pass a temporary object containing your data to winrt::single_threaded_vector, as with coll1, above. Oppure puoi spostare uno std::Vector, se non vi accederai più, nella funzione.Or you can move a std::vector (assuming you won't be accessing it again) into the function. In entrambi i casi si passa un rvalue alla funzione.In both cases, you're passing an rvalue into the function. In questo modo il compilatore diventa più efficiente ed evita di copiare i dati.That enables the compiler to be efficient and to avoid copying the data. Se vuoi saperne di più sugli rvalue, vedi Categorie di valore e riferimenti.If you want to know more about rvalues, see Value categories, and references to them.

Se vuoi associare un controllo di elementi XAML alla raccolta, puoi farlo.If you want to bind a XAML items control to your collection, then you can. Tieni presente però che per impostare correttamente la proprietà ItemsControl.ItemsSource devi impostarla su un valore di tipo IVector di IInspectable o di un tipo di interoperabilità, ad esempio IBindableObservableVector.But be aware that to correctly set the ItemsControl.ItemsSource property, you need to set it to a value of type IVector of IInspectable (or of an interoperability type such as IBindableObservableVector).

Ecco un esempio di codice che produce una raccolta di un tipo appropriato per il binding e accoda un elemento a essa.Here's a code example that produces a collection of a type suitable for binding, and appends an element to it. Puoi trovare il contesto per questo esempio di codice in Controlli di elementi XAML, binding a una raccolta C++/WinRT.You can find the context for this code example in XAML items controls; bind to a C++/WinRT collection.

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

Puoi creare una raccolta di Windows Runtime dai dati e ottenere una visualizzazione di essa pronta per il passaggio a un'API, il tutto senza copiare nulla.You can create a Windows Runtime collection from data, and get a view on it ready to pass to an API, all without copying anything.

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

La raccolta creata negli esempi riportati sopra può essere associata a un controllo di elementi XAML, ma non è osservabile.In the examples above, the collection we create can be bound to a XAML items control; but the collection isn't observable.

Raccolta osservabileObservable collection

Per recuperare un nuovo oggetto di un tipo che implementa una raccolta osservabile, chiama il modello di funzione winrt::single_threaded_observable_vector con qualsiasi tipo di elemento.To retrieve a new object of a type that implements an observable collection, call the winrt::single_threaded_observable_vector function template with any element type. Per rendere una raccolta osservabile adatta per il binding a un controllo di elementi XAML, usa IInspectable come tipo di elemento.But to make an observable collection suitable for binding to a XAML items control, use IInspectable as the element type.

L'oggetto viene restituito come un'IObservableVector e si tratta dell'interfaccia tramite cui (o del controllo a cui è associata) vengono chiamate funzioni e proprietà dell'oggetto restituito.The object is returned as an IObservableVector, and that's the interface via which you (or the control to which it's bound) call the returned object's functions and properties.

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

Per altre informazioni dettagliate ed esempi di codice sul binding dei controlli dell'interfaccia utente a una raccolta osservabile, vedi Controlli di elementi XAML, binding a una raccolta C++/WinRT.For more details, and code examples, about binding your user interface (UI) controls to an observable collection, see XAML items controls; bind to a C++/WinRT collection.

Raccolta associativa (mappa)Associative collection (map)

Per le due funzioni che abbiamo esaminato sono disponibili versioni per raccolte associative.There are associative collection versions of the two functions that we've looked at.

È facoltativamente possibile preparare queste raccolte con i dati passando alla funzione una rvalue di tipo std::map o std::unordered_map.You can optionally prime these collections with data by passing to the function an rvalue of type std::map or 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)) };

A thread singoloSingle-threaded

L'espressione "a thread singolo" nei nomi di queste funzioni indica che esse non forniscono concorrenza, in altre parole non sono thread-safe.The "single-threaded" in the names of these functions indicates that they don't provide any concurrency—in other words, they're not thread-safe. La menzione dei thread non è correlata agli apartment perché gli oggetti restituiti da queste funzioni sono tutti Agile (vedi Oggetti Agile in C++/WinRT).The mention of threads is unrelated to apartments, because the objects returned from these functions are all agile (see Agile objects in C++/WinRT). Indica solo che gli oggetti sono a thread singolo.It's just that the objects are single-threaded. E questo è del tutto appropriato se si vuole semplicemente passare dati in una sola direzione o nell'altra attraverso l'interfaccia applicativa binaria (ABI).And that's entirely appropriate if you just want to pass data one way or the other across the application binary interface (ABI).

Classi di base per le raccolteBase classes for collections

Se, per una flessibilità completa, si desidera implementare una raccolta personalizzata, è opportuno evitare di farlo nel modo difficile.If, for complete flexibility, you want to implement your own custom collection, then you'll want to avoid doing that the hard way. Ad esempio, ecco come si presenterebbe una visualizzazione vettoriale personalizzata senza l'assistenza delle classi di base di C++/WinRT.For example, this is what a custom vector view would look like without the assistance of C++/WinRT's base classes.

...
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 alternativa è molto più semplice derivare la visualizzazione vettoriale personalizzata dal modello di struct winrt::vector_view_base e implementare semplicemente la funzione get_container per esporre il contenitore che include i dati.Instead, it's much easier to derive your custom vector view from the winrt::vector_view_base struct template, and just implement the get_container function to expose the container holding your data.

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

Il contenitore restituito da get_container deve fornire l'interfaccia begin e end che winrt::vector_view_base si aspetta.The container returned by get_container must provide the begin and end interface that winrt::vector_view_base expects. Come illustrato nell'esempio precedente, std:: Vector offre questo.As shown in the example above, std::vector provides that. Ma puoi restituire qualsiasi contenitore che rispetti lo stesso contratto, tra cui un contenitore personalizzato.But you can return any container that fulfils the same contract, including your own custom 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 };
};

Queste sono le classi di base fornite da C++/WinRT per agevolare l'implementazione delle raccolte personalizzate.These are the base classes that C++/WinRT provides to help you implement custom collections.

winrt::vector_view_basewinrt::vector_view_base

Vedi gli esempi di codice riportati sopra.See the code examples above.

winrt::vector_basewinrt::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_basewinrt::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_basewinrt::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_basewinrt::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_basewinrt::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 }
    };
};

API importantiImportant APIs