Dieser Artikel wurde maschinell übersetzt.

JavaScript

Datenbindung in einer Windows Store-App mit JavaScript

Chris Sells
Brandon Satrom

In diesem Artikel untersuchen wir die Datenbindung in einer Windows-Speicher-app mit JavaScript gebaut. Dies ist ein Hybrid von anderen Arten von apps für Windows 8 gebaut. Es ist wie eine desktop-Anwendung, insofern sie auf Ihrem Computer, im Gegensatz zu einer Website installiert ist. Auf der anderen Seite, ist es wie eine Website, dass Sie es mit HTML5, JavaScript und CSS3 erstellen können. Jedoch anstatt die Benutzeroberfläche auf der Serverseite generieren, das JavaScript-Framework zum Erstellen von Windows Store apps und der zugrunde liegenden Windows-Runtime können Sie apps mit clientseitigen Zustand, offline-Speicher, Steuerelemente, Vorlagen und Bindung erstellen — sowie eine ganze Reihe anderer Dienste.

Datenbindung ist die Fähigkeit, den Wert einer Liste von Daten, z. B. eine Reihe von RSS-Feeds, und verwenden Sie es zum Auffüllen eines Steuerelements, z. B. eine ListView. Wir können zusammen, welche Daten wir extrahieren Sie mithilfe von Vorlagen. Wir zeigen wie die Bindung noch flexibler als das, ist erlaubt, Aktualisieren der Benutzeroberfläche Änderungen der zugrunde liegenden Daten, zusammen mit sortieren, Filtern und gruppieren.

Wenn wir die Datenbindung verwenden, ist es oft im Rahmen eines Steuerelements. Wir werden einen Blick auf das ListView-Steuerelement und seine Unterstützung für Datenbindung und Vorlagen.

Datenbindung 101

Die Verwendung der Bindung ermöglicht Ihnen die Einrichtung einer Assoziation zwischen zwei Eigenschaften auf zwei Objekte, die in den meisten Fällen die Eigenschaft eines Objekts mit einer Eigenschaft für ein Element HTML Document Object Model (DOM) als zuordnen Abbildung 1 zeigt.

Binding Between an Attribute on a Destination Element and a Property from a Source Object
Abbildung 1 Bindung zwischen einem Attribut auf ein Zielelement und eine Eigenschaft aus einem Quellobjekt

Zur Gründung einer Bindung dient zum Kopieren von Daten zwischen den beiden Objekten beteiligt: die Quelle, von wo die Daten kommt und das Ziel, zu dem die Daten geht. Man könnte meinen, dass Sie dieses Ziel eine einfache Zuweisungsanweisung erreichen können:

myDestElem.value = mySourceObj.name;

Grundsätzlich ist die Zuordnung welche Bindung hat. Allerdings ist Bindung nicht nur eine Beschreibung, welche Daten zu kopieren und wohin, sondern auch wann. Das "Wann" einer Bindung ist in der Regel eine der folgenden:

  • Unidirektionale Bindung: Kopieren Sie die Daten auf das DOM-Element, wenn das Objekt ändert. Dies ist die Standardeinstellung in der Windows-Library für JavaScript (WinJS).
  • Einmalige Bindung: Kopieren Sie die Daten auf das DOM-Element, wenn die Bindung erstmalig eingerichtet wird. Dies entspricht der Zuordnung.
  • Bidirektionale Bindung: Kopieren Sie die Daten auf das DOM-Element, wenn das Objekt geändert, und kopieren Sie die Daten auf das Objekt, wenn das DOM-Element ändert. Dies ist nicht in WinJS unterstützt.

Standardmäßig ist WinJS Bindung unidirektionale Bindung, obwohl einmalige Bindung auch unterstützt wird. Obwohl WinJS nicht bidirektionalen Bindung unterstützt, ist ein schöner Ort, in Ihrem Lieblings bidirektionale Bindung-Engine wie in jQuery, Haken, wie Sie sehen werden.

Binding-Objekte

Um loszulegen, nehmen wir einen kleinen Browser für die Menschen in unserem Leben aufbauen wollen, wie in Abbildung 2.

Abbildung 2 Binden eines Objekts an eine Gruppe von HTML-Elementen

Die Idee ist, dass wir eine Reihe von Menschen, denen wir können navigieren, jedes mit einem Namen, Alter und eine Lieblingsfarbe, haben kann. Wie wir die Schaltflächen zurück und weiter verwenden, navigieren wir zu anderen Menschen in der Liste, und wenn wir die Taste in der Mitte — die Uhr — einen Geburtstag feiern wir mit zunehmendem Alter der aktuell angezeigte Person. Folgende repräsentiert die Gruppe der Menschen, die wir in unserem Beispiel Surfen sein werde:

var people = [
  { name: "John", age: 18, favoriteColor: "red" },
  { name: "Tom", age: 16, favoriteColor: "green" },
  { name: "Chris", age: 42, favoriteColor: "blue" },
];

