Condividi tramite


Procedura dettagliata per la creazione di un componente Windows Runtime C++/CX e chiamata del componente da JavaScript o C#

Nota

Questo argomento è utile per gestire l'applicazione C++/CX. Ma consigliamo di usare C++/WinRT per le nuove applicazioni. C++/WinRT è una proiezione del linguaggio C++ 17 interamente standard e moderna per le API di Windows Runtime (WinRT), implementata come libreria basata su file di intestazione e progettata per fornirti accesso privilegiato alla moderna API di Windows. Per informazioni su come creare un componente Windows Runtime con C++/WinRT, vedere Componenti Windows Runtime con C++/WinRT.

Questa procedura dettagliata descrive come creare una DLL di un componente Windows Runtime di base che può essere chiamata da JavaScript, C# o Visual Basic. Prima di iniziare questa procedura dettagliata, assicurarsi di aver compreso concetti come ABI (Abstract Binary Interface), classi di riferimento e le estensioni dei componenti Visual C++, che semplificano l'uso delle classi di riferimento. Per altre informazioni, vedere componenti Windows Runtime con C++/CX e Informazioni di riferimento su Visual C++ (C++/CX).

Creazione del componente C++ DLL

In questo esempio si crea prima di tutto il progetto componente, ma è prima possibile creare il progetto JavaScript. L'ordine non importa.

Si noti che la classe principale del componente contiene esempi di definizioni di proprietà e metodi e una dichiarazione di evento. Questi vengono forniti solo per mostrare come viene fatto. Non sono necessari e in questo esempio si sostituirà tutto il codice generato con il codice personalizzato.

Per creare il progetto componente C++

  1. Nella barra dei menu di Visual Studio selezionare File, Nuovo, Progetto.

  2. Nel riquadro sinistro della finestra di dialogo Nuovo progetto espandere Visual C++ e quindi selezionare il nodo per le app di Universal Windows.

  3. Nel riquadro centrale selezionare Componente Windows Runtime e quindi assegnare al progetto il nome WinRT_CPP.

  4. Scegli il pulsante OK.

Per aggiungere una classe attivabile al componente

Una classe attivabile è una classe che il codice client può creare usando una nuova espressione (Nuovo in Visual Basic o nuovo rif in C++). Nel componente viene dichiarato come classe di riferimento pubblica sealed. Infatti, i file Class1.h e .cpp hanno già una classe ref. È possibile modificare il nome, ma in questo esempio si userà il nome predefinito Class1. Se necessario, è possibile definire classi di riferimento aggiuntive o classi regolari nel componente. Per ulteriori informazioni sulle classi di riferimento, vedere Sistema di tipi (C++/CX).

Aggiungere queste direttive #include a Class1.h:

#include <collection.h>
#include <ppl.h>
#include <amp.h>
#include <amp_math.h>

collection.h è il file di intestazione per le classi concrete C++, ad esempio la classe Platform::Collections::Vector e la classe Platform::Collections::Map, che implementano interfacce indipendenti dal linguaggio definite da Windows Runtime. Le intestazioni amp vengono usate per eseguire calcoli nella GPU. Non hanno equivalenti di Windows Runtime e va bene perché sono privati. In generale, per motivi di prestazioni è consigliabile usare il codice ISO C++ e le librerie standard internamente all'interno del componente; è solo l'interfaccia di Windows Runtime che deve essere espressa nei tipi di Windows Runtime.

Per aggiungere un delegato nell'ambito dello spazio dei nomi

Un delegato è un costrutto che definisce i parametri e il tipo restituito per i metodi. Un evento è un'istanza di un tipo delegato specifico e qualsiasi metodo del gestore eventi che sottoscrive l'evento deve avere la firma specificata nel delegato. Il codice seguente definisce un tipo delegato che accetta un valore int e restituisce void. Successivamente, il codice dichiara un evento pubblico di questo tipo; ciò consente al codice client di fornire metodi richiamati quando viene generato l'evento.

Aggiungere la dichiarazione di delegato seguente nell'ambito dello spazio dei nomi in Class1.h, subito prima della dichiarazione Class1.

public delegate void PrimeFoundHandler(int result);

