Вы зашли как: Гость
Опрос
Верите ли вы в скорый выход Surface Phone?

Начала Metro-программирования: простейшее приложение в стиле Metro (ч.2)

Напечатать страницу
16.05.2012 14:12 | dronov_va

Продолжаем рассказ о началах Metro-программирования и разработке первого, самого простого Metro-приложения.


4. Открытие файла
Как мы уже знаем, интерфейс Metro-приложения описывается в файле default.html, хранящемся непосредственно в папке проекта. Переключимся на него, щёлкнув на соответствующей ему вкладке, что находится на панели вкладок (см. рис. 4).

Если же такой вкладки там нет (а, скорее всего, так и будет), нам потребуется открыть данный файл. Проще всего сделать это, воспользовавшись панелью Solution Explorer. Найдём в ней пункт, представляющий нужный нам файл, и дважды щёлкнем на нем. Кстати, двойным щелчком на папке мы можем открыть её содержимое.

Visual Studio выведет содержимое открытого нами файла в новом окне документа и тотчас сделает его активным.


5. Создание интерфейса приложения
Вот теперь можно приниматься за интерфейс нашего первого приложения.

Язык HTML здесь описываться не будет. В Интернете можно найти большое количество вполне толковых руководств и справочников по этому языку, к тому же, отличный справочник можно найти в разделе веб-сайта MSDN, посвящённом Metro-программированию. К тому же, думается, многие читатели знают HTML достаточно хорошо, чтобы разобраться в приведённом далее коде.

5.1. Содержимое изначального файла default.html
Но сначала давайте посмотрим на содержимое файла default.html, который был создан Visual Studio в процессе формирования проекта. Оно может рассказать нам довольно много о самой платформе Metro и о том, как пишутся Metro-приложения.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Calc</title>

  <!-- WinJS references -->
  <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
  <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
  <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>

  <!-- Calc references -->
  <link href="/css/default.css" rel="stylesheet">
  <script src="/js/default.js"></script>
</head>
<body>
  <p>Content goes here</p>
</body>
</html>


Прежде всего, обратим внимание на служебный тег <!DOCTYPE html>, поставленный в самом начале кода. Он указывает, что для описания интерфейса используется новая версия языка HTML - HTML5. В Microsoft рассудили здраво - если уж писать для новейшей программной платформы, то использовать для этого новейшие технологии.

Далее мы видим служебный тег <meta charset="utf-8">. Он указывает, что содержимое файла default.html хранится в кодировке UTF-8. Забегая вперёд, скажем, что содержимое всех остальных файлов, составляющих приложение, также записано в этой кодировке.

Тег <title>, задающий название веб-страницы, в данном случае не нужен, поскольку задаваемое им название всё равно нигде не выводится. Однако он требуется для полного соответствия стандартам HTML5, поэтому и присутствует в коде.

Первый из тегов <link>, встречающийся в коде, выполняет привязку таблицы стилей ui-dark.css, задающей базовое оформление различных элементов интерфейса. Эта таблица стилей не включается в состав проекта, а является одной из составных частей платформы Metro.

Таблица стилей ui-dark.css задаёт "тёмную" тему оформления для Metro-приложения. Существует также таблица стилей ui-light.css, задающая "светлую" тему.

На заметку
Путь к файлу таблицы стилей, проставленный в теге <link>, весьма примечателен. Из него можно выяснить, что платформа Metro, актуальная на момент написания этой статьи, имеет номер версии 0.6.

Далее находятся два тега <script>, выполняющих привязку файлов логики base.js и ui.js. Эти файлы содержат базовую логику, обеспечивающую само функционирование Metro-приложения, и также входят в состав платформы Metro.

На заметку
Копии файлов таблиц стилей, описывающих базовое оформление, и файлов с базовой логикой можно отыскать в папке C:\Program Files\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\Microsoft.WinJS\<номер версии платформы Metro>\DesignTime\Debug\Neutral\Microsoft.WinJS<номер версии платформы Metro>. Вложенная в неё папка css содержит файлы с базовым оформлением, а папка js - файлы с базовой логикой.