Ausgehend von einer Navigation Application Projektvorlage in Visual Studio 2012 bietet HTML für uns zum Auffüllen, siehe Abbildung 3.

Abbildung 3 das Hauptformular

    <!DOCTYPE html>
    <!-- homePage.html -->
    <html>
    <head>
      <meta charset="utf-8" />
      <title>homePage</title>
      <!-- WinJS references -->
      <link href="//Microsoft.WinJS.1.0/css/ui-light.css" rel="stylesheet" />
      <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
      <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
      <link href="/css/default.css" rel="stylesheet" />
      <link href="/pages/home/home.css" rel="stylesheet" />
      <script src="/pages/home/home.js"></script>
    </head>
    <body>
      <!-- The content that will be loaded and displayed.-->
      <div class="fragment homepage">
        <header aria-label="Header content" role="banner">
          <button class="win-backbutton" aria-label="Back"
            disabled type="button"></button>
          <h1 class="titlearea win-type-ellipsis">
            <span class="pagetitle">Welcome to PeopleBrowser!</span>
          </h1>
        </header>
        <section aria-label="Main content" role="main">
          <!-- display each person -->
          <div id="nameLabel">Name</div>
          <input id="name" readonly="true" type="text" 
            data-win-bind="value: name" />
          <div id="ageLabel">Age</div>
          <input id="age" readonly="true" type="text" 
            data-win-bind="value: age" />
          <div id="colorLabel">Favorite Color</div>
          <div id="color" data-win-bind="style.backgroundColor:
            favoriteColor"></div>
          <div id="buttons">
            <button id="previousButton"></button>
            <button id="birthdayButton"></button>
            <button id="nextButton"></button>
          </div>
        </section>
      </div>
    </body>
    </html>

Der interessante Teil dieses HTML ist die Verwendung des Attributs binden Sie-gewinnen, die das folgende Format verwendet:

    <div data-win-bind="destProp1: sourceProp1; destProp2: sourceProp2;..."></div>

Die Sieg-binden-Syntax ist eine durch Semikolons getrennte Liste der Bindungsausdrücke. Jeder Ausdruck ist die Kombination eines Ziel-DOM-Element-Eigenschaft und eine Quelleigenschaft Objekt. Die gepunkteten Syntax, die wir verwenden, legen Sie die Hintergrundfarbe auf den Stil für die Lieblingsfarbe Div — d. h. style.backgroundColor—works für Eigenschaften auf die Quelle und das Ziel, und sie bohrt in Teilobjekte, wie man erwarten würde.

Jede Destination-Eigenschaft in einem Bindungsausdruck wird gegen das HTML-Element aufgelöst, das Sieg-binden-Attribut enthält. Die Frage ist: Wo kommt das Objekt gegen die Eigenschaftsnamen gelöst werden? Und die Antwort ist: der Datenkontext.

Festlegen des Datenkontexts ist Teil des Bindungsvorgangs, die die Zuordnung zwischen dem HTML-Element und welchem Objekt dient als Datenkontext festlegt, wie in Abbildung 4.

Abbildung 4 festlegen des Datenkontexts

// homePage.js
(function () {
  "use strict";
  WinJS.UI.Pages.define("/pages/home/home.html", {
    ready: function (element, options) {
      var people = [
        { name: "John", age: 18, favoriteColor: "red" },
        { name: "Tom", age: 16, favoriteColor: "green" },
        { name: "Chris", age: 42, favoriteColor: "blue" },
      ];
      // Bind the current person to the HTML elements in the section
      var section = element.querySelector("section[role=main]");
      var current = 0;
      WinJS.Binding.processAll(section, people[current]);
    }
  });
})();

Die integrierenAlle-Funktion in der WinJS.Binding-Namespace ist die Funktion, die die Sieg-binden-Attribute für eine gegebene Hierarchie von HTML-Elementen, den Abschnitt mit den Eingabe- und Div-Elementen in unserem Beispiel analysiert. Der Aufruf von integrierenAlle richtet die Bindungen zwischen den HTML-Elementen und den Datenkontext wie in jedem Sieg-binden-Attribut beschrieben. Der Datenkontext ist das zweite Argument für integrierenAlle und wird verwendet, um die Eigenschaftennamen in jeder Bindungsausdruck gefunden zu beheben. Die Ergebnisse bereits was danach wir, wie in dargestellt aussehen Abbildung 2.

Standardmäßig Wenn wir nichts anderes tun, haben wir eine unidirektionale Bindung-Verbindung zwischen dem Daten-Kontext-Objekt und das DOM-Element aufgebaut. Das bedeutet, dass als Eigenschaften auf der Daten-Quelle-Objekt ändern, wir die Ausgabe als auch erwarten, wie in dargestellt ändern Abbildung 5.

