Development

ในตอนที่ผ่านมา เราได้เพิ่มฟีเจอร์หลักคือการอ่านและเขียนไฟล์ รวมถึงพัฒนาแอพลิเคชันให้เข้ากับลักษณะ Lifecycle แบบใหม่แล้ว ในตอนนี้เราจะเพิ่มความสามารถอื่นๆ สำหรับแอพลิเคชันบน Windows 8 เพิ่มเติม คือ การรองรับการแชร์ และการสร้างเมนูปรับตั้งค่า

การแชร์

โดยปกติหากเราต้องการนำข้อมูลจากโปรแกรมหนึ่งไปใช้ในอีกโปรแกรมหนึ่ง เรามักใช้วิธีลากไปปล่อย อย่างไรก็ตามวิธีนี้ไม่เหมาะกับการใช้งานบนอุปกรณ์พกพานัก บนแอพลิเคชันสำหรับ Windows 8 App Store จะให้ผู้ใช้ส่งข้อมูลระหว่างแอพลิเคชันด้วยวิธีการ "แชร์" ได้ โดยการเรียกเมนูแชร์จาก Charm Bar

การแชร์ข้อมูลให้แอพลิเคชันอื่น

การแชร์ข้อมูลให้แอพลิเคชันอื่นนั้น ให้เรารอฟังอีเวนต์ datarequested จาก Windows.ApplicationModel.DataTransfer.DataTransferManager ซึ่งจะถูกส่งออกมาเมื่อผู้ใช้คลิกปุ่ม Share บน Charm Bar เพื่อให้แอพลิเคชันของเราตัดสินใจว่า ขณะนั้นแอพลิเคชันของเรามีข้อมูลอะไรจะให้แชร์หรือไม่ (และข้อมูลนั้นคืออะไร)

เราจะแก้แอพลิเคชันตัวอย่างให้แชร์เนื้อหาทั้งหมดในขณะนั้น หรือเนื้อหาส่วนที่ถูกเลือกถ้าผู้ใช้เลือก (ทำ selection) ไว้ เริ่มต้นจากเพิ่มฟังก์ชัน onDataRequested ในไฟล์ /pages/editor/editor.js ดังนี้

{syntaxhighlighter brush: jscript}var onClickShareButton = function (e) {
var data, title;
if (contentArea.selectionStart != contentArea.selectionEnd) {
// Some text is selected. Share only the selected text.
var startIndex = Math.min(contentArea.selectionStart, contentArea.selectionEnd);
var endIndex = Math.max(contentArea.selectionStart, contentArea.selectionEnd);
title = "Content from selected text";
data = contentArea.innerText.substring(startIndex, endIndex);
}
else {
// No text is selected. Share all text.
title = "Content from current document";
data = contentArea.innerText;
}
var request = e.request;
request.data.properties.title = title;
request.data.properties.description = data;
request.data.setText(data);
};{/syntaxhighlighter}

จากนั้นเพิ่มโค้ดส่วนท้ายของฟังก์ชัน ready ของหน้า editor (ไฟล์ /pages/editor/editor.js) ให้รอฟังอีเวนต์ datarequested ดังนี้ หากมีอีเวนต์เกิดขึ้นให้เรียกฟังก์ชัน onDataRequested ที่สร้างเอาไว้ก่อนหน้านี้ ดังนี้

{syntaxhighlighter brush: jscript}WinJS.UI.Pages.define("/pages/editor/editor.html", {
ready: function (element, options) {
// ...
// Code from previous chapters
// ...
var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
dataTransferManager.addEventListener("datarequested", onDataRequested);
}
});{/syntaxhighlighter}

จากนั้นลองรันแอพลิเคชันและทดลองแชร์

หมายเหตุ: ดูเอกสารคลาส DataPackage เพื่อดูฟังก์ชันที่ใช้แชร์ข้อมูลประเภทอื่นๆ เช่น RTF, HTML, URI, Bitmap, StorageItems

เอกสารและคำแนะนำเพิ่มเติม

  • เอกสารวิธีแชร์: ข้อความ, ลิงก์, HTML, รูปภาพ, ไฟล์
  • หากระหว่างทดสอบแอพลิเคชันพบว่าแชร์ข้อมูลไม่ได้เพราะค้างอยู่ที่หน้า "Getting info from ..." ให้ใช้ Task Manager รีสตาร์ทโปรเซส Windows Explorer ใหม่ อ้างอิง