Второй по счёту тег <link> и третий по счёту тег <script> привязывают, соответственно, таблицу стилей и файл логики, чьё содердимое задаётся самими разработчиками. Это уже знакомые нам файлы default.css и default.js.

Собственно код, описывающий интерфейс, как и в случае обычных веб-страниц, помещается внутрь парного тега <body>. Уже присутствующий там код <p>Content goes here</p> просто формирует соответствующее указание для разработчика и перед вставкой реального кода должен быть удалён.

5.2. Написание кода интерфейса
Больше ничего интересного для нас в изначальном содержимом файла default.html нет. Так что не будем тянуть волынку и вставим в парный тег <body> вот такой код:

<input type="text" id="txtOutput" value="0" readonly />
<input type="button" id="btnC" value="C" />
<input type="button" id="btnCE" value="CE" />
<input type="button" id="btn1" value="1" />
<input type="button" id="btn2" value="2" />
<input type="button" id="btn3" value="3" />
<input type="button" id="btn4" value="4" />
<input type="button" id="btn5" value="5" />
<input type="button" id="btn6" value="6" />
<input type="button" id="btn7" value="7" />
<input type="button" id="btn8" value="8" />
<input type="button" id="btn9" value="9" />
<input type="button" id="btn0" value="0" />
<input type="button" id="btnDot" value="." />
<input type="button" id="btnPlus" value="+" />
<input type="button" id="btnMinus" value="-" />
<input type="button" id="btnMult" value="*" />
<input type="button" id="btnDiv" value="/" />
<input type="button" id="btnEqual" value="=" />


Он создаёт доступное только для чтения поле ввода и набор кнопок, характерных для обычного арифметического калькулятора.

Тег <input> формирует большинство элементов управления, поддерживаемых языком HTML. Для указания, какой именно элемент управления следует создать, применяется атрибут тега type. Атрибут тега id позволяет указать уникальное имя элемента интерфейса, по которому на данный элемент можно будет сослаться из кода логики.

Для формирования поля ввода мы зададим в качестве значения атрибута type тега <input> строку text. Атрибут тега value в этом случае укажет значение, которое должно быть подставлено в поле ввода изначально, в нашем случае - строку 0. А атрибут без значения readonly, присутствующий в теге, сделает это поле ввода доступным только для чтения.

Для формирования обычной кнопки в качестве значения атрибута type тега <input> указывается строка button. Атрибут тега value в случае кнопки задаст для неё надпись.

Поскольку любой элемент управления HTML представляет собой встроенный элемент интерфейса, ведущий себя как символ в текстовом абзаце, созданные нами поле ввода и кнопки выстроятся в линию по горизонтали. Если для их отображения не хватит места по шиирне экрана, данная линия будет разорвана на две или более, как разрываются строки обычного текста.

Пока что интерфейс нашего первого приложения будет таким. Расстановкой элементов интерфейса на экране с применением разметки мы займёмся потом.


6. Сохранение файлов
Теперь следует сохранить исправленный файл. Это необходимо проделывать всякий раз перед запуском приложения.

Сохранить содержимое файла, открытого в активном окне документа, проще простого — достаточно нажать комбинацию клавиш <Ctrl>+<S>. Также можно нажать расположенную на панели инструментов кнопку Save <имя файла, открытого в активном окне документа> или выбрать одноимённый пункт меню File.

В дальнейшем, разрабатывая более сложные приложения, мы будем активно работать сразу с несколькими файлами. Чтобы сохранить содержимое сразу всех исправленных файлов, следует нажать комбинацию клавиш <Ctrl>+<Shift>+<S>. Если же мы не хотим отрывать руки от мыши и тянуться к клавиатуре, то можем нажать расположенную на панели инструментов кнопку Save All или выбрать пункт Save All меню File.