Se il codice non viene allineato correttamente quando lo si incolla in Visual Studio, premere CTRL+K+D per correggere il rientro per l'intero file.

Aggiungere i membri pubblici

La classe espone tre metodi pubblici e un evento pubblico. Il primo metodo è sincrono perché viene sempre eseguito molto velocemente. Poiché gli altri due metodi potrebbero richiedere del tempo, sono asincroni in modo che non blocchino il thread dell'interfaccia utente. Questi metodi restituiscono IAsyncOperationWithProgress e IAsyncActionWithProgress. Il primo definisce un metodo asincrono che restituisce un risultato e quest'ultimo definisce un metodo asincrono che restituisce void. Queste interfacce consentono anche al codice client di ricevere aggiornamenti sullo stato di avanzamento dell'operazione.

public:

        // Synchronous method.
        Windows::Foundation::Collections::IVector<double>^  ComputeResult(double input);

        // Asynchronous methods
        Windows::Foundation::IAsyncOperationWithProgress<Windows::Foundation::Collections::IVector<int>^, double>^
            GetPrimesOrdered(int first, int last);
        Windows::Foundation::IAsyncActionWithProgress<double>^ GetPrimesUnordered(int first, int last);

        // Event whose type is a delegate "class"
        event PrimeFoundHandler^ primeFoundEvent;

Per aggiungere i membri privati

La classe contiene tre membri privati: due metodi helper per i calcoli numerici e un oggetto CoreDispatcher usato per effettuare il marshalling delle chiamate di evento dai thread di lavoro al thread dell'interfaccia utente.

private:
        bool is_prime(int n);
        Windows::UI::Core::CoreDispatcher^ m_dispatcher;

Per aggiungere le direttive intestazione e spazio dei nomi

  1. In Class1.cpp aggiungere queste direttive #include:
#include <ppltasks.h>
#include <concurrent_vector.h>
  1. Aggiungere ora queste istruzioni using per eseguire il pull negli spazi dei nomi necessari:
using namespace concurrency;
using namespace Platform::Collections;
using namespace Windows::Foundation::Collections;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;

Per aggiungere l'implementazione per ComputeResult

In Class1.cpp aggiungere l'implementazione del metodo seguente. Questo metodo viene eseguito in modo sincrono sul thread chiamante, ma è molto veloce perché usa C++ AMP per parallelizzare il calcolo nella GPU. Per maggiori informazioni, vedere Panoramica C++ AMP. I risultati vengono aggiunti a un tipo concreto Platform::Collections::Vector<T>, che viene convertito in modo implicito in un oggetto Windows::Foundation::Collections::IVector<T> quando viene restituito.

//Public API
IVector<double>^ Class1::ComputeResult(double input)
{
    // Implement your function in ISO C++ or
    // call into your C++ lib or DLL here. This example uses AMP.
    float numbers[] = { 1.0, 10.0, 60.0, 100.0, 600.0, 10000.0 };
    array_view<float, 1> logs(6, numbers);

    // See http://msdn.microsoft.com/library/hh305254.aspx
    parallel_for_each(
        logs.extent,
        [=] (index<1> idx) restrict(amp)
    {
        logs[idx] = concurrency::fast_math::log10(logs[idx]);
    }
    );

    // Return a Windows Runtime-compatible type across the ABI
    auto res = ref new Vector<double>();
    int len = safe_cast<int>(logs.extent.size());
    for(int i = 0; i < len; i++)
    {      
        res->Append(logs[i]);
    }

    // res is implicitly cast to IVector<double>
    return res;
}

Per aggiungere l'implementazione per GetPrimesOrdered e il relativo metodo helper

In Class1.cpp aggiungere le implementazioni per GetPrimesOrdered e il metodo helper is_prime. GetPrimesOrdered usa una classe concurrent_vector e un ciclo di funzioni parallel_for per dividere il lavoro e usare le risorse massime del computer in cui è in esecuzione il programma per produrre risultati. Dopo che i risultati vengono calcolati, archiviati e ordinati, vengono aggiunti a un oggetto Platform::Collections::Vector<T> e restituiti come Windows::Foundation::Collections::IVector<T> al codice client.