การเปิดรับข้อมูลที่แชร์จากแอพลิเคชันอื่น

เนื่องจากการเปิดรับข้อมูลที่แชร์ต้องเกิดขึ้นได้แม้ผู้ใช้จะยังไม่ได้เปิดแอพลิเคชันของเรา ดังนั้นส่วนนี้จะเริ่มต้นโดยการสร้าง Share Target Contract ขึ้น เพื่อให้ระบบสามารถรู้ได้ว่าแอพลิเคชันของเรารับข้อมูลอะไรได้บ้าง การสร้าง Contract นี้ยังใช้กับฟีเจอร์อื่นๆ ที่ทำงานในลักษณะเดียวกันนี้ด้วย เช่น Search Contract, File Open Picker Contract เป็นต้น

เราจะเริ่มต้นโดยการสร้างโฟลเดอร์ /pages/shareTarget จากนั้นคลิกขวาที่โฟลเดอร์แล้วเลือกเมนู Add New Item... แล้วเลือกสร้าง Share Target Contract ชื่อ shareTarget.html

จากนั้นเปิดไฟล์ package.appmanifest แล้วไปที่แท็บ Declarations จะพบว่ามี Share Target ระบุไว้ ในหน้านี้เราสามารถระบุได้ว่าจะรับข้อมูลประเภทใดบ้างที่ฟิลด์ Data Format (ซึ่งเราจะแก้ไขให้รับเพียง Text เท่านั้น) และระบุได้ว่าจะให้หน้าใดเป็นหน้ารับข้อมูลที่แชร์มาในส่วน App Settings (ซึ่งหากเราสร้างหน้า Share Contract ด้วยวิธีข้างต้น โปรแกรมจะกำหนดให้เปิดหน้า Share Contract ที่เราสร้างไว้อยู่แล้ว)

หากเราลองเปิดแอพลิเคชันที่แชร์ข้อมูลประเภท Text ได้ (เช่น Internet Explorer ในสถานะที่เลือกข้อความอยู่) จะปรากฎชื่อแอพลิเคชันของเราให้เลือก ซึ่งเมื่อกดเข้าไปจะพบหน้าแชร์ตั้งต้น

เราจะแก้ไขหน้าแชร์ตั้งต้นให้แสดงกล่องข้อความเช่นเดียวกับหน้า editor ดังนี้

HTML (/pages/shareTarget/shareTarget.html)

{syntaxhighlighter brush: xml}

Share Target

Share

{/syntaxhighlighter}

CSS (/pages/shareTarget/shareTarget.css)

{syntaxhighlighter brush: css}section[role=main] {
display: -ms-grid;
width: 100%;
height: 100%;
-ms-grid-columns: 40px 1fr 40px;
-ms-grid-rows: 40px 1fr 20px auto 40px;
}
#contentArea {
box-sizing: border-box;
-ms-grid-column: 2;
-ms-grid-row: 2;
margin: 0;
font-size: x-large;
}
.sharecontrols {
-ms-grid-column: 2;
-ms-grid-row: 4;
-ms-grid-column-align: end;
}{/syntaxhighlighter}

จากนั้นเราจะเขียนโค้ดจาวาสคริปท์ /pages/shareTarget/shareTarget.js เพื่อรับข้อมูลที่ถูกแชร์มา เนื่องจากส่วนรับข้อมูลที่แชร์จากแอพลิเคชันอื่นนี้จะเป็นโปรแกรมที่แยกจากโปรแกรมหลัก ดังนั้นโค้ดในส่วนนี้จึงเขียนเหมือนเป็นอีกแอพลิเคชันหนึ่ง ดังนี้

{syntaxhighlighter brush: jscript}(function () {
"use strict";
var shareOperation;
var contentArea;
WinJS.Application.onactivated = function (args) {
if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.shareTarget) {
contentArea = document.querySelector("#contentArea");
shareOperation = args.detail.shareOperation;
shareOperation.data.getTextAsync().done(function (text) {
contentArea.innerText = text;
});
}
};
WinJS.Application.start();
})();{/syntaxhighlighter}

