Procedura dettagliata: creazione di un componente Windows Runtime di base in C++ e chiamata da JavaScript o C#
In questa procedura dettagliata viene illustrato come creare la DLL di un componente di Windows Runtime di base che è possibile chiamare da JavaScript, C# o Visual Basic. Prima di iniziare questa procedura dettagliata, assicurati di avere compreso concetti quali interfaccia binaria astratta (ABI), classi di riferimento e estensioni dei componenti di Visual C++ che semplificano l'uso delle classi di riferimento. Per ulteriori informazioni, vedi Creazione di componenti Windows Runtime in C++ e Riferimenti al linguaggio Visual C++ (C++/CX).
Creazione della DLL del componente C++
In questo esempio abbiamo creato prima il progetto di componente, ma se vuoi puoi creare prima il progetto JavaScript. L'ordine non ha importanza.
Nota che la classe principale del componente contiene esempi di definizioni di proprietà e metodi e una dichiarazione di evento, forniti al solo scopo illustrativo. Non sono necessari e in questo esempio sostituiremo tutto il codice generato con il nostro codice.
Per creare un progetto di componente C++
Dalla barra dei menu di Visual Studio scegli File, Nuovo, Progetto.
Nel riquadro sinistro della finestra di dialogo Nuovo progetto espandi Visual C++, quindi seleziona il nodo per le applicazioni Windows Store.
Nel riquadro centrale seleziona Componente Windows Runtime, quindi assegna al progetto il nome WinRT_CPP.
Scegli OK.
Per aggiungere una classe attivabile al componente
- Una classe attivabile è una classe che il codice client può creare utilizzando un'espressione new (New in Visual Basic o ref new in C++). Nel componente dichiara la classe come public ref class sealed. Di fatto, i file Class1.h e cpp dispongono già di una classe di riferimento. Puoi modificare il nome, ma in questo esempio utilizzeremo il nome predefinito, Class1. Se necessario, puoi definire ulteriori classi di riferimento o regolari nel componente. Per ulteriori informazioni sulle classi ref, vedi Sistema di tipi (C++/CX).
Per aggiungere le direttive obbligatorie #include
Aggiungi queste direttive #include a Class1.h:
#include <collection.h> #include <amp.h> #include <amp_math.h>
collection.h è il file di intestazione per le classi concrete C++ come Classe Platform::Collections::Vector e Classe Platform::Collections::Map, che implementano le interfacce indipendenti dalla lingua definite da Windows Runtime. Le intestazioni amp vengono utilizzate per eseguire calcoli sul GPU. Giustamente non dispongono di equivalenti in Windows Runtime perché sono private. In genere, per motivi di prestazioni è consigliabile utilizzare le librerie standard e di codice C++ ISO all'interno del componente. È solo l'interfaccia di Windows Runtime che deve essere espressa nei tipi di Windows Runtime.
Per aggiungere un delegato all'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 di gestore eventi che sottoscrive l'evento deve avere la firma specificata nel delegato. Il codice seguente definisce un tipo delegato che accetta int e restituisce void. Successivamente il codice dichiara un oggetto event pubblico di questo tipo. Ciò consente al codice client di fornire i metodi richiamati quando viene generato l'evento.
Aggiungi la seguente dichiarazione di delegato all'ambito dello spazio dei nomi nel file Class1.h, appena prima della dichiarazione Class1.
public delegate void PrimeFoundHandler(int result);
Suggerimento
Se il codice non è correttamente allineato quando lo incolli in Visual Studio, premi semplicemente CTRL+K+D per correggere il rientro dell'intero file.
Per aggiungere i membri pubblici
La classe espone tre metodi pubblici e un evento pubblico. Il primo metodo è sincrono perché la sua esecuzione è sempre molto veloce. Gli altri due metodi, che richiedono più tempo, sono asincroni in modo da non bloccare il thread UI. Questi metodi restituiscono IAsyncOperationWithProgress e IAsyncActionWithProgress. Il primo definisce un metodo asincrono che restituisce un risultato, mentre il secondo definisce un metodo asincrono che restituisce void. Queste interfacce consentono inoltre 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 di supporto per i calcoli numerici e un oggetto CoreDispatcher che viene utilizzato per effettuare il marshalling delle chiamate dell'evento dai thread di lavoro al thread UI.
private: bool is_prime(int n); Windows::UI::Core::CoreDispatcher^ m_dispatcher;
Per aggiungere le direttive dello spazio dei nomi e dell'intestazione
Nel file Class1.cpp aggiungi le seguenti direttive #include:
#include <ppltasks.h> #include <concurrent_vector.h>
Aggiungi queste istruzioni using per inserire gli spazi dei nomi obbligatori:
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 aggiungi l'implementazione del seguente metodo. Questo metodo viene eseguito in modo sincrono sul thread chiamante, ma è molto veloce perché utilizza C++ AMP per parallelizzare il calcolo sul GPU. Per ulteriori informazioni, vedi Cenni preliminari su C++ AMP. I risultati vengono aggiunti in coda a un tipo concreto Platform::Collections::Vector<T>, che viene implicitamente convertito in un tipo 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 https://msdn.microsoft.com/en-us/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 di supporto
In Class1.cpp, aggiungi le implementazioni per GetPrimesOrdered e il metodo di supporto is_prime. GetPrimesOrdered utilizza Classe concurrent_vector e un ciclo Funzione parallel_for per dividere il lavoro e utilizzare le risorse ottimali del computer in cui è eseguito il programma che genera i risultati. Una volta calcolati, memorizzati e ordinati, i risultati vengono aggiunti a Platform::Collections::Vector<T> e restituiti al codice client come Windows::Foundation::Collections::IVector<T>.
Fai attenzione al codice del reporter dello stato di avanzamento, che consente al client di collegare una barra di stato o altra interfaccia utente per indicare all'utente la durata effettiva dell'operazione. La segnalazione dello stato di avanzamento ha un costo. Un evento deve essere generato sul lato componente e gestito sul thread UI e il valore dello stato di avanzamento deve essere memorizzato in ogni iterazione. Un modo per ridurre al minimo questo costo consiste nel limitare la frequenza con cui viene generato un evento di stato. Se il costo è ancora troppo elevato o se non riesci a stimare la durata dell'operazione, prova a utilizzare un livello di stato. Questo elemento indica che un'operazione è in corso ma non mostra il tempo rimanente 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 i singoli risultati man mano che vengono trovati, senza attendere che siano stati trovati tutti. Ogni risultato viene restituito nel gestore eventi e visualizzato sull'interfaccia utente in tempo reale. Nota che anche qui viene utilizzato un reporter dello stato di avanzamento. Questo metodo utilizza anche il metodo di supporto 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); }); }
Premi CTRL+MAIUSC+B per compilare il componente.
Creazione di un'app client JavaScript
Per creare un progetto di JavaScript
-
Nota
Se desideri solo creare un client C#, puoi ignorare questa sezione.
In Esplora soluzioni apri il menu di scelta rapida per il nodo Soluzione e scegli Aggiungi, Nuovo progetto.
Espandi JavaScript (può essere annidato sotto Altri linguaggi) e scegli Applicazione vuota.
Accetta il nome predefinito, App1 scegliendo OK.
Apri il menu di scelta rapida per il nodo del progetto App1 e scegli Imposta come progetto di avvio.
Aggiungi un riferimento del progetto a WinRT_CPP:
Apri il menu di scelta rapida per il nodo Riferimenti e scegli Aggiungi riferimento.
Nel riquadro sinistro della finestra di dialogo Gestione riferimenti seleziona Soluzione, quindi Progetti.
Nel riquadro centrale seleziona WinRT_CPP, quindi scegli OK.
Per aggiungere il codice HTML che richiama i gestori eventi JavaScript
Incolla questo codice HTML nel nodo <body> della pagina default.html:
<div id="LogButtonDiv"> <button id="logButton" onclick="LogButton_Click()">Logarithms using AMP</button> </div> <div id="LogResultDiv"> <p id="logResult"></p> </div> <div id="OrderedPrimeButtonDiv"> <button id="orderedPrimeButton" onclick="ButtonOrdered_Click()">Primes using parallel_for with sort</button> </div> <div id="OrderedPrimeProgress"> <progress id="OrderedPrimesProgressBar" style="-ms-grid-column-span:2" value="0" max="100"></progress> </div> <div id="OrderedPrimeResultDiv"> <p id="orderedPrimes"> Primes found (ordered): </p> </div> <div id="UnorderedPrimeButtonDiv"> <button id="ButtonUnordered" onclick="ButtonUnordered_Click()">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" onclick="ButtonClear_Click()">Clear</button> </div>
<div id="LogButtonDiv"> <button id="logButton" onclick="LogButton_Click()">Logarithms using AMP</button> </div> <div id="LogResultDiv"> <p id="logResult"></p> </div> <div id="OrderedPrimeButtonDiv"> <button id="orderedPrimeButton" onclick="ButtonOrdered_Click()">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" onclick="ButtonUnordered_Click()">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" onclick="ButtonClear_Click()">Clear</button> </div>
Per aggiungere stili
In default.css rimuovi lo stile body e aggiungi gli stili seguenti:
#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 che chiamano la DLL del componente
Aggiungi le seguenti funzioni alla fine del file default.js. Queste funzioni vengono chiamate quando vengono scelti i pulsanti nella pagina principale. Nota come JavaScript attiva la classe C++ e chiama i relativi metodi e come utilizza 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; }
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; }
Premi F5 per eseguire l'app.
Creazione di un'app client C#
La DLL del componente Windows Runtime C++ può essere chiamata altrettanto facilmente da un client C# quanto da un client JavaScript. Nei passaggi seguenti viene illustrato come creare un client C# equivalente al client JavaScript della sezione precedente.
Per creare un progetto C#
In Esplora soluzioni apri il menu di scelta rapida per il nodo Soluzione e quindi scegli Aggiungi, Nuovo progetto.
Espandi Visual C# (può essere annidato sotto Altri linguaggi), seleziona Windows Store nel riquadro sinistro e, nel riquadro centrale, seleziona Applicazione vuota.
Assegna a questa app il nome CS_Client e scegli OK.
Apri il menu di scelta rapida per il nodo del progetto CS_Client e scegli Imposta come progetto di avvio.
Aggiungi un riferimento del progetto a WinRT_CPP:
Apri il menu di scelta rapida per il nodo Riferimenti e scegli Aggiungi riferimento.
Nel riquadro sinistro della finestra di dialogo Gestione riferimenti seleziona Soluzione, quindi Progetti.
Nel riquadro centrale seleziona WinRT_CPP, quindi scegli OK.
Per aggiungere il codice XAML che definisce l'interfaccia utente
Aggiungi il seguente elemento ScrollViewer e il relativo contenuto alla griglia nel file 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 apri il file mainpage.xaml.cs (può essere annidato nel file mainpage.xaml). Aggiungi una direttiva using per System.Text, quindi aggiungi il gestore eventi per il calcolo logaritmico nella classe MainPage subito dopo OnNavigateTo.
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(); }
Aggiungi 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(); }
Aggiungi il gestore eventi per il risultato non ordinato e per il pulsante che consente di cancellare i risultati in modo da poter eseguire nuovamente 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
Seleziona il progetto C# o il progetto JavaScript come progetto di avvio aprendo il menu di scelta rapida del nodo di progetto in Esplora soluzioni e scegliendo Imposta come progetto di avvio. Premi F5 per eseguire contestualmente anche il debug oppure CRTL+F5 per eseguire senza il debug.
Controllo del componente nel Visualizzatore oggetti (facoltativo)
Nel Visualizzatore oggetti puoi controllare tutti i tipi di Windows Runtime definiti nei file .winmd; sono inclusi i tipi nello spazio dei nomi Platform e nello spazio dei nomi predefinito. I tipi nello spazio dei nomi Platform::Collections sono invece definiti nel file di intestazione collections.h, anziché nel file .winmd. Perciò non appaiono nel Visualizzatore oggetti.
Per controllare il componente
Sulla barra dei menu scegli Visualizza, Altre finestre, Visualizzatore oggetti.
Nel riquadro sinistro del Visualizzatore oggetti espandi il nodo WinRT_CPP per visualizzare i tipi e i metodi definiti nel componente.
Suggerimenti relativi al debug
Per un debug ottimale, scarica i simboli di debug dai server di simboli Microsoft pubblici.
Sulla barra dei menu, scegliere Strumenti, Opzioni.
Nella finestra di dialogo Opzioni espandi il nodo Debug e seleziona Simboli.
Seleziona Server dei simboli Microsoft e scegli OK.
Il primo download dei simboli potrebbe richiedere del tempo. Per ottenere prestazioni più veloci quando premerai F5 la volta successiva, specifica una directory locale da utilizzare come cache per i simboli.
Quando esegui il debug di una soluzione JavaScript che dispone di una DLL del componente, puoi impostare il debugger per abilitare l'esecuzione passo passo dello script o l'esecuzione passo passo del codice nativo nel componente, ma non entrambe contemporaneamente. Per modificare l'impostazione, in Esplora soluzioni apri il menu di scelta rapida per il nodo di progetto JavaScript e scegli Proprietà, Debug, Tipo di debugger.
Assicurati di selezionare le funzionalità appropriate nella finestra di progettazione del pacchetto. Se ad esempio tenti di accedere ai file a livello di codice nella cartella Immagini, accertati di selezionare la casella di controllo Raccolta immagini nel riquadro Funzionalità della finestra di progettazione del pacchetto.
Se il codice JavaScript non riconosce le proprietà o i metodi pubblici nel componente, verifica di utilizzare la convenzione Camel in JavaScript. Ad esempio, è necessario fare riferimento al metodo ComputeResult C++ come computeResult in JavaScript.
Se rimuovi il progetto di Componente C++ di Windows Runtime da una soluzione, devi anche rimuovere manualmente il riferimento al progetto dal progetto JavaScript. In caso contrario non potrai eseguire le operazioni di debug o compilazione successive. Se necessario, puoi aggiungere un riferimento all'assembly alla DLL.
Vedere anche
Riferimenti
Roadmap for Windows Store apps using C++