Si noti il codice per il reporter di stato, che consente al client di associare un indicatore di stato o un'altra interfaccia utente per mostrare all'utente quanto tempo richiederà l'operazione. La creazione di report sullo stato ha un costo. Un evento deve essere generato sul lato componente e gestito nel thread dell'interfaccia utente e il valore di stato deve essere archiviato in ogni iterazione. Un modo per ridurre al minimo il costo consiste nel limitare la frequenza con cui viene generato un evento di stato. Se il costo è ancora proibitivo o se non è possibile stimare la lunghezza dell'operazione, prendere in considerazione l'uso di un anello di stato, che indica che un'operazione è in corso ma non mostra il tempo rimanente fino al completamento.

// Determines whether the input value is prime.
bool Class1::is_prime(int n)
{
    if (n < 2)
        return false;
    for (int i = 2; i < n; ++i)
    {
        if ((n % i) == 0)
            return false;
    }
    return true;
}

// This method computes all primes, orders them, then returns the ordered results.
IAsyncOperationWithProgress<IVector<int>^, double>^ Class1::GetPrimesOrdered(int first, int last)
{
    return create_async([this, first, last]
    (progress_reporter<double> reporter) -> IVector<int>^ {
        // Ensure that the input values are in range.
        if (first < 0 || last < 0) {
            throw ref new InvalidArgumentException();
        }
        // Perform the computation in parallel.
        concurrent_vector<int> primes;
        long operation = 0;
        long range = last - first + 1;
        double lastPercent = 0.0;

        parallel_for(first, last + 1, [this, &primes, &operation,
            range, &lastPercent, reporter](int n) {

                // Increment and store the number of times the parallel
                // loop has been called on all threads combined. There
                // is a performance cost to maintaining a count, and
                // passing the delegate back to the UI thread, but it's
                // necessary if we want to display a determinate progress
                // bar that goes from 0 to 100%. We can avoid the cost by
                // setting the ProgressBar IsDeterminate property to false
                // or by using a ProgressRing.
                if(InterlockedIncrement(&operation) % 100 == 0)
                {
                    reporter.report(100.0 * operation / range);
                }

                // If the value is prime, add it to the local vector.
                if (is_prime(n)) {
                    primes.push_back(n);
                }
        });

        // Sort the results.
        std::sort(begin(primes), end(primes), std::less<int>());		
        reporter.report(100.0);

        // Copy the results to a Vector object, which is
        // implicitly converted to the IVector return type. IVector
        // makes collections of data available to other
        // Windows Runtime components.
        return ref new Vector<int>(primes.begin(), primes.end());
    });
}

Per aggiungere l'implementazione per GetPrimesUnordered

L'ultimo passaggio per creare il componente C++ consiste nell'aggiungere l'implementazione per GetPrimesUnordered in Class1.cpp. Questo metodo restituisce ogni risultato non appena viene trovato, senza attendere che vengano trovati tutti i risultati. Ogni risultato viene restituito nel gestore eventi e visualizzato nell'interfaccia utente in tempo reale. Anche in questo caso, si noti che viene usato un reporter di stato. Questo metodo usa anche il metodo helper is_prime.

// This method returns no value. Instead, it fires an event each time a
// prime is found, and passes the prime through the event.
// It also passes progress info.
IAsyncActionWithProgress<double>^ Class1::GetPrimesUnordered(int first, int last)
{

    auto window = Windows::UI::Core::CoreWindow::GetForCurrentThread();
    m_dispatcher = window->Dispatcher;


    return create_async([this, first, last](progress_reporter<double> reporter) {

        // Ensure that the input values are in range.
        if (first < 0 || last < 0) {
            throw ref new InvalidArgumentException();
        }

        // In this particular example, we don't actually use this to store
        // results since we pass results one at a time directly back to
        // UI as they are found. However, we have to provide this variable
        // as a parameter to parallel_for.
        concurrent_vector<int> primes;
        long operation = 0;
        long range = last - first + 1;
        double lastPercent = 0.0;

        // Perform the computation in parallel.
        parallel_for(first, last + 1,
            [this, &primes, &operation, range, &lastPercent, reporter](int n)
        {
            // Store the number of times the parallel loop has been called  
            // on all threads combined. See comment in previous method.
            if(InterlockedIncrement(&operation) % 100 == 0)
            {
                reporter.report(100.0 * operation / range);
            }

            // If the value is prime, pass it immediately to the UI thread.
            if (is_prime(n))
            {                
                // Since this code is probably running on a worker
                // thread, and we are passing the data back to the
                // UI thread, we have to use a CoreDispatcher object.
                m_dispatcher->RunAsync( CoreDispatcherPriority::Normal,
                    ref new DispatchedHandler([this, n, operation, range]()
                {
                    this->primeFoundEvent(n);

                }, Platform::CallbackContext::Any));

            }
        });
        reporter.report(100.0);
    });
}