Abbildung 5 als Eigenschaften auf der Daten-Quelle ändern, So auch die Ausgabe

function ready(element, options) {
  var people = [
    { name: "John", age: 18, favoriteColor: "red" },
    { name: "Tom", age: 16, favoriteColor: "green" },
    { name: "Chris", age: 42, favoriteColor: "blue" },
  ];
  var section = element.querySelector("section[role=main]");
  var current = 0;
  WinJS.Binding.processAll(section, people[current]);
  birthdayButton.onclick = function () {
    var person = people[current];
    person.age++; // Changing a bound property doesn't work yet ...
  };
}

Unsere Implementierung von den Click-Ereignishandler für die Schaltfläche "Geburtstag" sucht das aktuelle Element und ändert ein Anwesen, speziell im Alter. Wir sind jedoch nicht ganz wo wir bekommen die Benutzeroberfläche automatisch aktualisiert werden müssen.

Das Problem ist, dass ein standard-JavaScript-Objekt kein Benachrichtigung-Protokoll unterstützt, um Interessenten zu informieren – z. B. eine Bindung —, die seine Daten geändert hat. Die Benachrichtigung hinzufügen-Protokoll ist eine Frage der Berufung der as-Methode aus dem WinJS.Binding-Namespace, wie in Abbildung 6.

Abbildung 6 hinzufügen die Notification-Protokolls

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    var current = 0;
    WinJS.Binding.processAll(section, people[current]);
    birthdayButton.onclick = function () {
      var person = people[current];
      person.age++; // Now this works!
    };
  }
});

Die "als" Methode umschließt jedes Objekt, das Benachrichtigung Bindungsprotokoll bereitstellen, so dass jeder Eigenschaftenänderung Listener Bindung (z. B. unsere gebundenen HTML-Elemente benachrichtigt). Mit diesem Code, ändern das Alter einer Person spiegelt sich in der Benutzeroberfläche als Abbildung 7 zeigt.

Changing the Underlying Data Automatically Updates the Bound HTML Elements
Abbildung 7 Änderung der zugrunde liegenden Daten automatisch aktualisiert die gebundenen HTML-Elemente

Wir haben Binden einer einzigen Person-Objekts an den Satz von HTML-Elementen für die Anzeige, aber Sie können Datenbindungsausdrücke in die Sieg-binden-Attribute mit einer anderen Art der Datenkontext verarbeiten, wie in Abbildung 8.

Abbildung 8 Verarbeitung der Datenbindungsausdrücke

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    var current = 0;
    var viewModel = WinJS.Binding.as({ person: people[current] });
    WinJS.Binding.processAll(section, viewModel);
    birthdayButton.onclick = function () {
      viewModel.person.age++;
    };
    // Bind to the previous object
    previousButton.onclick = function () {
      current = (people.length + current - 1) % people.length;
      viewModel.person = people[current];
    };
    // Bind to the next object
    nextButton.onclick = function () {
      current = (people.length + current + 1) % people.length;
      viewModel.person = people[current];
    };
  }
});

Hier ist wo wir eine Verschiebung zwischen Weitergabe von Daten in einer einzigen aus der app "Modell" (das heißt, der Satz von Daten, die nichts mit der Anzeige von sich selbst zu tun hat) machen zu gruppieren der Daten, die für unsere "Ansicht" des Modells (in diesem Fall die aktuelle Person anzeigen) geeignet ist. Wir nennen diese Variable "Ansichtsmodell" nach einer berühmten und nützliche Technik für die Umsetzung von UIs genannt Model-View-ViewModel (MVVM). Nachdem wir unsere Ansichtsmodell als bindbare Objekt erstellt haben, als die zugrunde liegenden Eigenschaften ändern (die Person, in unserem Fall) die Ansicht wird aktualisiert. Wir dann unsere Ansicht an das Ansichtsmodell binden, so in unserem weiter und zurück Handler Schaltfläche — wie wir welche Person ändern möchten wir zeigen — die Ansicht wird benachrichtigt. Damit dies funktioniert, müssen wir den HTML-Code um das Ansichtsmodell statt die Person direkt zu verwenden, zu aktualisieren, wie in Abbildung 9.

Abbildung 9 aktualisieren HTML um das Ansichtsmodell zu verwenden

 

    <section aria-label="Main content" role="main">
      <!-- display each person -->
      <div id="nameLabel">Name</div>
      <input id="name" readonly="true" type="text" 
        data-win-bind="value: person.name" />
      <div id="ageLabel">Age</div>
      <input id="age" readonly="true" type="text" 
        data-win-bind="value: person.age" />
      <div id="colorLabel">Favorite Color</div>
      <div id="color" 
        data-win-bind="style.backgroundColor: person.favoriteColor"></div>
      <div id="buttons">
        <button id="previousButton"></button>
        <button id="birthdayButton"></button>
        <button id="nextButton"></button>
      </div>
    </section>