เมื่อผู้ใช้เลือกแชร์ข้อมูลมายังแอพลิเคชันของเรา แอพลิเคชันจะถูกเรียกขึ้นมาใหม่ (คนละตัวกับโปรแกรมปกติ หากแอพลิเคชันของเราถูกเปิดอยู่แล้ว) โดยจะระบุสาเหตุที่ถูกเรียกเป็น shareTarget เราสามารถนำข้อมูลที่เกี่ยวข้องกับการแชร์ออกมาได้จากวัตถุ args.detail.shareOperation ซึ่งสามารถดูวิธีการใช้งานอย่างละเอียดได้จากหน้าคลาส ShareOperation

เมื่อทดสอบแอพลิเคชันจะพบข้อความที่ถูกแชร์แสดงใน textarea แล้ว

จากนั้นเราจะกำหนดให้เมื่อผู้ใช้กดปุ่ม Share ให้บันทึกเนื้อหาลงใน Local Storage ไว้ก่อน เพื่อให้ผู้ใช้ไปเปิดได้จากแอพลิเคชันของเราในภายหลัง (เนื่องจากเราไม่สามารถเรียก File Picker จากหน้านี้ได้) โดยเพิ่มเติมโค้ด ดังนี้

{syntaxhighlighter brush: jscript}(function () {
"use strict";
var shareOperation;
var contentArea;
var shareButton;
var onClickShareButton = function() {
var localFolder = Windows.Storage.ApplicationData.current.localFolder;
var generateUniqueName = Windows.Storage.CreationCollisionOption.generateUniqueName;
localFolder.createFileAsync("Shared.txt", generateUniqueName)
.then(function (file) {
return Windows.Storage.FileIO.writeTextAsync(file, contentArea.innerText);
})
.done(function () {
shareOperation.reportCompleted();
});
};
WinJS.Application.onactivated = function (args) {
if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.shareTarget) {
contentArea = document.querySelector("#contentArea");
shareButton = document.querySelector("#shareButton");
shareButton.addEventListener("click", onClickShareButton);
shareOperation = args.detail.shareOperation;
shareOperation.data.getTextAsync().done(function (text) {
contentArea.innerText = text;
});
}
};
WinJS.Application.start();
})();{/syntaxhighlighter}

โค้ดที่เพิ่มเติมขึ้นจะสร้างไฟล์ใน Local Storage ซึ่งโดยปกติจะเก็บไว้ที่ C:\Users[UserName]\AppData\Local\Packages[ApplicationID]\LocalState ซึ่งแอพลิเคชันสามารถอ่านและเขียนไฟล์ที่นี่ได้โดยไม่ต้องขอสิทธิ์อนุญาตเพิ่มเติม โดยนำวัตถุ Windows.Storage.ApplicationData.current.localFolder เรียกเมธอด createFileAsync เพื่อขอสร้างไฟล์ตามชื่อที่ต้องการ (ในที่นี้กำหนดตัวเลือกพิเศษ generateUniqueName เพื่อให้ระบบเปลี่ยนชื่อให้ถ้าชื่อซ้ำ) จากนั้นจึงเขียนเนื้อหาลงในไฟล์ที่สร้าง

เมื่อแชร์เสร็จเรียบร้อยแล้ว เราจะต้องเรียกเมธอด shareOperation.reportCompleted() เพื่อปิดหน้าต่างนี้เอง อย่างไรก็ตาม ผู้ใช้จะไม่สามารถเลือกไฟล์ที่เราบันทึกไว้ใน Local Storage ได้ ดังนั้นเราจะเพิ่มเติมหน้าแรกให้แสดงไฟล์เหล่านี้ต่อไป

การสร้าง List View

เราจะสร้างลิสต์แสดงไฟล์ใน Local Storage เพิ่มในหน้าแรกของแอพลิเคชัน เพื่อให้ผู้ใช้เปิดไฟล์ในนั้นมาแก้ไขได้ เริ่มต้นโดยแก้ไขไฟล์ /pages/home/home.js เพื่อให้ปล่อย DataSource ของรายการไฟล์ใน Local Storage ของเราออกมา ดังนี้