7. Запуск Metro-приложения
Настала пора запустить наше первое Metro-приложение. Да, мы создали только его интерфейс и даже не приступали к работе над логикой, но, по крайней мере, посмотрим, правильно ли оно выводится на экран.

Проще всего запустить приложение, нажав клавишу <F5>. Ещё можно выбрать пункт Start Debugging меню Debug или нажать расположенную на панели инструментов кнопку Local Machine.

В процессе запуска приложения Visual Studio выполнит следующие действия:

  • Сформирует на основе проекта дистрибутивный пакет, содержащий отладочную редакцию приложения.
  • Выполнит установку приложения из этого пакета и создаст для него плитку в меню Start.
  • Собственно, запустит это приложение.


Как только приложение будет запущено, на экране появится заставка — графическое изображение, выводимое в процессе запуска Metro-приложения. На рис. 5 можно видеть заставку по умолчанию, которую Visual Studio самостоятельно добавляет в каждое вновь созданное приложение; она представляет собой схематичное изображение часов на синем фоне.


Рис. 5. Заставка Metro-приложения по умолчанию


Когда приложение запустится и инициализируется, на экране появится его интерфейс - см. рис. 6.


Рис. 6. Интерфейс нашего первого Metro-приложения


Ура! Наше первое Metro-приложение запускается и выполняется! Правда, пока что ничего полезного оно не делает... Но мы это очень скоро исправим!


8. Завершение выполнения Metro-приложения
Чтобы запущенное Metro-приложение не расходовало попусту системные ресурсы, перед масштабными правками его желательно завершить. Для этого достаточно нажать комбинацию клавиш <Shift>+<F5>. Уж простите автора — он привык к клавиатуре... Также можно нажать кнопку Stop Debugging в панели инструментов или выбрать пункт Stop Debugging меню Debug.


9. Создание логики приложения
Приступим к написанию кода программной логики, которая вдохнёт в наше приложение "жизнь". Этот код будет храниться в файле default.js, храняшемся в папке js. Переключимся на этот файл или, если он ещё не открыт, откроем его.

Опять же, описание языка JavaScript здесь приводиться не будет. Руководства и справочники по нему можно без труда найти в Интернете, в частности, в разделе веб-сайта MSDN, посвящённом Metro-программированию.

9.1. Содержимое изначального файла default.js
И первое, что мы сделаем, - рассмотрим код, что уже присутствует в файле логики default.js, созданном Visual Studio. Это позволит нам понять некоторые принципы, по которым пишется и выполняется программная логика всех Metro-приложений.

(function () {
  "use strict";

  var app = WinJS.Application;

  app.onactivated = function (eventObject) {
    if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
      if (eventObject.detail.previousExecutionState !==
      Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
        // TODO: This application has been newly launched. Initialize
        // your application here.
      } else {
        // TODO: This application has been reactivated from suspension.
        // Restore application state here.
      }
        WinJS.UI.processAll();
      }
  };

  app.oncheckpoint = function (eventObject) {
    // TODO: This application is about to be suspended. Save any state
    // that needs to persist across suspensions here. You might use the
    // WinJS.Application.sessionState object, which is automatically
    // saved and restored across suspension. If you need to complete an
    // asynchronous operation before your application is suspended, call
    // eventObject.setPromise().
  };

  app.start();
})();


Мы видим, что весь код логики помещён в тело анонимной функции, которая объявляется и сразу же после объявления выполняется.

(function () {
  . . .
})();


В результате все переменные и функции, что объявлены в теле этой функции, будут принадлежать ей, или, говоря в терминологии JavaScript, станут локальными. Если же пользоваться терминологией Metro-программирования, они станут частями анонимного пространства имён. "Извне" эти переменные и функции доступны не будут.

Зачем так сделано? Давайте разберёмся.