Creazione di un'app client JavaScript (Visual Studio 2017)

Se si vuole creare un client C#, è possibile ignorare questa sezione.

Nota

In Visual Studio 2019 i progetti Universal Windows Platform (UWP) usando JavaScript non sono supportati. Vedere JavaScript and TypeScript in Visual Studio 2019. Per seguire questa sezione, è consigliabile usare Visual Studio 2017. Vedere JavaScript in Visual Studio 2017.

Per creare un progetto JavaScript

  1. In Esplora soluzioni (in Visual Studio 2017; vedere Nota precedente), aprire il menu di scelta rapida per il nodo Soluzione e selezionare Aggiungi, Nuovo progetto.

  2. Espandere JavaScript (potrebbe essere annidato in Altri linguaggi) e selezionare App vuota (Windows universale).

  3. Accettare il nome predefinito App1 selezionando il pulsante OK.

  4. Aprire il menu di scelta rapida per il nodo del progetto App1 e selezionare Imposta come progetto di avvio.

  5. Aggiungere un riferimento al progetto a WinRT_CPP:

  6. Aprire il menu di scelta rapida per il nodo Riferimenti e scegliere Aggiungi riferimento.

  7. Nel riquadro sinistro della finestra di dialogo Gestione riferimenti selezionare Progetti , quindi selezionare Soluzione.

  8. Nel riquadro centrale selezionare WinRT_CPP e quindi selezionare il pulsante OK

Per aggiungere il codice HTML che richiama i gestori eventi JavaScript

Incollare il codice HTML nel nodo del <corpo> della pagina default.html:

<div id="LogButtonDiv">
     <button id="logButton">Logarithms using AMP</button>
 </div>
 <div id="LogResultDiv">
     <p id="logResult"></p>
 </div>
 <div id="OrderedPrimeButtonDiv">
     <button id="orderedPrimeButton">Primes using parallel_for with sort</button>
 </div>
 <div id="OrderedPrimeProgress">
     <progress id="OrderedPrimesProgressBar" value="0" max="100"></progress>
 </div>
 <div id="OrderedPrimeResultDiv">
     <p id="orderedPrimes">
         Primes found (ordered):
     </p>
 </div>
 <div id="UnorderedPrimeButtonDiv">
     <button id="ButtonUnordered">Primes returned as they are produced.</button>
 </div>
 <div id="UnorderedPrimeDiv">
     <progress id="UnorderedPrimesProgressBar" value="0" max="100"></progress>
 </div>
 <div id="UnorderedPrime">
     <p id="unorderedPrimes">
         Primes found (unordered):
     </p>
 </div>
 <div id="ClearDiv">
     <button id="Button_Clear">Clear</button>
 </div>

Per aggiungere stili

In default.css rimuovere lo stile del corpo e quindi aggiungere questi stili:

#LogButtonDiv {
border: orange solid 1px;
-ms-grid-row: 1; /* default is 1 */
-ms-grid-column: 1; /* default is 1 */
}
#LogResultDiv {
background: black;
border: red solid 1px;
-ms-grid-row: 1;
-ms-grid-column: 2;
}
#UnorderedPrimeButtonDiv, #OrderedPrimeButtonDiv {
border: orange solid 1px;
-ms-grid-row: 2;   
-ms-grid-column:1;
}
#UnorderedPrimeProgress, #OrderedPrimeProgress {
border: red solid 1px;
-ms-grid-column-span: 2;
height: 40px;
}
#UnorderedPrimeResult, #OrderedPrimeResult {
border: red solid 1px;
font-size:smaller;
-ms-grid-row: 2;
-ms-grid-column: 3;
-ms-overflow-style:scrollbar;
}