Abbildung 10 zeigt das Ergebnis.

You Can Rebind Different Objects to the Same Set of HTML Elements
Abbildung 10 können Sie verschiedene Objekte den gleichen Satz von HTML-Elemente binden

Zusätzlich zum Binden von Objekten an Elemente, ermöglicht Bindung auch einfach für einen Wert ändern zu hören. Zum Beispiel wie wir den Index auf den aktuellen Wert zu ändern klickt der Benutzer auf die vorherigen oder nächsten Schaltflächen, müssen jetzt wir vergessen Sie nicht, schreiben Sie den Code um das Ansichtsmodell Person Feld entsprechend zu ändern. Sie konnte jedoch verwenden, selbst hier, helfen in beschriebenen Binden Abbildung 11.

Abbildung 11 Wiederaufbereitung Bindungsausdrücke

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    // Listen for the current index to change and update the HTML
    var viewModel = WinJS.Binding.as({ current: 0, person: null });
    WinJS.Binding.processAll(section, viewModel);
    viewModel.bind("current", function (newValue, oldValue) {
      viewModel.person = people[newValue];
    });
    birthdayButton.onclick = function () {
      viewModel.person.age++;
    };
    // Bind to the previous object
    previousButton.onclick = function () {
      // Set the current index and let the binding do the work
      viewModel.current = (people.length + 
        viewModel.current - 1) % people.length;
    };
    // Bind to the next object
    nextButton.onclick = function () {
      // Set the current index and let the binding do the work
      viewModel.current = (people.length + 
        viewModel.current + 1) % people.length;
    };
  }
});

Statt einer einfachen Variablen für den Index der aktuell angezeigte Person fügen wir den Index der aktuell angezeigte Person an unserer bindbare Ansichtsmodell. Alle bindbare Objekte haben eine Bind-Methode, die uns erlaubt, die Änderungen an den Eigenschaften des Objekts (der current-Eigenschaft in diesem Beispiel) zu hören. Klickt der Benutzer auf den vorherigen oder nächsten Schaltflächen, ändern wir einfach dem Index des aktuellen Person gezeigt werden und lassen den Bind-Handler-Prozess die Sieg-binden-Attribute für den HTML-Code, der die aktuelle Person zeigt.

Wenn Sie Bind Ereignisse zu stoppen möchten, können Sie die Unbind-Methode aufrufen.

Nun, wie erwähnt, funktioniert alles, was Sie gesehen haben gegen die Standardeinstellung: unidirektionale Bindung. Jedoch, wenn Sie andere Arten der Bindung einrichten oder an der Bindungsprozess selbst teilnehmen möchten, können Sie mit einer Bindung-Initialisierung tun.

Initialisierungen

Eine Initialisierung ist die optionalen dritten Parameter auf einen verbindlichen Ausdruck, der gibt eine Funktion aufrufen, wenn die Bindung hergestellt wird:

    <div data-win-bind="destProp: sourceProp init" ...></div>

Eine Initialisierung als Teil eines Bindungsausdrucks zu bieten, wenn Sie möchten teilnehmen oder sogar ersetzen der vorhandenen Bindung Verhalten — z. B. zum Durchführen einer Datenkonvertierung oder sogar Haken jQuery bidirektionale Bindung. Eine Bindung-Initialisierung ist eine Funktion, die für die unidirektionale Standardbindung übernimmt und die folgende Signatur hat:

function myInit(source, sourceProperties,
  dest, destProperties) {...}

Die Details der Implementierung einer benutzerdefinierten Initialisierung sind, würde den Rahmen dieses Artikels sprengen, aber WinJS hat integrierte mehrere Initialisierungen, die Sie nutzen können. Beispielsweise möchten Sie tun einmalige anstelle von unidirektionalen Bindung, können Sie die einmalige Funktion aus dem WinJS.Binding-Namespace:

    <input data-win-bind=
      "value: person.name WinJS.Binding.oneTime"></input>

Am anderen Ende des Spektrums, wenn unidirektionalen Bindung durchführen ist es oft sinnvoll, Datenkonvertierung (auch bekannt als Datenumwandlung) ausführen. Zum Beispiel stellen Sie vor, dass wir das Alter der Menschen in unserem Leben buchstabieren wollte:

function getWordsFromNumber(i) {...}
// Convert ages to words
window.ageToWords =
  WinJS.Binding.converter(function (value) { 
    return getWordsFromNumber(value); 
  });

Die Konverter-Funktion auf dem WinJS.Binding-Namespace stellt den schwierige Teil der Initialisierer Umsetzung; alles, was Sie tun müssen ist die Funktion zum Ausführen der eigentlichen Konvertierungs angeben und es als die Wertänderungen der Quelle genannt werden. Verwendung in den HTML-Code sieht wie man erwarten würde:

    <input data-win-bind="value: person.age ageToWords"></input>

Sie sehen die Ergebnisse in Abbildung12.

