Share via


Come creare un'origine dati personalizzata (HTML)

[ Questo articolo è rivolto agli sviluppatori per Windows 8.x e Windows Phone 8.x che realizzano app di Windows Runtime. Gli sviluppatori che usano Windows 10 possono vedere Documentazione aggiornata ]

La libreria Windows per JavaScript fornisce numerosi oggetti origine dati pronti all'uso che puoi utilizzare per popolare un oggetto ListView o FlipView con diversi tipi di dati. C'è l'oggetto WinJS.Binding.List, per l'accesso alle matrici e ai dati JSON, e l'oggetto StorageDataSource, per l'accesso alle informazioni sul file system.

Queste origini dati non sono le uniche a tua disposizione. Puoi creare un'origine dati personalizzata per l'accesso a qualsiasi altro tipo di dati, ad esempio un file XML o un servizio Web. Questo argomento illustra come implementare un'origine dati personalizzata per l'accesso a un servizio Web. Utilizza XHR per connettersi al servizio di ricerca immagini di Bing e visualizza i risultati in un oggetto ListView.

Dato che il servizio di Bing richiede che ogni app abbia la propria chiave AppID, prima di poter utilizzare questo codice devi ottenere una chiave. Per ulteriori informazioni su come ottenere una chiave AppID, consulta il centro per sviluppatori di Bing.

Per creare un'origine dati personalizzata, sono necessari oggetti che implementano le interfacce IListDataAdapter e IListDataSource. WinJS contiene un oggetto VirtualizedDataSource che implementa IListDataSource. È quindi sufficiente ereditare da questo oggetto e passare un oggetto IListDataAdapter al costruttore di base. Dovrai creare un oggetto che implementa l'interfaccia IListDataAdapter.

IListDataAdapter interagisce direttamente con l'origine dati per recuperare o aggiornare elementi. IListDataSource si connette a un controllo e modifica IListDataAdapter.

Prerequisiti

Istruzioni

Passaggio 1: Creare un file JavaScript per l'origine dati personalizzata

  1. Usa Microsoft Visual Studio per aggiungere un file JavaScript al tuo progetto. In Esplora soluzioni fai clic con il pulsante destro del mouse sulla cartella js del progetto e scegli Aggiungi > Nuovo elemento. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento.
  2. Seleziona File JavaScript. Assegna al file il nome "bingImageSearchDataSource.js". Fai clic su Aggiungi per creare il file. Visual Studio crea un file JavaScript vuoto denominato bingImageSearchDataSource.js.

Passaggio 2: Creare un oggetto IListDataAdapter

Il passaggio successivo prevede la creazione di un oggetto che implementi l'interfaccia IListDataAdapter. IListDataAdapter recupera dati da un'origine dati e li fornisce a IListDataSource.