{syntaxhighlighter brush: jscript}(function () {
"use strict";
// ...
// Code from previous chapters
// ...
var localFolder = Windows.Storage.ApplicationData.current.localFolder;
var orderByName = Windows.Storage.Search.CommonFileQuery.orderByName;
var queryOption = new Windows.Storage.Search.QueryOptions(orderByName, [".txt"]);
WinJS.Namespace.define("StrifePad", {
files: new WinJS.UI.StorageDataSource(localFolder.createFileQueryWithOptions(queryOption))
});
})();{/syntaxhighlighter}

ในที่นี้ DataSource ประเภท WinJS.UI.StorageDataSource โดยให้เราส่งคิวรีเพื่อหาไฟล์และเรียงลำดับตามคุณสมบัติที่เราต้องการ ซึ่งคิวรีนี้เราสร้างได้โดยเรียกเมธอด createFileQueryWithOptions บนโฟลเดอร์ที่เราต้องการหาไฟล์ในนั้น สามารถส่งพารามิเตอร์เป็นการเรียงลำดับ และนามสกุลที่ต้องการได้ จากนั้นแก้ไขไฟล์ /pages/home/home.html เพื่อเพิ่ม ListView ลงไป ดังนี้ (โค้ดนี้ละส่วน head ที่ไม่ได้มีการแก้ไขใดๆ)

{syntaxhighlighter brush: xml}

...

StrifePad

New

Open

Local Storage

{/syntaxhighlighter}

ส่วนที่เพิ่มขึ้นมาเริ่มจากด้านล่าง เราเพิ่ม header สำหรับลิสต์ และคอมโพเนนต์ ListView โดยกำหนดให้ใช้แหล่งข้อมูลจากตัวแปรโกลบอล StrifePad.localStorageFiles (ซึ่งเราได้เตรียมไว้แล้วก่อนหน้านี้) และกำหนดให้แต่ละชิ้นในลิสต์ใช้เทมเพลตจากอิลิเมนต์ไอดี fileItemTemplate

ส่วนอิลิเมนต์ไอดี fileItemTemplate เป็นคอนโทรลประเภท WinJS.Binding.Template ซึ่งต้องประกาศเอาไว้ก่อน ListView ที่เรียกใช้ โดยเราสามารถกำหนดเนื้อในได้ตามต้องการ เพื่อให้แต่ละชิ้นในลิสต์แสดงผลตามต้องการได้ หากเราต้องการนำข้อมูลของแต่ละวัตถุใน DataSource มาแสดงก็ทำได้โดยใช้ binding จากตัวอย่างเราต้องการนำชื่อไฟล์มาแสดงใน span ซึ่งโดยซอร์สโค้ดภาษาจาวาสคริปต์ปกติเราจะเขียนว่า

{syntaxhighlighter brush: jscript}var span;
var file;
span.innerText = file.displayName;{/syntaxhighlighter}

เราสามารถเขียนใหม่แบบ Binding ใน HTML Template ได้ดังนี้

{syntaxhighlighter brush: xml}{/syntaxhighlighter}

กรณีที่ต้องการ bind หลายๆ อย่างในคอมโพเนนต์เดียวกัน สามารถใช้ semi-colon คั่นระหว่างแต่ละคำสั่งใน win-data-bind ได้ แต่ในกรณีนี้ไม่ใช่การใช้ binding ตามปกติ เพราะวัตถุใน DataSource คือไฟล์ ดังนั้นเราจำเป็นต้องกำหนดออพชันพิเศษ WinJS.Binding.oneTime ด้วย (สำหรับผู้ที่เข้าใจเรื่อง Binding บ้างแล้ว ดูรายละเอียดเพิ่มเติมได้จากคำถามคำตอบบน msdn)

จากนั้นตกแต่งเพิ่มเติมด้วย CSS โดยแก้ไขไฟล์ /pages/home/home.css โดยกำหนดขนาดของกริดใหม่ ให้มีสามคอลัมน์ โดยคอลัมน์แรกเป็นปุ่มสองปุ่มเดิม ส่วนคอลัมน์ที่สามเป็นตัวลิสต์ ซึ่งปรับขนาดตามเนื้อหาของลิสต์ (กำหนดขนาดเป็น auto) ดังนี้