Предположим, мы разрабатываем сложное приложение, отдельные части интерфейса которого реализованы в виде фрагментов - независимых частей, описание каждой из которых хранится в отдельном HTML-файле, а её логика - в отдельном файле логики. Если бы мы не использовали анонимные пространства имён, как было показано ранее, все объявленные там переменные и функции стали бы частью глобального пространства имён JavaScript. А это может повлечь конфликт имён, когда разные переменные, объявленные в разных частях логики, имеют одно и то же имя. В результате разные части кода фактически будут обращаться к одной и той же переменной, что вызовет ошибку в работе приложения.

Но, поскольку мы используем анонимные пространства имён (а сам Visual Studio подталкивает нас к этому), эти переменные, даже если они и "тёзки", окажутся в разных пространствах имён и, следовательно, останутся разными переменными. Если же нам потребуется передавать данные из одного фрагмента в другой, мы воспользуемся именованными пространствами имён, благо платформа Metro припасла нам удобные инструменты для работы с ними. Впрочем, это тема для другой статьи...

Идём далее. Строка "use strict";, что находится в начале тела анонимной функции, указывает платформе Metro работать в так называемом "строгом" режиме. В этом режиме перед использованием любой переменной в обязательном порядке требуется её явное объявление с помощью оператора var. Что позволит снизить количество ошибок, вызванных случайным обращением к не объявленной ещё переменной.

Следующим выполняется выражение var app = WinJS.Application;. Оно объявляет переменную app и присваивает ей экземпляр объекта WinJS.Application. Данный объект представляет само Metro-приложение; единственный его экземпляр создаётся непосредстенно платформой Metro в коде базовой логики и доступен из переменной WinJS.Application. В принципе, его необязательно присваивать другой переменной, но разработчики платформы Metro так сделали.

Следующие два выражения привязывают обработчики к событиям activated и checkpoint объекта WinJS.Application. Этот код нужен в том случае, если мы собираемся реализовать сохранение и восстановление состояния приложения. Если же мы не собираемся этого делать, данные выражения можно удалить; впрочем, этого можно и не делать, так как они не выполняют ничего ни полезного, ни бесполезного.

Последнее выражение - app.start(); - вызывает метод start объекта WinJS.Application. Этот метод выполняет запуск Metro-приложения.

9.2. Принципы создания логики Metro-приложений
Теперь настало время рассмотреть принципы, по которым создаётся и работает логика Metro-приложений. Несоблюдение этих принципов вполне может привести к ошибкам в работе приложений, так что будем внимательны!

9.2.1. Объявление необходимых переменных
При разработке логики нам потребуется хранить какие-либо данные, которые будут необходимы постоянно, в любой момент функционирования приложения. К таким данным относятся экземпляры объектов, представляющих различные элементы интерфейса, информация, которая обрабатывается приложением, какие-то служебные данные и пр.

Поскольку платформа Metro по умолчанию работает в "строгом" режиме (в который её переводит уже знакомая нам строка "use strict";, присутствующая в самом начале кода её логики), нам потребуется явно объявить все эти переменные. Выполняется это с помощью оператора var.

Но куда вставить код, объявляющий переменные? Во-первых, вне объявления всех функций, прямо в тело функции, создающей анонимное пространство имён. Во-вторых, где-либо в её начало, желательно сразу после строки var app = WinJS.Application;. Так мы сведём все объявления переменных в одно место и заметно облегчим задачу их отслеживания.

(function () {
  "use strict";

  var app = WinJS.Application;

  [i]<код, объявляющий необходимые переменные>[/i]

  . . .

  app.start();
})();

start();
})();[/code]
9.2.2. Объявление необходимых функций
В процессе создания логики нам, так или иначе, придётся объявлять различные функции. В первую очередь, это, разумеется, будущие обработчики событий, возникающих в различных элементах интерфейса; в конце концов, практически весь код, формирующий логику современных приложений, - суть обработчики событий. Также нам, возможно, потребуется объявить вспомогательные функции, выполняющие какие-либо повторяющиеся задачи.