L'interfaccia IListDataAdapter supporta l'accesso di lettura e scrittura e le notifiche di modifica. Tuttavia, non devi implementare l'interfaccia per intero, puoi semplicemente creare un'interfaccia IListDataAdapter di sola lettura attraverso l'implementazione dei soli metodi itemsFromIndex e getCount.

  1. Apri bingImageSearchDataSource.js, il file JavaScript che hai creato nel passaggio precedente.

  2. Crea una funzione anonima e attiva la modalità strict.

    Come abbiamo descritto in Codifica delle app di base, è consigliabile incapsulare il codice JavaScript eseguendone il wrapping all'interno di una funzione anonima, come pure usare la modalità strict.

    (function () {
        "use strict"; 
    
  3. Usa la funzione WinJS.Class.define per creare l'implementazione di IListDataAdapter. Il primo parametro che la funzione WinJS.Class.define accetta è il costruttore della classe.

    Questo IListDataAdapter eseguirà la connessione al servizio di ricerca di Bing. La query di ricerca dell'API di Bing prevede determinati dati. Archivieremo questi dati, nonché altri dati aggiuntivi, nell'elemento IListDataAdapter come membri di classe.

    • _minPageSize: il numero minimo di elementi per pagina.
    • _maxPageSize: il numero massimo di elementi per pagina.
    • _maxCount: il numero massimo di elementi da restituire.
    • _devKey: l'ID dell'app. L'API di Bing richiede una chiave AppID per identificare l'applicazione.
    • _query: la stringa di ricerca.

    Crea un costruttore che accetti un AppID per l'API di Bing e una query di ricerca e che fornisca valori per gli altri membri.

    
        // Definition of the data adapter
        var bingImageSearchDataAdapter = WinJS.Class.define(
            function (devkey, query) {
    
                // Constructor
                this._minPageSize = 10;  // based on the default of 10
                this._maxPageSize = 50;  // max request size for bing images
                this._maxCount = 1000;   // limit on the bing API
                this._devkey = devkey;
                this._query = query;
            },
    
  4. Il parametro successivo previsto dalla funzione WinJS.Class.define è un oggetto contenente i membri dell'istanza della classe. Tale oggetto viene usato per implementare i metodi itemsFromIndex e getCount.

    Crea la parentesi graffa di apertura per questo oggetto.

            // IListDataDapter methods
            // These methods define the contract between the IListDataSource and the IListDataAdapter.
            {
    
    1. Implementa il metodo itemsFromIndex. Il metodo itemsFromIndex si collega all'origine dati e restituisce i dati richiesti come IFetchResult. Il metodo itemsFromIndex usa tre parametri: l'indice di un elemento da recuperare, il numero di elementi che precedono l'elemento da recuperare e il numero di elementi che seguono l'elemento da recuperare.

                  itemsFromIndex: function (requestIndex, countBefore, countAfter) {
                      var that = this;
      
    2. Verifica che l'elemento richiesto (requestIndex) sia minore del numero massimo di elementi da recuperare. In caso contrario, restituisci un errore.

                      if (requestIndex >= that._maxCount) {
                          return Promise.wrapError(new WinJS.ErrorFromName(UI.FetchError.doesNotExist));
                      }
      
    3. Usa requestIndex, countBefore e countAfter per calcolare l'indice del primo elemento e la dimensione della richiesta. I parametri countBefore e countAfter sono consigli sulla quantità di dati da recuperare: non devi recuperare tutti gli elementi che ti vengono richiesti. In questo esempio la dimensione massima della richiesta di Bing è di 50 elementi, pertanto è preferibile limitare le dimensioni della richiesta a questo valore.

      In genere, una richiesta chiede uno o due elementi precedenti o successivi all'elemento richiesto e un numero maggiore dal lato opposto, pertanto dobbiamo tenerne conto quando decidiamo cosa chiedere al server.

                      var fetchSize, fetchIndex;
      
                      // See which side of the requestIndex is the overlap.
                      if (countBefore > countAfter) {
                          // Limit the overlap
                          countAfter = Math.min(countAfter, 10);
      
                          // Bound the request size based on the minimum and maximum sizes.
                          var fetchBefore = Math.max(
                              Math.min(countBefore, that._maxPageSize - (countAfter + 1)),
                              that._minPageSize - (countAfter + 1)
                              );
                          fetchSize = fetchBefore + countAfter + 1;
                          fetchIndex = requestIndex - fetchBefore;
                      } else {
                          countBefore = Math.min(countBefore, 10);
                          var fetchAfter = Math.max(Math.min(countAfter, that._maxPageSize - (countBefore + 1)), that._minPageSize - (countBefore + 1));
                          fetchSize = countBefore + fetchAfter + 1;
                          fetchIndex = requestIndex - countBefore;
                      }
      
    4. Crea la stringa di richiesta.

                      // Create the request string. 
                      var requestStr = "http://api.bing.net/json.aspx?"
                      + "AppId=" + that._devkey
                      + "&Query=" + that._query
                      + "&Sources=Image"
                      + "&Version=2.0"
                      + "&Market=en-us"
                      + "&Adult=Strict"
                      + "&Filters=Aspect:Wide"
                      + "&Image.Count=" + fetchSize
                      + "&Image.Offset=" + fetchIndex
                      + "&JsonType=raw";
      
    5. Usa WinJS.xhr per inviare la richiesta. WinJS.xhr restituisce un oggetto Promise che contiene il risultato. Puoi elaborare il risultato chiamando il metodo then dell'oggetto Promise.

                      return WinJS.xhr({ url: requestStr }).then(
      
    6. Crea un callback per un'operazione WinJS.xhr riuscita. Questa funzione elabora i risultati e li restituisce come elemento IFetchResult. IFetchResult contiene le tre proprietà elencate di seguito.

      • items: una matrice di oggetti IItem che rappresentano i risultati della query.
      • offset: l'indice dell'elemento della richiesta nella matrice di elementi.
      • totalCount: il numero totale di elementi nella matrice di elementi.

      Ogni IItem deve presentare una proprietà chiave contenente un identificatore per tale elemento e una proprietà dati contenente i dati dell'elemento:

      { key: key1, data : { field1: value, field2: value, ... }}

      Ecco come si presenta la matrice di oggetti IItem:

      [{ key: key1, data : { field1: value, field2: value, ... }}, { key: key2, data : {...}}, ...];

                          function (request) {
                              var results = [], count;
      
                              // Use the JSON parser on the results (it's safer than using eval).
                              var obj = JSON.parse(request.responseText);
      
                              // Verify that the service returned images.
                              if (obj.SearchResponse.Image !== undefined) {
                                  var items = obj.SearchResponse.Image.Results;
      
                                  // Create an array of IItem objects:
                                  // results =[{ key: key1, data : { field1: value, field2: value, ... }}, { key: key2, data : {...}}, ...];
                                  for (var i = 0, itemsLength = items.length; i < itemsLength; i++) {
                                      var dataItem = items[i];
                                      results.push({
                                          key: (fetchIndex + i).toString(),
                                          data: {
                                              title: dataItem.Title,
                                              thumbnail: dataItem.Thumbnail.Url,
                                              width: dataItem.Width,
                                              height: dataItem.Height,
                                              linkurl: dataItem.Url
                                          }
                                      });
                                  }
      
                                  // Get the count.
                                  count = obj.SearchResponse.Image.Total;
      
                                  return {
                                      items: results, // The array of items.
                                      offset: requestIndex - fetchIndex, // The index of the requested item in the items array.
                                      totalCount: Math.min(count, that._maxCount), // The total number of records. Bing will only return 1000, so we cap the value.
                                  };
                              } else {
                                  return WinJS.UI.FetchError.doesNotExist;
                              }
                          },
      
    7. Crea un callback per le operazioni WinJS.xhr non riuscite.

                          // Called if the WinJS.xhr funtion returned an error. 
                          function (request) {
                              return WinJS.UI.FetchError.noResponse;
                          });
      
    8. Chiudi il metodo itemsFromIndex. Definirai un altro metodo in seguito, per cui aggiungi una virgola dopo la chiusura di itemsFromIndex.

                  },
      
  5. Implementa il metodo getCount.

    1. Il metodo getCount non accetta alcun parametro e restituisce un oggetto Promise per il numero di elementi nei risultati dell'oggetto IListDataAdapter.

                  // Gets the number of items in the result list. 
                  // The count can be updated in itemsFromIndex.
                  getCount: function () {
                      var that = this;
      
    2. Crea la stringa di richiesta. Dato che Bing non prevede un modo esplicito per richiedere il conteggio, richiediamo un record e lo usiamo per ottenere il conteggio.

      
                      // Create up a request for 1 item so we can get the count
                      var requestStr = "http://api.bing.net/json.aspx?";
      
                      // Common request fields (required)
                      requestStr += "AppId=" + that._devkey
                      + "&Query=" + that._query
                      + "&Sources=Image";
      
                      // Common request fields (optional)
                      requestStr += "&Version=2.0"
                      + "&Market=en-us"
                      + "&Adult=Strict"
                      + "&Filters=Aspect:Wide";
      
                      // Image-specific request fields (optional)
                      requestStr += "&Image.Count=1"
                      + "&Image.Offset=0"
                      + "&JsonType=raw";
      
    3. Usa WinJS.xhr per inviare la richiesta. Elabora i risultati e restituisci il conteggio.

                      // Make an XMLHttpRequest to the server and use it to get the count.
                      return WinJS.xhr({ url: requestStr }).then(
      
                          // The callback for a successful operation.
                          function (request) {
                              var data = JSON.parse(request.responseText);
      
                              // Bing may return a large count of items, 
                              /// but you can only fetch the first 1000.
                              return Math.min(data.SearchResponse.Image.Total, that._maxCount);
                          },
                          function (request) {
                              return WinJS.Promise.wrapError(new WinJS.ErrorFromName(WinJS.UI.FetchError.doesNotExist));
                          });
                  }
      
  6. Questo è l'ultimo membro dell'istanza. Puoi quindi chiudere l'oggetto che hai creato per contenerli. Esistono altri metodi IListDataAdapter che potresti implementare, ma non sono necessari per creare un'origine dati di sola lettura.

                // setNotificationHandler: not implemented
                // itemsFromStart: not implemented
                // itemsFromEnd: not implemented
                // itemsFromKey: not implemented
                // itemsFromDescription: not implemented
            }
    
  7. Chiudi la chiamata di WinJS.Class.define.

            );
    

    Hai creato una classe denominata bingImageSarchDataAdapter che implementa l'interfaccia IListDataAdapter. Ora creerai un oggetto IListDataSource.

Passaggio 3: Creare un oggetto IListDataSource

Un oggetto IListDataSource connette un controllo (ad esempio ListView) a IListDataAdapter. IListDataSource modifica IListDataAdapter, che provvede effettivamente a modificare e recuperare i dati. In questo passaggio implementi IListDataSource.

WinJS ti fornisce un'implementazione dell'interfaccia IListDataSource: l'oggetto VirtualizedDataSource. Puoi usare questo oggetto utile per implementare IListDataSource. Come vedremo tra un momento, non c'è molto da fare.

  1. Usa la funzione WinJS.Class.derive per creare una classe che eredita da VirtualizedDataSource. Per quanto riguarda il secondo parametro della funzione, definisci un costruttore che usi l'AppID di Bing e una stringa di query. Fai in modo che il costruttore chiami il costruttore della classe base e passagli un nuovo oggetto bingImageSarchDataAdapter (quello che hai definito al passaggio precedente).

        var bingImageSearchDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, function (devkey, query) {
            this._baseDataSourceConstructor(new bingImageSearchDataAdapter(devkey, query));
        });
    
  2. Usa la funzione WinJS.Namespace.define per definire uno spazio dei nomi e rendere la classe accessibile pubblicamente. La funzione WinJS.Namespace.define accetta due parametri: il nome dello spazio dei nomi da creare e un oggetto contenente una o più coppie nome/valore. Ogni proprietà è il nome pubblico del membro, mentre ogni valore è la variabile, la proprietà o la funzione sottostante nel tuo codice privato che vuoi esporre.

        WinJS.Namespace.define("DataExamples", { bingImageSearchDataSource: bingImageSearchDataSource });  
    
  3. Hai appena implementato un IListDataAdapter e un IListDataSource. Hai terminato tutte le operazioni su bingImageSearchDataSource.js e puoi quindi chiudere la funzione anonima esterna.

    })();
    

    Per usare l'origine dati personalizzata, crea una nuova istanza della classe bingImageSearchDataSource. Passa al costruttore l'AppID di Bing per la tua app e una query di ricerca:

    var myDataSrc = new DataExamples.bingImageSearchDataSource(devKey, searchTerm);
    

    Puoi ora usare bingImageSearchDataSource con i controlli che accettano un IListDataSource, ad esempio il controllo ListView.