Per aggiungere i gestori eventi JavaScript richiamati nella DLL del componente

Aggiungere le funzioni seguenti alla fine del file default.js. Queste funzioni vengono chiamate quando vengono scelti i pulsanti nella pagina principale. Si noti che JavaScript attiva la classe C++ e quindi chiama i relativi metodi e usa i valori restituiti per popolare le etichette HTML.

var nativeObject = new WinRT_CPP.Class1();

function LogButton_Click() {

    var val = nativeObject.computeResult(0);
    var result = "";

    for (i = 0; i < val.length; i++) {
        result += val[i] + "<br/>";
    }

    document.getElementById('logResult').innerHTML = result;
}

function ButtonOrdered_Click() {
    document.getElementById('orderedPrimes').innerHTML = "Primes found (ordered): ";

    nativeObject.getPrimesOrdered(2, 10000).then(
        function (v) {
            for (var i = 0; i < v.length; i++)
                document.getElementById('orderedPrimes').innerHTML += v[i] + " ";
        },
        function (error) {
            document.getElementById('orderedPrimes').innerHTML += " " + error.description;
        },
        function (p) {
            var progressBar = document.getElementById("OrderedPrimesProgressBar");
            progressBar.value = p;
        });
}

function ButtonUnordered_Click() {
    document.getElementById('unorderedPrimes').innerHTML = "Primes found (unordered): ";
    nativeObject.onprimefoundevent = handler_unordered;

    nativeObject.getPrimesUnordered(2, 10000).then(
        function () { },
        function (error) {
            document.getElementById("unorderedPrimes").innerHTML += " " + error.description;
        },
        function (p) {
            var progressBar = document.getElementById("UnorderedPrimesProgressBar");
            progressBar.value = p;
        });
}

var handler_unordered = function (n) {
    document.getElementById('unorderedPrimes').innerHTML += n.target.toString() + " ";
};

function ButtonClear_Click() {

    document.getElementById('logResult').innerHTML = "";
    document.getElementById("unorderedPrimes").innerHTML = "";
    document.getElementById('orderedPrimes').innerHTML = "";
    document.getElementById("UnorderedPrimesProgressBar").value = 0;
    document.getElementById("OrderedPrimesProgressBar").value = 0;
}

Aggiungere il codice per aggiungere i listener di eventi sostituendo la chiamata esistente a WinJS.UI.processAll in app.onactivated in default.js con il codice seguente che implementa la registrazione degli eventi in un blocco successivo. Per una spiegazione dettagliata di questo argomento, vedere Creare un'app "Hello, World" (JS).

args.setPromise(WinJS.UI.processAll().then( function completed() {
    var logButton = document.getElementById("logButton");
    logButton.addEventListener("click", LogButton_Click, false);
    var orderedPrimeButton = document.getElementById("orderedPrimeButton");
    orderedPrimeButton.addEventListener("click", ButtonOrdered_Click, false);
    var buttonUnordered = document.getElementById("ButtonUnordered");
    buttonUnordered.addEventListener("click", ButtonUnordered_Click, false);
    var buttonClear = document.getElementById("Button_Clear");
    buttonClear.addEventListener("click", ButtonClear_Click, false);
}));

Premere F5 per eseguire lo script.

Creazione di un'app client C#

Per creare un progetto C#

  1. In Esplora soluzioni aprire il menu di scelta rapida per il nodo Soluzione e quindi selezionare Aggiungi, Nuovo progetto.

  2. Espandere Visual C# (potrebbe essere annidato in Altri linguaggi), selezionare Windows e quindi Universal nel riquadro sinistro e quindi selezionare App vuota nel riquadro centrale.

  3. Assegnare all'app il nome CS_Client e quindi scegliere il pulsante OK.

  4. Aprire il menu di scelta rapida per il nodo del progetto CS_Client e selezionare Imposta come progetto di avvio.

  5. Aggiungere un riferimento al progetto a WinRT_CPP:

    • Aprire il menu di scelta rapida per il nodo Riferimenti e selezionare Aggiungi riferimento.

    • Nel riquadro sinistro della finestra di dialogo Gestione riferimenti, selezionare Progetti e quindi selezionare Soluzione.

    • Nel riquadro centrale selezionare WinRT_CPP e quindi selezionare il pulsante OK.

