Persistente Datenspeicherung für Windows 8 Apps in HTML5/Javascript

Von Christian Vorhemus Autor Feed 1. May 2013 11:58
In diesem Tutorial soll gezeigt werden, wie Daten in einer Windows 8 App mittels IndexedDB gespeichert und wieder ausgelesen werden können. Als Beispiel dient dazu eine einfache Benutzerverwaltungs-App, mit der Benutzer angelegt und wieder gelöscht werden. Ein kurzer Überblick über IndexedDB Im Zuge der immer vielfältigeren Möglichkeiten, die mit klassischen Webapplikationen geschaffen werden können, wurden auch Stimmen nach effizienten clientseitige Speichermöglichkeiten laut. Bis dato war die persistente Datenspeicherung hier so gut wie gar nicht möglich: Lediglich Cookies erlaubten das Schreiben und Lesen von Parametern. Diese waren aber allein schon aufgrund der geringen erlaubten Speichergröße maximal für einige zu speichernden Einstellungen auf Webseiten zu gebrauchen. Mozilla wagte hier einen Vorstoß und führte als eine der Ersten für ihren Browser eine Index-basierte Datenbank ein. Schließlich wurde die Spezifikation für eine solche Datenbank vor gut einem Jahr vom W3-Konsortium verabschiedet und ist offiziell Bestandteil von HTML5. Verwendet werden kann IndexedDB nicht nur mit Browsern wie Internet Explorer 10, Chrome oder Firefox sondern dank der weitreichenden HTML5-Unterstützung auch mit Windows 8! Schritt 1: Projekt öffnen und vorbereiten Zunächst öffnen wir in Visual Studio 2012 ein neues Projekt und wählen den Unterpunkt JavaScript > Windows Store > Navigations-App aus. (Hinweis: Wer neu in der Welt der HTML5/Javascript-Apps ist, mag sich als Einstieg vielleicht zuvor dieses Tutorial ansehen) Ist das Projekt angelegt, navigieren wir in den Ordner pages/home und öffnen home.html. Dort ändern wir zunächst den style von ui-dark.css auf ui-light.css, schreiben im span-tag der Klasse “pagetitle” “Benutzerverwaltung” statt “Willkommen bei DBSample” und löschen die Zeile “Hier Inhalt einfügen” zwischen den <p></p>-Tags. Als nächstes fügen wir die AppBar hinzu, die sich bei einem Rechtsklick in die App bzw. auf Touch-Devices von einer Wischbewegung vom unteren Rand nach oben öffnet. Dazu kopieren wir folgenden Code und fügen ihn in die home.html-Datei knapp über dem </body>-Tag ein: <div id="appbar" data-win-control="WinJS.UI.AppBar"> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'removeUser', label:'Löschen', icon:'delete'}" type="button"></button> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'addUser', label:'Neu', icon:'add'}" type="button"></button> </div> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Wenn wir nun auf F5 klicken um die App zu starten und danach mit dem rechten Maustaste in die App klicken, sollte sich die noch funktionslose AppBar öffnen. Um die AppBar zu stylen, können wir uns übrigens der .win-appbar-property bedienen. Um den AppBar-Hintergrund grau zu färben, kopiere man nachfolgenden Code in die home.css-Datei: .win-appbar { background-color: #CCCCCC; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Im nächsten Schritt legen wir ein Fenster an, das sich öffnet, wenn der User auf den “Neu”-Button in der AppBar klickt. Dazu schreiben wir ein <div>, in dem sich Text-inputs sowie Buttons befinden. Diesen Code fügen wir gleich nach dem <body>-Tag in home.html hinzu: <div id="addDiv"> <h2>Neuen Benutzer hinzufügen</h2><p></p> <table> <tr><td>Name:</td><td><input type="text" id="username" /></td></tr> <tr><td>Alter:</td><td><input type="number" id="age"/></td></tr> <tr><td>Typ:</td><td><select id="type"><option>User</option><option>Administrator</option> </select></td></tr> </table> <p></p> <input type="button" id="addEntry" value="Eintragen"/> <input type="button" id="close" value="Schließen"/> </div> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Um das <div> mittig auszurichten, kopiere man folgenden Code in die home.css-Datei: #addDiv { color:black; display:none; height:250px; position: absolute; width:530px; z-index: 50; border: 5px solid grey; top: 50%; left: 50%; margin-top: -125px; margin-left: -287px; background-color:white; font-size:20px; padding-top:20px; padding-left:20px; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Das div wird zunächst nicht angezeigt (display:none;), kümmern wie uns nun um den Öffnen/Schließen-Mechanismus. Dazu öffnen wir die home.js-Datei. In Zeile 7 sehen wir den Eintrag “ready: function (element, options)”. In dieser Funktion wird die Seite initialisiert, hier werden wir auch unsere EventListener anlegen, damit bei Klicks auf die Buttons der AppBar das Fenster geöffnet wird. In dieser Funktion legen wir die folgenden drei EventListener an: document.getElementById("addEntry").addEventListener("click", addEntry); document.getElementById("close").addEventListener("click", closeWindow); document.getElementById("addUser").addEventListener("click", openWindow); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Wird auf den Button mit der ID “addEntry” geklickt, wird die Funktion addEntry ausgeführt; Äquivalentes gilt für die anderen zwei Listener. Legen wir nun die openWindow() und closeWindow() Funktionen an. Wir kopieren den nachfolgenden Code und fügen ihn kurz nach der WinJS.UI.Pages.define-Funktion ein. function openWindow() { document.getElementById("appbar").winControl.hide(); var elm = document.getElementById("addDiv"); elm.style.display = "block"; WinJS.UI.Animation.fadeIn(elm); }   function closeWindow() { var elm = document.getElementById("addDiv"); elm.style.display = "none"; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Unsere home.js Datei sollte bis jetzt wie folgt aussehen:   Detail am Rande: In der openWindow-Funktion bedienen wir uns der von WinJS bereitgestellten fadeIn-Funktion um einen Fade-Effekt zu erzeugen. Eine Fade-Out-Animation gibt es auch – fadeOut heißt hier das Pendant. Wenn wir nun auf den “Neu”-Button in unserer AppBar klicken, wird unser div geöffnet, die sich zentriert in der Bildschirmmitte befindet: Schritt 2: Datenbank anlegen Mit IndexedDB werden Objekte in Form eines key-value-pairs gespeichert, am häufigsten wird zu diesem Zweck die JSON- Notation verwendet. Würden wir mit einer relationalen Datenbank arbeiten, müssten wir für unsere Benutzerverwaltung zunächst die Datenbank erstellen. Das könnte für relationale Datenbanken in MySQL etwa so aussehen: CREATE DATABASE userDatabase; In unserer IndexedDB legen wir eine Datenbank wie folgt an: var request = window.indexedDB.open("userDatabase ", 1); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Der erste Parameter ist der Datenbankname, der zweite gibt die Versionsnummer an (immer wenn sich das Datenbankschema ändert, muss sich auch die Versionsnummer ändern). Die open()-Funktion selbst retourniert ein Request-Objekt, das mehrere Zustände beschreiben kann: Success, Error, Blocked und UpgradeNeeded wobei letzterer Zustand immer dann aufgerufen wird, wenn sich die Versionsnummer ändert. Um die Datenbank anlegen bzw öffnen zu können, fügen wir folgende Funktion kurz oberhalb von openWindow in home.js ein: var db = null; function openDatabase() { var dbRequest = window.indexedDB.open("userDatabase", 1); dbRequest.onerror = function () { console.log("Fehler beim Erstellen der Datenbank"); }; dbRequest.onblocked = function () { console.log("Datenbank blockiert"); };   dbRequest.onsuccess = function (evt) { db = evt.target.result; showEntries(); };   dbRequest.onupgradeneeded = function (evt) { if (db) { db.close(); } db = evt.target.result; var txn = evt.target.transaction; var bookStore = db.createObjectStore("userlist", { keyPath: "id", autoIncrement: true }); bookStore.createIndex("username", "username", { unique: false });   txn.oncomplete = function () { }; }; }   function showEntries() {   } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Die openDatabse()-Funktion soll bei der Initialisierung der Seite aufgerufen werden, wir fügen daher den Eintrag openDatabase(); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } kurz unterhalb des EventListeners document.getElementById("addUser").addEventListener("click", openWindow); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } hinzu. In relationalen Datenbanken würden wir im nächsten Schritt das Datenbankschema in SQL anlegen, was (in MySQL) etwa so aussehen könnte: CREATE TABLE user (   id INT PRIMARY KEY,   username VARCHAR(40) ,   age INT,   type ENUM(‘Administrator’, ‘User’) ); Mit diesem Code legen wir also eine Tabelle an, in die wir nun Daten ablegen können. Mit IndexedDB kreieren wir im Unterschied dazu Objekt-Storages. Das ist nichts anderes als ein Speicherplatz mit einem zugewiesenen Namen, in den Objekte (als key-value-pair) abgelegt werden können. Ein “richtiges” Schema für Tabellen wie bei relationalen Datenbanken gibt es hierbei nicht. Der entsprechende Code um ein solches Objekt-Storage für die Benutzerverwaltung anzulegen, könnte in etwa wie folgt aussehen: db.createObjectStore("users",{keyPath: "id"}); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } keypath gibt hierbei jenen value an, mit der der Datensatz eindeutig identifiziert werden kann. Unsere Datenbank steht nun bereit um Daten aufzunehmen, fügen wir nun eine Funktion addEntry() hinzu. Diese können wir oberhalb von openDatabase einfügen: var user = new WinJS.Binding.List(); WinJS.Namespace.define("UserList", { user: user });   function addEntry() {   var username = document.getElementById("username").value var age = document.getElementById("age").value var type = document.getElementById("type").value var id = 0;   if (user.length != 0) { user.dataSource.itemFromIndex(user.length - 1).done(function (item) { id = item.data.id + 1; }); }   var item = { "id": id, "username": username, "age": age, "type": type, "picture": "/images/user.png" };   var transaction = db.transaction("userlist", "readwrite"); var addRequest = transaction.objectStore("userlist").add(item); addRequest.onsuccess = function (evt) { user.push(item); } closeWindow(); }   .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Um Daten löschen zu können, legen wir nun in der home.js-Datei einen weiteren EventListener in der ready-Funktion an: document.getElementById("removeUser").addEventListener("click", deleteEntry); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } … die zugehörige deleteEntry()-Funktion sieht so aus, diese kopieren wir unter die addEntry-Funktion: function deleteEntry() { var listView = document.getElementById("itemsListView").winControl;   listView.selection.getItems().done(function (currentSelection) { currentSelection.forEach(function (selectedItem) {   var dbKey = selectedItem.data.id; var listViewKey = selectedItem.key; var transaction = db.transaction("userlist", "readwrite"); var deleteRequest = transaction.objectStore("userlist").delete(dbKey);   deleteRequest.onsuccess = function () { user.dataSource.remove(listViewKey); } deleteRequest.onerror = function () { } }); }); document.getElementById("appbar").winControl.hide(); } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Schritt 3: ListView erstellen Im letzten Schritt haben wir unter anderem die Zeile var user = new WinJS.Binding.List(); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } hinzugefügt. Diese so definierte Liste “user” verwenden wir, um darin alle Benutzer zu speichern, die wir aus der Datenbank auslesen um diese schließlich zu unserer ListView hinzuzufügen. Die ListView selbst ist nichts anderes als eine von WinJS zur Verfügung gestellte control um eine Ansammlung an Items im Sinne des "Modern UI” anzuzeigen. Um unsere Liste “user” beim Initialisieren zunächst mit den Daten aus der Datenbank zu füllen, ersetzen wir die leere showEntries()-Funktion, die sich bereits in unserer home.js-Datei befindet, mit folgendem Code: function showEntries() { if (db) { var request = []; var transaction = db.transaction("userlist", "readonly"); var store = transaction.objectStore("userlist");   var index = store.index("username"); index.openCursor().onsuccess = function (event) { var cursor = event.target.result; if (cursor) { user.dataSource.insertAtEnd(null, cursor.value); cursor.continue(); } }; } }   Nun müssen wir unsere Liste “user” allerdings auch anzeigen. Zu diesem Zweck fügen wir den folgenden Code in unsere home.html-Datei kurz nach “<section aria-label="Main content" role="main">” hinzu: <div id="mediumListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none"> <div class="mediumListIconTextItem"> <img src="#" class="mediumListIconTextItem-Image" data-win-bind="src: picture" /> <div class="mediumListIconTextItem-Detail"> <b>Username:</b> <span data-win-bind="innerText: username"></span><br /> <b>Alter:</b> <span data-win-bind="innerText: age"></span><br /> <b>Accounttyp:</b> <span data-win-bind="innerText: type"></span> </div> </div> </div> <div id="itemsListView" data-win-control="WinJS.UI.ListView" data-win-options="{itemDataSource : UserList.user.dataSource, itemTemplate: select('#mediumListIconTextTemplate')}"> </div> Hier wird die ListView angelegt und mit einem entsprechenden Template versehen, sodass unsere Daten formatiert ausgegeben werden. Wenn wir die App testen, auf “Neu” klicken und einen Benutzer anlegen, können wir schon Einträge speichern, allerdings sieht der Eintrag noch etwas unfömig aus. Um das zu ändern, fügen wir zunächst folgendes Bild in den /image-Folder hinzu: Außerdem fügen wir folgenden Code in unsere home.css ein: #itemsListView { height: calc(100% - 80px); width:calc(100% - 90px); border: 0px solid red; }   #itemsListView .win-container:not(.footprint):not(.hover) { background-color: transparent; color:black; border: 1px solid gray; }   .mediumListIconTextItem { width: 282px; height: 70px; padding: 5px; overflow: hidden; display: -ms-grid; }   .mediumListIconTextItem img.mediumListIconTextItem-Image { width: 60px; height: 60px; margin: 5px; -ms-grid-column: 1; }   .mediumListIconTextItem .mediumListIconTextItem-Detail { margin: 5px; -ms-grid-column: 2; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Mit diesem Schritt sind wir bereits fertig: Wir können nun Benutzer hinzufügen indem wir in der AppBar auf “Neu” klicken. Wenn wir Benutzer löschen wollen, klicken wir mit der rechten Maustaste auf die jeweiligen Einträge um sie auszuwählen und dann nochmals mit der rechten Maustaste um auf den “Löschen”-Button klicken zu können. Ein nettes Feature wäre noch, wenn sich bei einer Auswahl an Einträgen die AppBar automatisch öffnet, diese Funktion fügen wir im finalen Schritt 4 noch hinzu. Schritt 4: Öffnen der AppBar durch selectionchanged-Events Zunächst fügen wir wieder einen EventListener in der ready-Funktion in home.js ein: document.getElementById("itemsListView").winControl.addEventListener("selectionchanged", changedSelection); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Danach fügen wir die nachfolgende changedSelection-Funktion zB unterhalb von deleteEntry hinzu: function changedSelection(eventObject) { document.getElementById("appbar").winControl.show(); } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } In Worten gesprochen passiert hier folgendes: Immer dann, wenn sich die aktuelle Auswahl (Rechtsklick) der itemsListView ändert, öffnet sich die AppBar. Den Quellcode dieses Projekts gibt es auf http://www.wissen-kompakt.at/codefest/DBSample.zip zum Download! Los gehts! Dieses Tutorial ist nur ein Einstiegspunkt für weitere eigene Entwicklungen. Die Möglichkeiten, diese App zu erweitern sind unbegrenzt und reichen zB von einem FilePicker, um statt dem User-Platzhalter-Icon Fotos von Benutzern zu speichern, bis hin zu automatischer Datensynchronisation, um auf allen Geräten stets den gleichen Datenstand zu haben. Nur empfehlen kann man abschließend die umfangreichen Dokumentationen und Codebeispiele auf msdn.microsoft.com, die einen tieferen Einblick in die Materie bieten.

Entwickler Wettbewerbe:

Wettbewerbe

Entwickler Events:

Developer Events

App für Windows 8, Windows Phone oder/und Azure? Diese Events zeigen Dir, wie es geht:

Mehr Information

Aktuelle Downloads

Visual Studio Downloads
 
Windows Azure Free Trial
Instagram
CodeFest.at on Facebook

Datenschutz & Cookies · Nutzungsbedingungen · Impressum · Markenzeichen
© 2013 Microsoft. Alle Rechte vorbehalten · BlogEngine.NET 2.7.0.0 · Diese Website wird für Microsoft von atwork gehostet.
powered by atwork