Translating a Numeric Age into Words via Data Conversion
Abbildung 12 übersetzen Wörter über Daten-Konvertierung eines numerischen Zeitalters

Verbindlicher Werte eins zu einem Zeitpunkt ist nützlich, aber noch nützlicher — speziell für Windows Store apps — Auflistungen von Werten auf einmal verbindlich ist. Dafür haben wir der Bindungsliste.

Eine verbindliche Liste

Stellen Sie sich ein einfaches Beispiel für ein ListView-Steuerelement mit einer Auflistung von Werten mit:

<div data-win-control="WinJS.UI.ListView"
  data-win-options="{itemDataSource: items.dataSource}">
</div>

Hier erstellen ein ListView-Steuerelement deklarativ in HTML wir die die DataSource-Eigenschaft eines globalen Elemente-Objekts gebunden ist. In unsere JavaScript ist es einfach zu erstellen und füllen das Items-Objekt als verbindliche Liste:

// A global binding list of items
window.items = new WinJS.Binding.List();
[0, 1, 2].forEach(function (i) {
  WinJS.Promise.timeout(500 * (i+1)).done(function () {
    // Add an item to the binding list, updating the ListView
    items.push(i);
  });
});

In diesem Code erstellen wir eine verbindliche Liste (eine Instanz des Typs Liste aus dem WinJS.Binding-Namespace) und wir Schleife über ein Array von Werten, mit den einzelnen einen Timeout zu erstellen, der ein Versprechen ist, das zu einem bestimmten Zeitpunkt in der Zukunft nach dem Argument ausgelöst wird Sie übergeben (Millisekunden). Wenn jeder Timeout abgeschlossen ist, sehen wir die ListView, erhalten einen zusätzlichen Wert, als Abbildung 13 zeigt.

The ListView Updating as the Underlying Binding List Updates
Abbildung 13 aktualisiert die ListView Aktualisieren der zugrunde liegenden Bindungsliste

Das HTML keine ID für die ListView stellen, noch interagiert das JavaScript mit der ListView in keiner Weise. Stattdessen rendezvous die HTML- und JavaScript-sowohl auf die Elemente, die verbindliche Liste. Es ist die Bindungsliste, die die Auflistung binden API (genannt IListDataSource) implementiert. Statt machen Sie programmieren IListDataSource direkt — es ist nicht besonders Programmierer-Friendly — der Bindungsliste macht seine IListDataSource Umsetzung über die DataSource-Eigenschaft verfügbar.

Um eine API bereit, die so vertraut wie möglich, JavaScript-Programmierer, der Bindungsliste implementiert eine ähnliche API und ähnliche Semantik wie das integrierte Array unterstützt — beispielsweise push, pop, Scheiben, Arkane und so weiter. Zum Vergleich funktioniert so das integrierte JavaScript-Array:

// Using the built-in array
var array = [];
array.push("one");
array.push("two");
array.push("three");
var x = array[0]; // x = "one"
var y = array[1]; // y = "two"
array[2] = "THREE";
var z = array[2]; // z = "THREE";

Der Bindungsliste verhält sich ähnlich wie außer dass anstelle eines Indexers — d. h. eckige Klammern — es macht Elemente über SetAt und GetAt verfügbar:

// Using the WinJS binding list
var list = new WinJS.Binding.List();
list.push("one");
list.push("two");
list.push("three");
var x = list.getAt(0); // x = "one"
var y = list.getAt(1); // y = "two"
list.setAt(2, "THREE");
var z = list.getAt(2); // z = "THREE";

Sortieren und Filtern

Neben der bekannten API wurde der Bindungsliste mit Windows-Speicher-app, die Bedürfnisse im Auge Gebäude gebaut. Sie haben bereits gesehen, wie die DataSource-Eigenschaft des ListView-Steuerelements angeschlossen werden kann. Darüber hinaus könnte Sie sortieren und Filtern von Daten interessieren. Zum Beispiel, hier ist unsere Liste der Menschen wieder, diesmal in eine verbindliche Liste eingeschlossen:

var people = new WinJS.Binding.List([
  { name: "Tom", age: 16 },
  { name: "John", age: 17 },
  { name: "Chris", age: 42 },
]);
// Sort by name
window.sortedPeople = people.createSorted(function (lhs, rhs) { 
    return lhs.name.localeCompare(rhs.name); 
  });
// Filter by age (adults only)
window.filteredPeople = people.createFiltered(function (p) { return p.age > 17; });

Wir können eine verbindliche Liste zu sortieren, durch Aufrufen der CreateSorted-Methode, ein Sortier-Funktion übergeben oder durch Aufrufen der CreateFiltered-Methode, übergeben Sie eine Funktion für die Filterung zu filtern. Das Ergebnis der Aufruf einer dieser Methoden erstellen eine Ansicht über die Daten, die sieht aus und verhält sich wie eine andere Instanz der Bindungsliste, und wir können es zu einer ListView binden, als Abbildung 14 zeigt.