Per aggiungere il codice XAML che definisce l'interfaccia utente

Copiare il codice seguente nell'elemento Grid in MainPage.xaml.

<ScrollViewer>
            <StackPanel Width="1400">

                <Button x:Name="Button1" Width="340" Height="50"  Margin="0,20,20,20" Content="Synchronous Logarithm Calculation" FontSize="16" Click="Button1_Click_1"/>
                <TextBlock x:Name="Result1" Height="100" FontSize="14"></TextBlock>
            <Button x:Name="PrimesOrderedButton" Content="Prime Numbers Ordered" FontSize="16" Width="340" Height="50" Margin="0,20,20,20" Click="PrimesOrderedButton_Click_1"></Button>
            <ProgressBar x:Name="PrimesOrderedProgress" IsIndeterminate="false" Height="40"></ProgressBar>
                <TextBlock x:Name="PrimesOrderedResult" MinHeight="100" FontSize="10" TextWrapping="Wrap"></TextBlock>
            <Button x:Name="PrimesUnOrderedButton" Width="340" Height="50" Margin="0,20,20,20" Click="PrimesUnOrderedButton_Click_1" Content="Prime Numbers Unordered" FontSize="16"></Button>
            <ProgressBar x:Name="PrimesUnOrderedProgress" IsIndeterminate="false" Height="40" ></ProgressBar>
            <TextBlock x:Name="PrimesUnOrderedResult" MinHeight="100" FontSize="10" TextWrapping="Wrap"></TextBlock>

            <Button x:Name="Clear_Button" Content="Clear" HorizontalAlignment="Left" Margin="0,20,20,20" VerticalAlignment="Top" Width="341" Click="Clear_Button_Click" FontSize="16"/>
        </StackPanel>
</ScrollViewer>

Per aggiungere i gestori eventi per i pulsanti

In Esplora soluzioni aprire il file MainPage.xaml.cs. (Il file potrebbe essere annidato in MainPage.xaml.) Aggiungere una direttiva using per System.Text e quindi aggiungere il gestore eventi per il calcolo logaritmo nella classe MainPage.

private void Button1_Click_1(object sender, RoutedEventArgs e)
{
    // Create the object
    var nativeObject = new WinRT_CPP.Class1();

    // Call the synchronous method. val is an IList that
    // contains the results.
    var val = nativeObject.ComputeResult(0);
    StringBuilder result = new StringBuilder();
    foreach (var v in val)
    {
        result.Append(v).Append(System.Environment.NewLine);
    }
    this.Result1.Text = result.ToString();
}

Aggiungere il gestore eventi per il risultato ordinato:

async private void PrimesOrderedButton_Click_1(object sender, RoutedEventArgs e)
{
    var nativeObject = new WinRT_CPP.Class1();

    StringBuilder sb = new StringBuilder();
    sb.Append("Primes found (ordered): ");

    PrimesOrderedResult.Text = sb.ToString();

    // Call the asynchronous method
    var asyncOp = nativeObject.GetPrimesOrdered(2, 100000);

    // Before awaiting, provide a lambda or named method
    // to handle the Progress event that is fired at regular
    // intervals by the asyncOp object. This handler updates
    // the progress bar in the UI.
    asyncOp.Progress = (asyncInfo, progress) =>
        {
            PrimesOrderedProgress.Value = progress;
        };

    // Wait for the operation to complete
    var asyncResult = await asyncOp;

    // Convert the results to strings
    foreach (var result in asyncResult)
    {
        sb.Append(result).Append(" ");
    }

    // Display the results
    PrimesOrderedResult.Text = sb.ToString();
}

Aggiungere il gestore eventi per il risultato non ordinato e per il pulsante che cancella i risultati in modo da poter eseguire di nuovo il codice.