Esempio completo

Ecco il codice completo per bingImageSearchDataSource.js. Per visualizzare l'esempio completo, vedi l'esempio Uso delle origini dati.

// Bing image search data source example
//
// This code implements a datasource that will fetch images from Bing's image search feature
// Because the Bing service requires a developer key, and each app needs its own key, you must
// register as a developer and obtain an App ID to use as a key. 
// For more info about how to obtain a key and use the Bing API, see
// https://bing.com/developers and https://msdn.microsoft.com/en-us/library/dd251056.aspx


(function () {

    // Define the IListDataAdapter.
    var bingImageSearchDataAdapter = WinJS.Class.define(
        function (devkey, query) {

            // Constructor
            this._minPageSize = 10;  // based on the default of 10
            this._maxPageSize = 50;  // max request size for bing images
            this._maxCount = 1000;   // limit on the bing API
            this._devkey = devkey;
            this._query = query;
        },

        // IListDataDapter methods
        // These methods define the contract between the IListDataSource and the IListDataAdapter.
        // These methods will be called by vIListDataSource to fetch items, 
        // get the number of items, and so on.
        {
            // This example only implements the itemsFromIndex and count methods

            // The itemsFromIndex method is called by the IListDataSource 
            // to retrieve items. 
            // It will request a specific item and hints for a number of items before and after the
            // requested item. 
            // The implementation should return the requested item. You can choose how many
            // additional items to send back. It can be more or less than those requested.
            //
            //   This funtion must return an object that implements IFetchResult. 
            itemsFromIndex: function (requestIndex, countBefore, countAfter) {
                var that = this;
                if (requestIndex >= that._maxCount) {
                    return Promise.wrapError(new WinJS.ErrorFromName(UI.FetchError.doesNotExist));
                }

                var fetchSize, fetchIndex;

                // See which side of the requestIndex is the overlap.
                if (countBefore > countAfter) {
                    // Limit the overlap
                    countAfter = Math.min(countAfter, 10);

                    // Bound the request size based on the minimum and maximum sizes.
                    var fetchBefore = Math.max(
                        Math.min(countBefore, that._maxPageSize - (countAfter + 1)),
                        that._minPageSize - (countAfter + 1)
                        );
                    fetchSize = fetchBefore + countAfter + 1;
                    fetchIndex = requestIndex - fetchBefore;
                } else {
                    countBefore = Math.min(countBefore, 10);
                    var fetchAfter = Math.max(Math.min(countAfter, that._maxPageSize - (countBefore + 1)), that._minPageSize - (countBefore + 1));
                    fetchSize = countBefore + fetchAfter + 1;
                    fetchIndex = requestIndex - countBefore;
                }

                // Create the request string. 
                var requestStr = "http://api.bing.net/json.aspx?"
                + "AppId=" + that._devkey
                + "&Query=" + that._query
                + "&Sources=Image"
                + "&Version=2.0"
                + "&Market=en-us"
                + "&Adult=Strict"
                + "&Filters=Aspect:Wide"
                + "&Image.Count=" + fetchSize
                + "&Image.Offset=" + fetchIndex
                + "&JsonType=raw";

                // Return the promise from making an XMLHttpRequest to the server.
                return WinJS.xhr({ url: requestStr }).then(

                    // The callback for a successful operation. 
                    function (request) {
                        var results = [], count;

                        // Use the JSON parser on the results (it's safer than using eval).
                        var obj = JSON.parse(request.responseText);

                        // Verify that the service returned images.
                        if (obj.SearchResponse.Image !== undefined) {
                            var items = obj.SearchResponse.Image.Results;

                            // Create an array of IItem objects:
                            // results =[{ key: key1, data : { field1: value, field2: value, ... }}, { key: key2, data : {...}}, ...];
                            for (var i = 0, itemsLength = items.length; i < itemsLength; i++) {
                                var dataItem = items[i];
                                results.push({
                                    key: (fetchIndex + i).toString(),
                                    data: {
                                        title: dataItem.Title,
                                        thumbnail: dataItem.Thumbnail.Url,
                                        width: dataItem.Width,
                                        height: dataItem.Height,
                                        linkurl: dataItem.Url
                                    }
                                });
                            }

                            // Get the count.
                            count = obj.SearchResponse.Image.Total;

                            return {
                                items: results, // The array of items.
                                offset: requestIndex - fetchIndex, // The index of the requested item in the items array.
                                totalCount: Math.min(count, that._maxCount), // The total number of records. Bing will only return 1000, so we cap the value.
                            };
                        } else {
                            return WinJS.UI.FetchError.doesNotExist;
                        }
                    },

                    // Called if the WinJS.xhr funtion returned an error. 
                    function (request) {
                        return WinJS.UI.FetchError.noResponse;
                    });
            },


            // Gets the number of items in the result list. 
            // The count can be updated in itemsFromIndex.
            getCount: function () {
                var that = this;

                // Create up a request for 1 item so we can get the count
                var requestStr = "http://api.bing.net/json.aspx?";

                // Common request fields (required)
                requestStr += "AppId=" + that._devkey
                + "&Query=" + that._query
                + "&Sources=Image";

                // Common request fields (optional)
                requestStr += "&Version=2.0"
                + "&Market=en-us"
                + "&Adult=Strict"
                + "&Filters=Aspect:Wide";

                // Image-specific request fields (optional)
                requestStr += "&Image.Count=1"
                + "&Image.Offset=0"
                + "&JsonType=raw";

                // Make an XMLHttpRequest to the server and use it to get the count.
                return WinJS.xhr({ url: requestStr }).then(

                    // The callback for a successful operation.
                    function (request) {
                        var data = JSON.parse(request.responseText);

                        // Bing may return a large count of items, 
                        /// but you can only fetch the first 1000.
                        return Math.min(data.SearchResponse.Image.Total, that._maxCount);
                    },
                    function (request) {
                        return WinJS.Promise.wrapError(new WinJS.ErrorFromName(WinJS.UI.FetchError.doesNotExist));
                    });
            }

  

            // setNotificationHandler: not implemented
            // itemsFromStart: not implemented
            // itemsFromEnd: not implemented
            // itemsFromKey: not implemented
            // itemsFromDescription: not implemented
        }
        );

    var bingImageSearchDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, function (devkey, query) {
        this._baseDataSourceConstructor(new bingImageSearchDataAdapter(devkey, query));
    });

    WinJS.Namespace.define("DataExamples", { bingImageSearchDataSource: bingImageSearchDataSource }); 

})();