Filtering a Binding List
Abbildung 14 eine verbindliche Liste filtern

Anstatt eine Kopie der zugrunde liegenden Daten, zurück die Methoden CreateSorted und CreateFiltered ein live-Blick über die vorhandenen Daten. Das bedeutet, dass alle Änderungen an den zugrunde liegenden Daten sich in den Ansichten spiegeln und werden in allen gebundenen Steuerelementen angezeigt. Beispielsweise könnten wir ein Minderjähriger der zugrunde liegenden Liste hinzufügen:

// Changes to the underlying data are reflected in the live views
var person = { name: "Pete", age: 17, favoriteColor: "black" };
people.push(person);

Obwohl wir die zugrunde liegenden Daten ändern sind, die sortierte Ansicht aktualisiert wird, und das ListView-Steuerelement über die Änderung, als benachrichtigt werden Abbildung 15 zeigt.

Sorting a Binding List
Abbildung 15 eine verbindliche Liste sortieren

Auch, weil der Blick von der Create-Methoden sieht und fühlt sich wie eine verbindliche Liste, können weiter sortieren oder Filtern Sie die Ansicht in einem gestapelten Weise:

// Filterd by age (minors) and sorted by name
window.filteredSortedPeople = people.
  createFiltered(function (p) { return p.age < 18; }).
  createSorted(function (lhs, rhs) { 
    return lhs.name.localeCompare(rhs.name); 
  });

Die Ergebnisse der Bindung an die resultierende gefilterte und sortierte Ansicht sollte keine Überraschung sein (siehe Abbildung 16).

Sorting and Filtering a Binding List
Abbildung 16 sortieren und Filtern eine verbindliche Liste

Achten Sie beim Stapeln, dass Sie in der richtigen Reihenfolge tun. Bei Filtern, wenn Sie sortieren oder zuerst gruppieren und dann filtern, tun Sie mehr Arbeit, als Sie zu haben. Jede Ansicht-Ebene ist auch overhead, sollten Sie sicherstellen, dass Sie sie stapeln nur so tief wie erforderlich.

Gruppierung

Neben der Sortierung und Filterung über die verbindliche Listendaten, können Sie auch durch einige Kriterien der Daten gruppieren. Beispielsweise funktionieren würde Erwachsene und Minderjährige gut für unsere Beispieldaten:

// Group by age
window.groupedPeople = people.createGrouped(function (p) { return p.age < 18 ? "minor" : "adult" });

Der Rückgabewert der Gruppierungsfunktion ist ein Zeichenfolgenwert, der die Gruppe eindeutig — in unserem Fall die Zeichenfolge "kleine" oder die Zeichenfolge "Erwachsener". Bindung an die gruppierten Ansicht der Daten zeigt die Daten nach Gruppen geordnet – das heißt, alle Elemente aus jeder Gruppe vor dem Verschieben auf die nächste Gruppe, als Abbildung 17 zeigt.

Grouping a Binding List
Abbildung 17 eine verbindliche Liste Gruppieren

Dieses Beispiel zeigt nur zwei Gruppen, aber Sie können eine beliebige Anzahl von Gruppen haben. Auch, ebenso wie CreateSorted und CreateFiltered, die CreateGrouped-Methode gibt eine Ansicht über live-Daten, so dass Änderungen in der zugrunde liegenden Daten in Bind Destinationen reflektiert werden.

Jedoch zwar es für uns ist klar, die Entwickler, dass wir die Gruppen sortieren, — erste die Erwachsenen und dann die Minderjährigen — es ist nicht klar, Benutzer unseres Programms, denn es keine visuelle Anzeige der Gruppierung gibt. Um das ListView-Steuerelement einen visuelle Gruppierung-Indikator bereit zu stellen, können die ListView Sie zwei Sätze von Daten angeben: die Liste der gruppierten Elemente und der Gruppen selbst. Konfigurieren von ListView mit beide Sätze von Daten sieht wie folgt aus:

    <div data-win-control="WinJS.UI.ListView"
      data-win-options="{itemDataSource: groupedPeople.dataSource,
                         groupDataSource: groupedPeople.groups.dataSource}">
    </div>

Sobald wir die gruppierte Ansicht der Bindungsliste erstellt haben, macht die Gruppen-Eigenschaft eine Liste jener Gruppen, also das ListView-Steuerelement können sie verwenden. Bevor jedoch arbeiten können wir machen, müssen wir auch unsere Verwendung der CreateGrouped-Funktion zurückzukehren:

// Group by age
function groupKeySelector(p) { return p.age < 18 ? "minor" : "adult"; };
function groupDataSelector(p) { return p.age < 18 ? "minor" : "adult"; };
window.groupedPeople = people.createGrouped(groupKeySelector, groupDataSelector);