{syntaxhighlighter brush: css}.homepage section[role=main] {
box-sizing: border-box;
padding: 20px 120px;
height: 100%;
display: -ms-grid;
-ms-grid-columns: 250px 40px auto;
-ms-grid-rows: auto 20px 120px 10px 120px 1fr;
overflow-x: scroll;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
#tileButtonGroup {
height: calc(100% - 120px);
}
.tileButton {
background: rgb(71, 169, 80);
border: 1px solid rgb(109, 179, 81);
-ms-transition: -ms-transform ease-out 0.2s;
-ms-transform: scale(1.0, 1.0);
}
.tileButton:active {
-ms-transform: scale(0.978395);
}
.tileButton p {
margin: 5px 12px;
font-weight: 200;
font-size: x-large;
}
#newButton {
-ms-grid-row: 3;
-ms-grid-column: 1;
}
#openButton {
-ms-grid-row: 5;
-ms-grid-column: 1;
}
#localStorageHeader {
-ms-grid-row: 1;
-ms-grid-column: 3;
}
.win-listview {
-ms-grid-row: 3;
-ms-grid-row-span: 4;
-ms-grid-column: 3;
}
#mostRecentFilesListView {
margin: 0;
}
#mostRecentFilesListView .win-listview {
width: 100%;
height: 100%;
margin: 0;
}
#mostRecentFilesListView .win-surface {
margin-right: 40px;
}
#mostRecentFilesListView .win-item {
width: 300px;
height: 70px;
padding: 5px 12px;
overflow: hidden;
background-color: #2b496f;
border: solid 1px #385d8c;
}
#mostRecentFilesListView .win-container:not(.footprint):not(.hover) {
background-color: transparent;
}{/syntaxhighlighter}

หมายเหตุ: เราสามารถดูรายการ class ของ CSS ที่เราสามารถกำหนดรูปแบบได้จากเอกสารคอนโทรล ListView หัวข้อ Remarks/Styling the listview และสามารถดูวิธีการตกแต่งคอนโทรลประเภทอื่นๆ ได้ด้วยวิธีทำนองเดียวกันนี้

การสร้างเมนูปรับตั้งค่า (Settings)

การสร้างเมนูปรับตั้งค่าก็จะใช้วิธีใกล้เคียงกันกับการแชร์ข้อมูลให้แอพลิเคชันอื่น คือให้เรารอฟังอีเวนต์ settings จาก WinJS.Application ซึ่งจะถูกส่งออกมาเมื่อผู้ใช้คลิกปุ่ม Settings บน Charm Bar เพื่อให้แอพลิเคชันของเราสร้างกำหนดว่าจะมีหน้า Settings ย่อยๆ (เรียกว่า Settings Flyout) อะไรบ้าง เพื่อนำไปแสดงรวมกับเมนูตั้งต้น และเมนูปรับตั้งค่าของเครื่องใน Charm Bar อีกทีหนึ่ง

เริ่มต้นจากเพิ่มโค้ดในไฟล์ /js/default.js เพื่อรอฟังอีเวนต์ settings จาก WinJS.Application และเติมเมนู Options เพิ่มเข้าไป ดังนี้

{syntaxhighlighter brush: jscript}(function () {
"use strict";
// ...
// Code from previous chapters.
//
app.onsettings = function (e) {
e.detail.applicationcommands = {
"options": {
title: "Options",
href: "/pages/options/options.html"
}
};
WinJS.UI.SettingsFlyout.populateSettings(e);
};
app.start();
})();{/syntaxhighlighter}

การเพิ่มเมนูปรับตั้งค่านั้น ให้เราเพิ่มเมนูเข้าไปที่ property detail.applicationcommands ของอีเวนต์ที่ได้รับมา โดยกำหนดเป็นวัตถุที่มีชื่อ property เป็น Command ID ของหน้า และค่าเป็นวัตถุระบุชื่อ และที่อยู่ของหน้านั้นๆ ในตัวอย่าง เรากำหนดให้มีเมนูปรับตั้งค่าเมนูเดียว ซึ่งมี Command ID เป็น options มีชื่อว่า Options ซึ่งเมื่อถูกคลิกจะเรียกหน้า /pages/options/options.html ขึ้นมา