Автор рекомендует помещать код, объявляющий функции, сразу после кода, что объявляет необходимые переменные. Так мы, опять же, сведём все объявления функций в одно место и упростим себе задачу сопровождения кода.

[code](function () {
"use strict";

var app = WinJS.Application;

<код, объявляющий необходимые переменные>

<код, объявляющий необходимые функции>

app.start();
})();[/code]
9.2.3. Код инициализации
А ещё нам потребуется написать код инициализации приложения. Этот код:

  • Выполняется всего один раз за всё время функционирования приложения - сразу после его запуска.
  • Выполняет установочные задачи: получает доступ к элементам интерфейса, привязывает к событиям обработчики, задаёт значения свойств элементов интерфейса, выполняет всяческие предустановки и др.


Все задачи инициализации следует выполнять в теле обработчика события DOMContentLoaded объекта HTMLDocument.

Объект HTMLDocument представляет весь интерфейс Metro-приложения (тег <html>). Единственный его экземпляр создаётся самой платформой Metro при запуске приложения и доступен из переменной document, которая также создаётся платформой Metro.

Событие DOMContentLoaded возникает сразу после того, как платформа Metro считает из файлы default.html описание интерфейса приложения, разберёт его и сформирует в памяти компьютера экземпляры объектов, представляющие элементы интерфейса, а на экране - сами эти элементы. Или, говоря другими словами, когда интерфейс приложения будет готов к работе.

Внимание!
Внедрённые элементы интерфейса - графические изображения, звуковые и видеофайлы и др. - к моменту возникновения события DOMContentLoaded ещё могут продолжать загружаться. Для отслеживания окончания их успешной загрузки, если, конечно, её требуется отследить, следует использовать событие load этих элементов.

[code]document.addEventListener("DOMContentLoaded", function() {
<выполняем задачи инициализации>
});[/code]
Здесь мы привязали к экземпляру объекта HTMLDocument обработчик события DOMContentLoaded, реализованный в виде анонимной функции.

Код инициализации обычно помещается в самом конце кода логики, непосредственно перед выражением app.start();.

9.2.4. Получение доступа к элементам интерфейса
Чтобы манипулировать элементами интерфейса в коле логики - обращаться к их свойствам, вызывать их методы и привязывать к ним обработчики событий, - нам следует сначала получить к ним доступ. Под этим понимается получение экземпляра объекта, представляющего нужный элемент интерфейса.

Сделать это можно с помощью трёх методов, который мы сейчас рассмотрим.

Проще всего получить доступ по имени элемента интерфейса, указанного в качестве значения атрибута id формирующего его тега тега. Для этого применяется метод getElementById объекта HTMLDocument. В качестве единственного параметра он принимает строку с именем элемента интерфейса и возвращает то, что нам нужно, - представляющего этот элемент экземпляр объекта.

[code]var txtOutput = document.getElementById("txtOutput");[/code]
Получаем доступ к элементу интерфейса с именем txtOutput (это поле ввода, в котором будет выводиться результат вычислений).

Метод querySelector объекта HTMLBodyElement позволяет получить элемент интерфейса по сложному критерию, а именно, селектору, записанному в соответствии с правилами CSS. Объект HTMLBodyElement представляет содержимое тега <body>, то есть собственно описание интерфейса без служебных тегов. Единственный его экземпляр создаётся самой платформой Metro и доступен из свойства body объекта HTMLDocument. В качестве единственного параметра этот метод принимает строку с селектором CSS и возвращает экземпляр объекта, представляющий первый элемент интерфейса, что соответствует данному селектору.

[code]var txtOutput = document.body.querySelector("input[id=txtOutput]");[/code]
Получаем элемент интерфейса, сформированный с применением тега <input>, для атрибута id которого указано значение txtOutput. Хотя, разумеется, для этого удобнее использовать метод getElementById, описанный ранее.