Wenn wir gruppiert waren, mussten wir vorher nur eine Funktion angeben, die die Gruppierung basiert auf einige einzigartige Gruppenbezeichner tun könnte. Jedoch, wenn wir tatsächlich die Gruppen für den Benutzer angezeigt werden soll, brauchen wir eine andere Methode, die die Gruppen selbst extrahieren können (wenn Sie die Reihenfolge der Gruppen auswählen wollte, Sie könnte bieten eine dritte Methode, die CreateGroup-Methode, die die Sortierung wird). In beiden Fällen bieten wir eine Zeichenfolge zur Darstellung von der Gruppe als auch hinsichtlich um die Liste der Gruppen, zu bauen, die funktioniert ganz gut, wie Sie, in sehen können Abbildung 18.

Grouping a Binding List with ListView Headers
Abbildung 18 Gruppierung eine verbindliche Liste mit ListView-Headern

Als Abbildung 18 zeigt, die Gruppe ist tatsächlich zum ergänzen der gruppierten Daten macht es sehr einfach zu sehen, welche Daten in welcher Gruppe fällt. Leider auch mit dieser visuelle Anzeige der Gruppierung, unsere JSON-formatierte Objekte nicht wirklich die Benutzeroberfläche würde wollen wir unseren Nutzern zeigen. Müssen dazu den Weg wollen wir Vorlagen.

Templates

Eine Vorlage ist eine einzelne verwurzelte Hierarchie von HTML-Elementen mit optionalen "Löcher" dynamische Daten ausfüllen. Das Sieg-binden-Attribut auf das div-Tag definiert die Löcher mit Sieg-binden-Attributen. Können z. B., wir erstellen eine Vorlage für unsere Person Objekte wie folgt:

    <div id="itemTemplate" data-win-control="WinJS.Binding.Template">
      <span data-win-bind="style.color: favoriteColor">
        <span data-win-bind="textContent: name"></span>
        <span> is </span>
        <span data-win-bind="textContent: age"></span>
        <span> years old</span>
      </span>
    </div>

Was macht dieses Stück des HTML Vorlage ist das Daten-gewinnen-Control-Attribut auf den Typ des WinJS.Binding.Template-Steuerelements festgelegt. Nachdem wir unsere Vorlage haben, müssen Sie es in die Löcher mit Daten zu füllen zu rendern:

// Manual template rendering
var person = { name: "Pete", age: 17, favoriteColor: "black" };
var template = itemTemplate.winControl;
template.render(person).done(function (element) { peteDiv.appendChild(element); });

Da die Vorlage nur ein anderes Steuerelement ist (obwohl ein Steuerelement, das sich bis manuell gerendert versteckt), erreichen wir in das div-Tag, die es definiert und Zugriff auf seine Funktionalität über eine bekannte Eigenschaft WinControl namens. Die Funktionalität, die wir zugreifen möchten ist die Vorlage Render-Methode, die nimmt eines Datenkontexts für den Einsatz in binden die Sieg-binden-Attribute und erzeugt eine vollständige HTML-Element für uns zu tun, was wir wollen, mit.

Wenn Sie dem ListView-Steuerelement eine Vorlage bereitstellen, wird es jedes Element in der ListView mit dieser Vorlage gerendert. In der Tat kann das ListView-Steuerelement Vorlagen zum Rendern sowohl die Elemente als auch die Gruppenköpfe haben. Um, die in Aktion zu sehen, lassen Sie uns zuerst aktualisieren die Gruppen auf Objekte, wie es typisch ist:

// Fancy group by age
var groups = [{ key: 1, name: "Minor" }, { key: 2, name: "Adult" }];
function groupDataSelector(p) { 
  return p.age < 18 ? groups[0] : groups[1]; 
};
function groupKeySelector(p) { return groupDataSelector(p).key; };
window.fancyGroupedPeople = 
  people.createGrouped(groupKeySelector, groupDataSelector);

In diesem Code haben wir zwei Gruppenobjekte, jeweils mit einem Schlüssel und einem Namen, und haben wir separate Daten- und Schlüsselauswahlfunktionen, die der Gruppe selbst bzw. Mit unseren Gruppendaten, ein wenig mehr Real-Welt-wie gemacht, eine Vorlage für den Gruppenkopf erstellt, wie in Abbildung 19.

Abbildung 19-Vorlage für den Gruppenkopf

    <div id="headerTemplate" data-win-control="WinJS.Binding.Template">
      <span data-win-bind="textContent: name"></span>
    </div>
    <div id="itemTemplate" data-win-control="WinJS.Binding.Template">
      <span data-win-bind="style.color: favoriteColor">
        <span data-win-bind="textContent: name"></span>
        <span> is </span>
        <span data-win-bind="textContent: age"></span>
        <span> years old</span>
      </span>
    </div>
    <h1>Fancy Grouped</h1>
    <div data-win-control="WinJS.UI.ListView"
      data-win-options="{
        groupDataSource: fancyGroupedPeople.groups.dataSource,
        groupHeaderTemplate: select('#headerTemplate'),
        itemDataSource: fancyGroupedPeople.dataSource,
        itemTemplate: select('#itemTemplate')}">
    </div>