เมื่อเสร็จแล้วจึงเรียกฟังก์ชัน WinJS.UI.SettingsFlyout.populateSettings() เพื่อเรียกแถบ Settings ของ Charm Bar ออกมา หากทดสอบตรงนี้ จะมีเมนู Options เพิ่มขึ้นมาแล้ว จากนั้นเราจะเข้าไปแก้ไขหน้า Options โดยเปิดไฟล์ /pages/options/options.html แล้วสร้างเนื้อหาดังนี้

{syntaxhighlighter brush: xml}

Options

Options

{/syntaxhighlighter}

ในหน้านี้เราจะใช้คอมโพเนนท์ SettingsFlyOut โดยจะต้องกำหนด settingsCommandId ให้ตรงกับที่เราตั้งไว้ก่อนหน้านี้ จากนั้นก็สามารถใส่คอมโพเนนท์ต่างๆ ลงไปใน Settings Flyout ได้

สิ่งที่ควรทราบหลักๆ เกี่ยวกับการสร้างเมนูปรับตั้งค่ามีดังนี้

  • ค่าที่ผู้ใช้ปรับควรส่งผลกับแอพลิเคชันทันที หรืออย่างช้าคือทันทีที่ผู้ใช้ออกจากหน้านั้น
  • ควรไว้เฉพาะการปรับตั้งค่าของแอพลิเคชันโดยรวม ไม่นำงานปกติตาม Workflow การใช้งานมาใส่ไว้ในหน้า Settings (ควรใช้ Application Bar แทน โดยดูตัวอย่างได้จากตอนที่ 3 หรือใส่ไว้ในแอพลิเคชันโดยตรง)

ในที่นี้เราให้ผู้ใช้ปรับตั้งค่าได้อย่างเดียว คือ เปิดหรือปิดฟังก์ชันการตรวจสอบตัวสะกด โดยใช้คอมโพเนนท์ ToggleSwitch สำหรับปรับตั้งค่านี้

เมื่อทดสอบดูจะพบหน้าปรับตั้งค่าที่เราสร้างขึ้นแล้ว

สุดท้ายเราจะต้องจดจำและโหลดค่าที่ผู้ใช้ปรับไว้ รวมถึงนำค่าที่ผู้ใช้ปรับนี้ไปใช้งานต่อไป โดยการเขียนโค้ดภาษาจาวาสคริปต์เพิ่มเติม
เริ่มต้นจากเปิดไฟล์ /pages/options/options.js

{syntaxhighlighter brush: jscript}(function () {
"use strict";
var checkSpellingToggleSwitch;
var onCheckSpellingToggleSwitchChange = function (event) {
var appData = Windows.Storage.ApplicationData.current;
appData.localSettings.values["checkSpelling"] = checkSpellingToggleSwitch.winControl.checked;
};
WinJS.UI.Pages.define("/pages/options/options.html", {
ready: function (element, options) {
checkSpellingToggleSwitch = element.querySelector("#checkSpellingToggleSwitch");
checkSpellingToggleSwitch.addEventListener("change", onCheckSpellingToggleSwitchChange);
var appData = Windows.Storage.ApplicationData.current;
checkSpellingToggleSwitch.winControl.checked = appData.localSettings.values["checkSpelling"];
}
});
})();{/syntaxhighlighter}

การเขียนหน้า Settings Flyout โดยรวมก็ไม่ต่างจากการเขียนหน้า Page Control ปกติที่เราเขียนกันมาแล้ว โดยโค้ดในส่วนนี้จะเก็บค่าไว้ใน Local Settings (Windows.Storage.ApplicationData.current.localSettings) ซึ่งสามารถเก็บค่าแบบ Key/Value และเรียกกลับมาใช้ได้อย่างง่ายๆ เหมือนการอ่านและเขียน property จากวัตถุตามปกติ
กรณีที่ต้องการให้ Settings นั้นถูกอัพโหลดเก็บไว้เพื่อให้นำค่ากลับมาใช้เมื่อผู้ใช้คนเดียวกันติดตั้งแอพลิเคชันนี้ที่เครื่องอื่น สามารถย้ายไปเก็บที่ Roaming Settings ได้ โดยใช้วิธีเดียวกันนี้
ดูรายละเอียดเพิ่มเติมเกี่ยวกับการเก็บข้อมูลของแอพลิเคชันได้จากเอกสาร
เมื่อทดสอบตรงนี้เมนูของเราก็จะจำค่าที่ผู้ใช้เลือกไว้แล้ว คราวนี้เราจะนำค่าที่ผู้ใช้เลือกนี้ไปใช้ในแอพลิเคชันกัน เริ่มต้นจากแก้ไขไฟล์ /pages/editor/editor.js ในส่วนเริ่มต้นหน้า เพื่อนำค่านี้ไปกำหนดให้กับตัว textarea ดังนี้