Если же нам нужно получить все элементы интерфейса, удовлетворяющие какому-либо селектору, мы воспользуемся методом querySelectorAll объекта HTMLBodyElement. Он отличается от своего "коллеги" querySelector только тем, что возвращает коллекцию, содержащую все элементы интерфейса, что подходят под заданный селектор.

[code]var colButtons = document.body.querySelectorAll("input[type=button]");[/code]
Получаем все элементы интерфейса, сформированные с помощью тега <input>, для атрибута type которого задано значение button, то есть все кнопки.

9.2.5. Привязка обработчиков к событиям
Для привязки обработчиков к событиям следует использовать метод addEventListener, поддерживаемый всеми объектами, что представляют элементы интерфейса. Формат написания этого метода таков:

[code]<элемент интерфейса>.addEventListener(<событие>, <обработчик>)[/code]
Первым параметром указывается имя обрабатываемого события в виде строки. Вторым параметром задаётся сам обработчик события - в виде либо имени функции, либо объявления анонимной функции. Результата данный метод не возвращает.

[code]btnEqual.addEventListener("click", btnEqualClick);[/code]
Привязываем к событию click элемента интерфейса, хранящегося в переменной btnEqual, функцию-обработчик btnEqualClick. Подразумевается, что мы уже получили доступ к этому элементу интерфейса и уже объявили данную функцию. События click возникает при щелчке на элементе интерфейса.

[code]btnEqual.addEventListener("click", function() { . . . });[/code]
А здесь мы привязываем к тому же событию того же элемента интерфейса обработчик - анонимную функцию.

9.3. Написание кода логики
Вооружившись необходимыми знаниями, начнём писать код логики. Поскольку он заметно более сложен, нежели код, описывающий интерфейс, создавать его мы будем по частям.

9.3.1. Объявление необходимых переменных
Сначала напишем код, объявляющий необходимые переменные. Он будет таким:

[code]var arg1 = "", arg2 = "", op = "", txtOutput;[/code]
Переменная arg1 будет хранить тот аргумент операции, который пользователь в данный момент набирает на клавиатуре калькулятора (набираемый аргумент), переменная arg2 — второй аргумент, а переменная op — обозначение самой операции. Все эти значения мы будем хранить в строковом формате и всем трём переменным изначально присвоим пустые строки. Что касается переменной txtOutput, то она сохранит экземпляр объекта, представляющий поле ввода txtOutput.

Куда вставить этот код, мы уже знаем (см. ранее).

9.3.2. Написание кода инициализации
Следующий на очереди - код инициализации. Куда его поместить, мы также знаем.

Код инициализации нашего первого приложения будет совсем простым.

[code]document.addEventListener("DOMContentLoaded", function () {
txtOutput = document.getElementById("txtOutput");
var colButtons = document.body.querySelectorAll("input[type=button]");
for (var i = 0; i < colButtons.length; i++) {
colButtons.addEventListener("click", btnClick);
}
});[/code]
Здесь мы, прежде всего, получаем доступ к полю ввода txtOutput, к которому будем потом постоянно обращаться, чтобы вывести результат очередного вычисления. Далее с помощью метода querySelectorAll ищем все элементы интерфейса, созданные с помощью тега <input>, для атрибута type которого задано значение button, то есть все кнопки. Напоследок в цикле перебираем все кнопки — элементы полученной от метода querySelectorAll коллекции — и к каждой привязываем функцию btnClick в качестве обработчика события click.

Да-да, мы привяжем один обработчик события сразу ко всем кнопкам. Конечно, можно написать для каждой кнопки свою функцию-обработчик, но это не очень удобно.

9.3.3. Объявление необходимых функций
Теперь нам нужно объявить функцию btnClick - обработчик события click всех имеющихся в наличии кнопок. Эта функция будет реализовывать всю функциональность нашего простенького калькулятора.