private void PrimesUnOrderedButton_Click_1(object sender, RoutedEventArgs e)
{
    var nativeObject = new WinRT_CPP.Class1();

    StringBuilder sb = new StringBuilder();
    sb.Append("Primes found (unordered): ");
    PrimesUnOrderedResult.Text = sb.ToString();

    // primeFoundEvent is a user-defined event in nativeObject
    // It passes the results back to this thread as they are produced
    // and the event handler that we define here immediately displays them.
    nativeObject.primeFoundEvent += (n) =>
    {
        sb.Append(n.ToString()).Append(" ");
        PrimesUnOrderedResult.Text = sb.ToString();
    };

    // Call the async method.
    var asyncResult = nativeObject.GetPrimesUnordered(2, 100000);

    // Provide a handler for the Progress event that the asyncResult
    // object fires at regular intervals. This handler updates the progress bar.
    asyncResult.Progress += (asyncInfo, progress) =>
        {
            PrimesUnOrderedProgress.Value = progress;
        };
}

private void Clear_Button_Click(object sender, RoutedEventArgs e)
{
    PrimesOrderedProgress.Value = 0;
    PrimesUnOrderedProgress.Value = 0;
    PrimesUnOrderedResult.Text = "";
    PrimesOrderedResult.Text = "";
    Result1.Text = "";
}

Esecuzione dell'app

Selezionare il progetto C# o JavaScript come progetto di avvio aprendo il menu di scelta rapida per il nodo del progetto in Esplora soluzioni e scegliendo Imposta come progetto di avvio. Premere F5 per eseguire con il debug o CTRL+F5 per l'esecuzione senza eseguire il debug.

Controllo del componente in Visualizzatore oggetti (facoltativo)

In Visualizzatore oggetti è possibile esaminare tutti i tipi di Windows Runtime definiti nei file con estensione winmd. Sono inclusi i tipi nello spazio dei nomi Platform e nello spazio dei nomi predefinito. Tuttavia, poiché i tipi nello spazio dei nomi Platform::Collections sono definiti nel file di intestazione collections.h, non in un file winmd, non vengono visualizzati in Visualizzatore oggetti.

Per controllare un componente

  1. Sulla barra dei menu selezionare Visualizza, Visualizzatore oggetti (Ctrl+Alt+J).

  2. Nel riquadro sinistro del Visualizzatore oggetti espandere il nodo WinRT_CPP per visualizzare i tipi e i metodi definiti nel componente.

Suggerimenti per il debug

Per un'esperienza di debug migliore, scaricare i simboli di debug dai server di simboli Microsoft pubblici:

Per scaricare i simboli di debug

  1. Nella barra dei menu selezionare Strumenti, Opzioni.

  2. Nella finestra di dialogo Opzioni espandere Debug e selezionare Simboli.

  3. Selezionare Server simboli Microsoft e selezionare il pulsante OK.

Potrebbe essere necessario del tempo per scaricare i simboli la prima volta. Per ottenere prestazioni più veloci alla successiva pressione di F5, specificare una directory locale in cui memorizzare nella cache i simboli.

Quando si esegue il debug di una soluzione JavaScript con una DLL del componente, è possibile impostare il debugger per abilitare l'esecuzione dello script o l'esecuzione di codice nativo nel componente, ma non entrambi contemporaneamente. Per modificare l'impostazione, aprire il menu di scelta rapida per il nodo del progetto JavaScript in Esplora soluzioni e selezionare Proprietà, Debug, Tipo di debugger.

Assicurarsi di selezionare le funzionalità appropriate nella finestra di progettazione pacchetti. È possibile aprire la finestra di progettazione del manifesto del pacchetto aprendo il file Package.appxmanifest. Ad esempio, se si tenta di accedere a livello di codice ai file nella cartella Immagini, assicurarsi di selezionare la casella di spunta Raccolta di immagini nel Riquadro Funzionalità della finestra di progettazione pacchetti.

Se il codice JavaScript non riconosce le proprietà o i metodi pubblici nel componente, assicurarsi che in JavaScript si usi la combinazione di maiuscole e minuscole camel. Ad esempio, è necessario fare riferimento al metodo C++ ComputeResult come computeResult in JavaScript.

Se si rimuove un progetto di componente Windows Runtime C++ da una soluzione, si deve anche rimuovere manualmente il riferimento al progetto dal progetto JavaScript. In caso contrario, impedisce le operazioni di debug o compilazioni successive. Se necessario, è quindi possibile aggiungere un riferimento di gruppo alla DLL.