{syntaxhighlighter brush: jscript}WinJS.UI.Pages.define("/pages/editor/editor.html", {
ready: function (element, options) {
pageTitle = element.querySelector("#pageTitle");
contentArea = element.querySelector("#contentArea");
bottomAppBar = element.querySelector("#bottomAppBar");
saveButton = element.querySelector("#saveButton");
var appData = Windows.Storage.ApplicationData.current;
contentArea.spellcheck = appData.localSettings.values["checkSpelling"] || false;
// ...
// Code from previous chapters
// ...
}
});{/syntaxhighlighter}

อย่างไรก็ตาม หน้าปรับตั้งค่านี้ยังไม่สมบูรณ์ เนื่องจากค่าที่ผู้ใช้เลือกยังไม่ถูกนำไปใช้โดยทันที ดังนั้นเราจะต้องปรับปรุงโค้ดของเราอีกเล็กน้อย ในที่นี้เราจะทำอย่างง่าย โดยให้หน้า Options ส่งอีเวนต์ checkSpelling (ซึ่งเรากำหนดเอง) ผ่าน WinJS.Application หากมีการเปลี่ยนแปลงค่านี้ เราจะต้องเพิ่มโค้ดใน /pages/options/options.js ดังนี้ (ส่วนที่เป็นตัวหนาแสดงส่วนที่เพิ่มขึ้นมาจากหัวข้อที่แล้ว)

{syntaxhighlighter brush: jscript}(function () {
"use strict";
var checkSpellingToggleSwitch;
var onCheckSpellingToggleSwitchChange = function (event) {
var appData = Windows.Storage.ApplicationData.current;
appData.localSettings.values["checkSpelling"] = checkSpellingToggleSwitch.winControl.checked;
WinJS.Application.queueEvent({
type: "checkSpellingChange"
});
};
WinJS.UI.Pages.define("/pages/options/options.html", {
ready: function (element, options) {
checkSpellingToggleSwitch = element.querySelector("#checkSpellingToggleSwitch");
checkSpellingToggleSwitch.addEventListener("change", onCheckSpellingToggleSwitchChange);
var appData = Windows.Storage.ApplicationData.current;
checkSpellingToggleSwitch.winControl.checked = appData.localSettings.values["checkSpelling"];
}
});
})();{/syntaxhighlighter}

จากนั้นกลับมาแก้ไขไฟล์ /pages/editor/editor.js เพื่อรอฟังอีเวนต์ดังกล่าวและอัพเดท textarea ดังนี้

{syntaxhighlighter brush: jscript}var onCheckSpellingChange = function (e) {
var appData = Windows.Storage.ApplicationData.current;
contentArea.spellcheck = appData.localSettings.values["checkSpelling"] || false;
};
WinJS.UI.Pages.define("/pages/editor/editor.html", {
ready: function (element, options) {
// ...
// Code from previous chapters
// ...
WinJS.Application.addEventListener("checkSpellingChange", onCheckSpellingChange);
// ...
// Code from previous chapters
// ...
}
});{/syntaxhighlighter}

เอกสารแนะนำเพิ่มเติม

หมายเหตุ: ไม่ควรบันทึก password หรือข้อมูลที่อาจกระทบต่อความปลอดภัยของบัญชีผู้ใช้ไว้ใน local storage โดยแนะนำให้ใช้ PasswordVault แทน

สารบัญบทความ

บทความชุด การเขียนแอพลิเคชันสำหรับ Windows 8 App Store

Hiring! บริษัทที่น่าสนใจ