[code]function btnClick(evt) {
var oTarget = evt.target;
switch (oTarget.id) {
case "btn0":
case "btn1":
case "btn2":
case "btn3":
case "btn4":
case "btn5":
case "btn6":
case "btn7":
case "btn8":
case "btn9":
case "btnDot":
arg1 += oTarget.value;
txtOutput.value = arg1;
break;
case "btnPlus":
case "btnMinus":
case "btnMult":
case "btnDiv":
arg2 = arg1;
arg1 = "";
op = oTarget.value;
break;
case "btnEqual":
if (op != "") {
var a1 = parseFloat(arg1);
var a2 = parseFloat(arg2);
var a3;
switch (op) {
case "+":
a3 = a2 + a1;
break;
case "-":
a3 = a2 - a1;
break;
case "*":
a3 = a2 * a1;
break;
case "/":
a3 = a2 / a1;
break;
}
arg1 = a3.toString();
txtOutput.value = arg1;
op = "";
}
break;
case "btnC":
arg1 = "";
arg2 = "";
txtOutput.value = "0";
break;
case "btnCE":
arg1 = "";
txtOutput.value = "0";
break;
}
}[/code]
Эта функция весьма сложна, так что давайте рассмотрим её работу по частям.

Поскольку мы привязали одну и ту же функцию-обработчик сразу ко всем кнопкам нашего приложения, то в теле этой функции будем должны определить, какую именно кнопку нажал пользователь. Сделать это очень просто.

Любая функция-обработчик получает в качестве единственного параметра (у нас он носит имя evt) экземпляр объекта Event, который хранит сведения о возникшем событии. В том числе и элемент интерфейса, в котором это событие изначально возникло, — в свойстве target данного объекта. В нашем случае этим элементом интерфейса будет кнопка, нажатая пользователем.

Каждый объект, представляющий элемент интерфейса, поддерживает свойство id, хранящее имя этого элемента, которое мы задали в атрибуте тега id. Следовательно, обратившись к этому свойству и получив его значение, мы можем однозначно сказать, какая кнопка была нажата.

[code]var oTarget = evt.target;[/code]
Первым делом мы объявляем локальную переменную oTarget, в которую помещаем значение свойства target экземпляра объекта, хранящего сведения о событии, — нажатую пользователем кнопку. Это позволит нам несколько упростить код.