Die Vorlage für den Gruppenkopf wird genau wie eine Elementvorlage erstellt.unction groupKeySelector(item) id="tgt214" runat="server" sentenceId="273d9f598b57548d5332ba2295970ab8" >Die Gruppe Kopf- und Positionsdaten-Vorlagen werden auf das ListView-Steuerelement über die GroupHeaderTemplate und ItemTemplate-Eigenschaft im Daten-gewinnen-Options-Attribut übergeben.unction groupKeySelector(item) id="tgt215" runat="server" sentenceId="692f3c78cebef716e8a2998883a4e1f3" >Unsere Züchter gruppiert Daten sieht aus wie Abbildung 20.

Grouping a Binding List with ListView Headers and Templates
Abbildung 20 Gruppierung eine verbindliche Liste mit ListView Kopf- und Vorlagen

OK, zugegeben das ist nicht sehr extravagant, aber die Kombination von Gruppen und Elemente, einschließlich Vorlagen, zeigt die Macht der Bindungsliste.unction groupKeySelector(item) id="tgt218" runat="server" sentenceId="fc7bdd7636e9ff40b665e4828a1e489e" >In der Tat der Bindungsliste ist so nützlich, es ist der Kern des asynchronen Datenmodells aus von der Projektvorlagen Gittereinsatz und Split-Anwendung generierten Datei data.js ausgesetzt werden, wie in Abbildung 21.

Abbildung 21 die Data.js-Datei von der Gittereinsatz und Split-Anwendung-Projekt generiert

// data.js
(function () {
  "use strict";
  var list = new WinJS.Binding.List();
  var groupedItems = list.createGrouped(
      function groupKeySelector(item) { return item.group.key; },
      function groupDataSelector(item) { return item.group; }
  );
  // TODO: Replace the data with your real data.
  // You can add data from asynchronous sources whenever it becomes available.
  generateSampleData().forEach(function (item) {
    list.push(item);
  });
  WinJS.Namespace.define("Data", {
    items: groupedItems,
    groups: groupedItems.groups,
    getItemsFromGroup: getItemsFromGroup,
    ...
  });
  ...
  // This function returns a WinJS.Binding.List containing only the items
  // that belong to the provided group.
  function getItemsFromGroup(group) {
    return list.createFiltered(function (item) {
    return item.group.key === group.key; });
  }
  ...
  });
})();

Sie können sehen, dass die Erstellung der Liste leere Bindung, die Schaffung einer gruppierten Version dieser Liste mit Funktionen, die Schlüssel zu tun und Datenselektion über die Gruppen, eine wenig ForEach-Schleife, die hinzufügt, dass die Elemente an der Bindungsliste und schließlich ein Hilfsprogramm-Funktion tut filtern.

Schlussbemerkung

Wir begannen diesen Artikel von Graben in binding, die Möglichkeit, ein Attribut auf ein HTML-Element eine Eigenschaft eines Objekts zugeordnet. Out of the Box unterstützt WinJS One-Way, einmalige und benutzerdefinierte Bindung Initialisierungen, aber nicht bidirektionale Bindung. Bindung wird unterstützt, auf einzelne bindbare sowie Listen von Objekten, die die IListDataSource-Schnittstelle implementieren. Der einfachste Ort, um eine Implementierung der IListDataSource-Schnittstelle erfolgt über die Binding-Liste (WinJS.Binding.List)-Objekt, das voll unterstützt, sortieren, Filtern und gruppieren. Wir sahen auch wie nützliche Vorlagen Wenn kombiniert mit Bindung und wie nützlich sind Vorlagen und Bindung sind wenn es darum geht, Steuerelemente, die Listenbindung, z. B. das ListView-Steuerelement zu unterstützen.

Chris Sells ist Vice President der Developer Tools Division bei Telerik. Er ist Mitautor von "Building Windows 8 Apps mit JavaScript" (Addison-Wesley Professional, 2012), aus denen dieser Artikel angepasst wurde. Weitere Informationen zu verkauft und seine verschiedenen Projekte ist abrufbar unter sellsbrothers.com.

Brandon Satrom ist Programmmanager in der Kendo-UI-Division bei Telerik. Er ist Mitautor von "Building Windows 8 Apps mit JavaScript" (Addison-Wesley Professional, 2012), aus denen dieser Artikel angepasst wurde. Sie können ihn auf Twitter zu folgen twitter.com/BrandonSatrom.

Unser Dank gilt den folgenden technischen Experten für die Durchsicht dieses Artikels: Chris Anderson, Jonathan Antoine, Michael Weinhardt, Shawn Wildermuth und Josh Williams