Carmen Software company cover
Carmen Software
Hotel Financial Solutions
Next Innovation (Thailand) Co., Ltd. company cover
Next Innovation (Thailand) Co., Ltd.
We are web design with consulting & engineering services driven the future stronger and flexibility.
KKP Dime company cover
KKP Dime
KKP Dime บริษัทในเครือเกียรตินาคินภัทร
Kiatnakin Phatra Financial Group company cover
Kiatnakin Phatra Financial Group
Financial Service
Fastwork Technologies company cover
Fastwork Technologies
Fastwork.co เว็บไซต์ที่รวบรวม ฟรีแลนซ์ มืออาชีพจากหลากหลายสายงานไว้ในที่เดียวกัน
Thoughtworks Thailand company cover
Thoughtworks Thailand
Thoughtworks เป็นบริษัทที่ปรึกษาด้านเทคโนโยลีระดับโลกที่คว้า Great Place to Work 3 ปีซ้อน
Iron Software company cover
Iron Software
Iron Software is an American company providing a suite of .NET libraries by engineer for engineers.
CLEVERSE company cover
CLEVERSE
Cleverse is a Venture Builder. Our team builds several tech companies.
Nipa Cloud company cover
Nipa Cloud
#1 OpenStack cloud provider in Thailand with our own data center and software platform.
Bangmod Enterprise company cover
Bangmod Enterprise
The leader in Cloud Server and Hosting in Thailand.
CIMB THAI Bank company cover
CIMB THAI Bank
MOVING FORWARD WITH YOU - CIMB is the leading ASEAN Bank
Bangkok Bank company cover
Bangkok Bank
Bangkok Bank is one of Southeast Asia's largest regional banks, a market leader in business banking
MuvMi (Urban Mobility Tech Co.,Ltd.) company cover
MuvMi (Urban Mobility Tech Co.,Ltd.)
Shape the future of urban mobility towards affordable, clean, and safe solutions
T.N. Digital Solution Co., Ltd. company cover
T.N. Digital Solution Co., Ltd.
TNDS has been involving in every first move of banking’s major digital transformation.
KBTG - KASIKORN Business-Technology Group company cover
KBTG - KASIKORN Business-Technology Group
KBTG - "The Technology Company for Digital Business Innovation"
Siam Commercial Bank Public Company Limited company cover
Siam Commercial Bank Public Company Limited
"Let's start a brighter career future together"
Icon Framework co.,Ltd. company cover
Icon Framework co.,Ltd.
Global Standard Platform for Real Estate แพลตฟอร์มสำหรับธุรกิจอสังหาริมทรัพย์ครบวงจร มาตรฐานระดับโลก
REFINITIV company cover
REFINITIV
The Financial and Risk business of Thomson Reuters is now Refinitiv
H LAB company cover
H LAB
Re-engineering healthcare systems through intelligent platforms and system design.
The Gang Technology Co., Ltd. company cover
The Gang Technology Co., Ltd.
We're a Digital Agency that helps our customers transform their business into digital with ease.
LTMH company cover
LTMH
LTMH มุ่งเน้นการพัฒนาผลิตภัณฑ์ที่สามารถช่วยพันธมิตรของเราให้บรรลุเป้าหมาย
Seven Peaks company cover
Seven Peaks
We Drive Digital Transformation
Wisesight (Thailand) Co., Ltd. company cover
Wisesight (Thailand) Co., Ltd.
The Best Choice For Handling Social Media · High Expertise in Social Data · Most Advanced and Secure
MOLOG Tech company cover
MOLOG Tech
We are Modern Logistic Platform, Specialize in WMS, OMS and TMS.
Data Wow Co.,Ltd company cover
Data Wow Co.,Ltd
We enable our clients to realize increased productivity by solving their most complex issues by Data
LINE Company Thailand company cover
LINE Company Thailand
LINE, the world's hottest mobile messaging platform, offers free text and voice messaging + Call
LINE MAN Wongnai company cover
LINE MAN Wongnai
Join our journey to becoming No.1 food platform in Thailand

ทำ ui design บน ios มาดูบน win8 แล้วมันจะ clean เกินไปปะเนีย
ท่านใดพอจะแนะนำ Apps ของ win8 ที่ Design เด็จๆหน่อยซิครับหา inspiration