Далее находится выражение выбора (switch-case), в котором имя нажатой кнопки последовательно сравнивается с именами всех кнопок, составляющих интерфейс нашего приложения.

  • Если пользователь нажал кнопку-цифру или кнопку-точку, мы получаем надпись этой кнопки (свойство value), то есть нажатую цифру или точку, добавляем её к значению набираемого аргумента (это значение хранится в переменной arg1 в виде строки) и выводим набираемый аргумент в поле ввода txtOutput:

    [code]arg1 += oTarget.value;
    txtOutput.value = arg1;[/code]
  • Если пользователь нажал кнопку со знаком арифметического действия, мы присваиваем значение набираемого аргумента (переменная arg1) второму аргументу (переменная arg2), очищаем набираемый аргумент (присваиваем переменной arg1 пустую строку), получаем надпись нажатой кнопки — обозначение операции — и сохраняем её в переменной op:

    [code]arg2 = arg1;
    arg1 = "";
    op = oTarget.value;[/code]
  • Ситуация, когда пользователь нажимает кнопку со знаком равенства, выполняя тем самым вычисление, — самая сложная. Сначала мы проверяем, хранит ли переменная op обозначение операции (любое значение, отличное от пустой строки). Это нужно, чтобы исключить ситуации, когда пользователь нажимает кнопку со знаком равенства, не указав саму операцию.

    [code]if (op != "") {[/code]
    Далее, значения аргументов в переменных arg1 и arg2 мы храним в строковом виде, и перед вычислением результата нам придётся преобразовать их в числа. Если мы этого не сделаем, при выполнении сложения платформа Metro не сложит представляемые этими аргументами числа, а объединит их в одну строку.

    Здесь нам очень пригодится функция parseFloat. Она принимает в качестве аргумента строку, содержащую число с плавающей точкой, и возвращает в качестве результата это же число, но уже в числовом виде.

    [code] var a1 = parseFloat(arg1);
    var a2 = parseFloat(arg2);
    var a3;[/code]
    Здесь мы преобразуем строковые значения обоих аргументов в числовой вид и помещаем их во вновь объявленные переменные a1 и a2. Также мы объявляем переменную a3, куда потом поместим результат вычисления.

    Обозначение выбранной пользователем операции мы храним в переменной op. Чтобы выяснить, что это за операция, и выполнить соответствующий ей фрагмент кода, мы применим выражение выбора:

    [code] switch (op) {
    case "+":
    a3 = a2 + a1;
    break;
    case "-":
    a3 = a2 - a1;
    break;
    case "*":
    a3 = a2 * a1;
    break;
    case "/":
    a3 = a2 / a1;
    break;
    }[/code]
    Результат выполнения операции теперь хранится в переменной a3. Преобразуем его в строковый вид с помощью метода toString. (Этот метод возвращает в качестве результата строковое представление экземпляра объекта, у которого был вызван, в нашем случае — строку, содержащую число.) Сразу присвоим полученную строку набираемому аргументу (переменной arg1):

    [code] arg1 = a3.toString();[/code]
    Напоследок выведем результат в поле ввода txtOutput и очистим переменную, где хранится обозначение операции (op):

    [code] txtOutput.value = arg1;
    op = "";
    }[/code]
  • Если пользователь нажал кнопку полного сброса (C), мы очищаем значения обоих аргументов — и набираемого, и второго, - после чего выводим в поле ввода txtOutput число 0:

    [code]arg1 = "";
    arg2 = "";
    txtOutput.value = "0";[/code]
  • Наконец, если пользователь нажал кнопку сброса набираемого аргумента (CE), мы очищаем только значение набираемого аргумента и также выводим в поле ввода txtOutput число 0:

    [code]arg1 = "";
    txtOutput.value = "0";[/code]


Что ж, код логики готов. Сохраним все исправленные файлы и запустим приложение на выполнение. Попробуем выполнить какие-либо действия и посмотрим, правильно ли они выполняются.

Как видим, мы создали вполне функциональное приложение, написав совсем немного кода. В этом одно из преимущество платформы Metro и языков HTML и JavaScript - они предоставляют весьма мощные и вместе с тем простые инструменты для создания элементов интерфейса и манипулирования ими.


Дополнительные материалы


Окончание следует...


dronov_va, TheVista.Ru Team
Май 2012

Комментарии

Не в сети

хэтэмэльщики, чтоб вас.

Не умееют в XAML, зато в костыли - бегом.

16.05.12 14:32
0
Не в сети

2 Armanx64: Не большие костыли, чем какой-нибудь jQuery Mobile.

17.05.12 09:00
0
Не в сети

Костыли, костыли.
Шёл 2012-й год, а тут хэтэмэль...

20.05.12 16:00
0
Не в сети

Шёл 2012 год, а у ряда XAML-щиков всё ещё наблюдались комплексы перед нами, HTML-щиками...

21.05.12 09:06
0
Для возможности комментировать войдите в 1 клик через

По теме

Акции MSFT
90.14 0.00
Акции торгуются с 17:30 до 00:00 по Москве
Мы на Facebook
Мы ВКонтакте
Все права принадлежат © MSInsider.ru (ex TheVista.ru), 2017
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.062 секунд (Общее время SQL: 0.008 секунд - SQL запросов: 39 - Среднее время SQL: 0.00021 секунд))