Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript

Состояния, параметры, файлы и документы

Разбить на страницы
Показывать лекцию целиком

Файлы к данной лекции Вы можете скачать здесь.

Было бы очень интересно, если бы, когда вы путешествуете, каждый гостиничный номер, в котором вы останавливаетесь, автоматически подстраивался бы под ваши предпочтения. Чтобы там были подушки и простыни, которые вам нравятся, правильные стулья, ваша любимая еда в минибаре – вместо непристойно дорогих и невероятно маленьких банок с закусками. Если вы достаточно богаты, конечно, вы можете заранее отправить своих людей для того, чтобы они все подготовили, но подобное для множества из нас – лишь мечта.

Программное обеспечение, к счастью, не связано подобными ограничениями. Отправить своих людей в гостиницу перед своим приездом не означает необходимость бронирования для них авиабилетов, не нужно платить им зарплату и обеспечивать медицинскую страховку, не нужно делать вклады в их пенсионное обеспечение. Все, что нужно – подключение к Интернету, облачные сервисы, и вуаля! Все ваши предпочтения могут автоматически путешествовать вместе с вами. То есть – перемещаться между различными устройствами, которыми вы пользуетесь.

Этот опыт работы с перемещаемыми данными (roaming experience), как он называется, встроен в Windows 8 для параметров, оказывающих влияние на систему, таких, как изображение вашего профиля, установки начального экрана, избранные интернет-страницы, тема рабочего стола, сохраненные учетные данные и так далее. Когда вы используете учетную запись Microsoft для входа в Windows на доверенном компьютере, эти параметры безопасно сохраняются в облаке и автоматически перемещаются на другие доверенные устройства под управлением Windows 8, на которых вы используете ту же учетную запись. Я был приятно удивлен, когда в ходе разработки Windows 8 мне не приходилось вручную переносить все эти данные, когда я обновлял предварительные релизы системы на своем компьютере!

Если подобное возможно для системных параметров, пользователи будут ожидать похожего поведения и от приложений. Они будут ожидать, что параметры приложения будут надлежащим образом перемещаться с одного устройства на другое. Я сказал "надлежащим образом", так как некоторые настройки не имеет смысла перемещать, особенно те, которые специфичны для аппаратного обеспечения устройства. С другой стороны, если я настраиваю почтовые учетные записи в приложении на одном компьютере, я, конечно, надеюсь на то, что они окажутся и на других! (Не могу точно сказать вам, сколько раз я настраивал четыре своих активных почтовых учетных записи в Outlook). В общем, как пользователь, я ожидаю, что мой переход между устройствами – как на уровне системы, так и на уровне приложений – будет прозрачным и гладким.

Таким образом, это означает, что каждое приложение должно выполнять свою работу по управлению собственным состоянием (включая – перемещение документов и других пользовательских данных посредством служб наподобие SkyDrive), и даже обеспечивать те виды кэширования, которые помогут увеличить производительность и сформировать хороший опыт взаимодействия пользователя и программы в условиях, когда устройство не подключено к Интернету. Как я уже говорил о многих подобных функциональных деталях, усилия, которые вы вкладываете в них, могут сыграть важную роль в том, как пользователи воспринимают ваше приложение и в том, какие оценки и отзывы о приложени они оставят в Магазине Windows.

Многие подобные параметры будут полностью внутренними по отношению к приложению, а другие пользователь может настраивать и обычно так и поступает. В прошлом это порождало сложные наборы из вложенных диалоговых окон с множеством закладок, каждая из котоых была украшена кнопками, выпадающими меню и большими взаимосвязаными группами флажков и переключателей. Как результат, в деле настройки приложений не было единообразия. Не было и постоянного места, где располагались настройки приложений. Это могли быть, кроме прочих, команды меню Инструменты > Параметры, или Правка > Предустановки, или Файл > Сведения

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

Очевидно, данные приложения – параметры и внутренние состояния – лишь часть рассказа. Пользовательские данные (user data), такие, как документы, картинки, музыкальные и видео-файлы – тоже весьма важны. Для работы с ними мы ищем соответствующие возможности в манифесте приложения, позволяющие приложению работать с документами и медиа-библиотеками, со сменными носителями информации, позволяющие ему получать доступ к содержимому папок с помощью запросов. Мы решаем, как средство выбора файлов (file picker) позволит пользователю принять решение о доступе к другим безопасным областям файловой системы (но не к системным областям и папкам данных других приложений).

И здесь Windows 8, на самом деле, выводит нас за пределы локальной файловой системы. Подавляющее большинство данных, к которым имеет доступ современный пользователь, обычно расположены в сетевых хранилищах данных, а не в локальной файловой системе. Проблема здесь в том, что подобные данные обычно скрыты за специализированными API или веб-сервисами, что означает, что пользователь должен самостоятельно работать с веб-приложениями для просмотра данных, загружать и сохранять их в локальную файловую систему, и затем импортировать их в другие приложения. Видя такую модель взаимодействия, разрабочтики Windows 8 нашли другую возможность, которая представляет новый уровень интеграции и единообразия, которая позволяет приложениям представлять данные, хранящиеся в различных сервисах так, что они выглядят для других приложений как часть локальной файловой системы. Подобное реализуется посредством контракта средства выбора файлов (file picker contract), предоставляя пользователям возможность бесшовного опыта взаимодействия с локальными и сетевыми данными. Здесь мы рассмотрим ситуацию с точки зрения пользователя, а в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", поговорим о провайдерах данных.

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

Рассказ о состояниях приложения

Продолжая сравнение, о котором мы говорили в начале лекции, когда мы приезжаем в новые места и останавливаемся в гостинице, большинство из нас признает тот факт, что им, по прибытии, придется потратить некоторое время на то, чтобы распаковать вещи и расставить все в комнате так, как нам нравится. С другой стороны, мы ожидаем полной противоположености от наших домов: мы ожидаем преемственности или сохранения состояния (statefulness). За последний год я дважды переезжал (один раз – во временное жилище, пока наш дом не был достроен), и я способен оценить достоинства сохранения состояния. Представьте себе, что все в вашем доме упаковывается в коробки каждый раз, когда вы уезжаете. В итоге вам приходится тратить несколько часов, дней или недель на то, чтобы все распаковать! Нет, дом – это место, в котором, по нашим ожиданиям, вещи остаются на своих местах, даже если мы на некоторое время уезжаем. Думаю, именно поэтому многие люди любят путешествовать в домах на колесах!

Приложения для Магазина Windows рассчитаны на такую вот неизменность состояния, что означает, что они поддерживают у пользователя ощущение преемственности между сеансами работы, даже если приложение было приостановлено или остановлено между сеансами. Таким образом, приложения воспринимаются больше как дом, а не как временное пристанище. Они становятся местом, в которое пользователь приходит, чтобы отдохнуть среди данных, которые ему нужны. В итоге, чем меньше усилий ему потребуется, чтобы начать наслаждаться подобным опытом взаимодействия с программой – тем лучше.

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

Чтобы четко осознавать понятие "состояние приложения", вернемся ненадолго к пользовательским данным. Пользовательские данные, наподобие документов, изображений, музыкальных записей, видеофайлов, плейлистов и других подобных данных, создаются и используются приложением, но не зависят от приложения. Пользовательские данные подразумевают возможность работы с ними из разных приложений, и такие данные всегда остаются в системе, вне зависимости от существования приложения. Поэтому данные пользователя не являются частью состояния приложения. То есть, хотя приложение может запоминать пути (paths) к документам и другим файлам в составе списков избранных материалов или среди недавно использованных объектов реальное содержимое (content) этих файлов не является частью состояния приложения. Пользовательские данные, таким образом, не имеют прочной взаимосвязи с событиями жизненного цикла приложения. Их обычно сохраняют либо по непосредственной команде пользователя, либо, неявно, по событию наподобие visibilitychange, вместо использования такого события, как suspending. Опять же, приложение может запомнить список загруженных файлов как часть состояния сеанса работы при обработке события suspending, но содержимое файлов следует сохранить вне этого события, так как у вас есть лишь пять секунд на то, чтобы совершить все необходимые действия.

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

Данные приложения используются для управления следующими видами состояний:

  • Состояние сеанса (Session state). Это состояние, которое приложение сохраняет при приостановке для восстановления его после возможной остановки. Сюда включаются данные форм, история навигации по страницам и так далее. Как мы видели в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", перезапуск после приостановки и последующей остановки – это единственный случай, в котором приложение восстанавливает состояние сеанса. Состояние сеанса обычно сохраняют инкрементно (при изменении состояния), либо при обработке событий suspending или checkpoint.
  • Локальное состояние приложения (Local app state). Это – параметры, которые обычно загружаются при запуске приложения. Состояние приложения включает в себя кэшированные данные, сохраненные результаты поиска, списки недавно просмотренных элементов и различные параметры поведения приложения, которые отображаются в панели Параметры в виде настроек отображаемых элементов, предпочитаемых видеоформатов, настроек, зависящих от устройства и так далее. Локальное состояние приложения обычно сохраняется при его изменении, а не при обработке событий жизненного цикла приложения.
  • Перемещаемое состояния приложения (Roaming app state). Это состояние приложения, которое перемещается между экземплярами одного и того же приложения, исполняющимися на различных Windows 8 – устройствах, на которых пользователь выполнил вход. Это – списки избранного, позиция воспроизведения видео, параметры учетной записи, URI для важных файлов в облачном хранилище данных, возможно, некоторые сохраненные результаты поиска или запросы, и так далее. Так же, как локальном состоянием приложения, этим состоянием ожно управлять посредством панели Параметры. Перемещаемое состояние так же лучше всего сохранять при изменении значений. Больше об этом мы узнаем далее в этой лекции.
  • Есть два других компонента состояния приложени, которыми, на самом деле, управляют вне папки данных приложения или контейнеров параметров. Один из них – это список файлов, которые изначально получены посредство средства выбора файлов, к которым приложению может понадобиться программный доступ в будущем. Для подобных файлов недостаточно сохранить лишь путь – нужно сохранить и сведения о факте предоставления пользователем разрешения на доступ к ним с помощью средства выбора файлов. Это – цель использования API ), и, в целом, является частью локального состояния приложения.

    Второй компонент – это учетные данные, которые вы получили от пользователя и хотите использовать в будущем. Так как эти данные имеют критическую важность, в плане безопасности, приложению никогда не следует хранить их в составе собственных данных. Вместо этого используйте API хранилища учетных данных ). Содержимое хранилища будет перемещаться между доверенными ПК пользователя, и, таким образом, составлять часть перемещаемого состояния приложения. Больше об этом вы узнаете в лекции 3 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой".

    Параметры и состояние приложения

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

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

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

    Вот некоторые примеры хороших кандидатов на размещение в интерфейсе чудо-кнопки.

  • Отображение предустановок, наподобие единиц измерения, цветовых тем, выравнивающих сеток и предустановок.
  • Предпочтения, касающихся перемещаемых данных, которые позволяют пользователю настроить перемещение данных приложения, такое, как, например, раздельное хранение настроек для рабочего и домашнего компьютеров.
  • Настройки учетной записи и профиля, а так же – команды для входа в аккаунт и выхода от него, и для управления аккаунтами и профилями. Никогда не следует хранить пароль в составе локальных или перемещаемых состояний, используйте вместо этого Хранилище учетных данных.
  • Параметры, влияющие на поведение приложения, наподобие оффлайнового и онлайнового режима, авто-обновления данных, интервалов обновления данных, предпочитаемого качества потокового аудио и видео. Здесь же находятс параметры передачи данных в сетях с лимитными тарифными планами, расположения, из которых приложению следует загружать данные и так далее.
  • Форма или ссылка для обратной связи, с помощью которой вы можете получить от пользователя какую-то особую информацию.
  • Дополнительные сведения о приложении, такие, как Справка, О программе, страница с информацией об авторских правах, заявление о конфиденциальности, лицензионное ограничение, условия использования. Часто подобные команды перенаправляют пользователя на специальный сайт, такой подход отлично подходит для реализации.
  • Я настоятельно рекомендую вам ознакомиться с приложениями, которые встроены в Windows и исследовать особенности использования ими чудо-кнопки Параметры. Так же вы можете изучить и то, как чудо-кнопка Параметры используется другими приложениями в Магазине Windows, однако, эти приложения не всегда следуют руководствам по проектированию приложений, которые декларируют единообразие интерфейса, а это очень важно для настройки параметров.

    Если говорить об этом, то Windows автоматически предоставляет всем приложениям команды, которые называются Разрешения (Permissions) и Отзывы и оценки (Rate and Review). Команда Отзывы и оценки ведет пользователя к странице приложения в Магазине Windows, где пользователь может поставить приложению оценку и написать отзыв. Команда Разрешения, в свою очередь, позволяет пользователю контролировать доступ к критически важным ресурсам, таким, как определение местоположения, камера, микрофон и так далее. То, что появляется в данном разделе, зависит от набора возможностей, объявленных в манифесте приложения, и это то место, где пользователь может отозвать то или иное разрешение или предоставить его приложению. Конечно, если приложение не использует подобных возможностей, команда Разрешения не отображается.

    Вы можете обратить внимание на то, что я не упоинал отображение сведений об обновлениях приложения внутри интерфейса чудо-кнопки Параметры. В этом нет необходимости, так как уведомления об обновлениях обеспечиваются напрямую Магазином Windows. Это – еще один способ уменьшения количества ненужного содержимого, с которым ранее сталкивались пользователи, когда каждое приложение по-своему представляло информацию об обновлениях (и иногда это происходило слишком часто!).

    Расположение данных приложения

    Теперь, когда мы понимаем, какик виды информации составляют состояние приложения, следующий вопрос заключается в том, где все это хранится. Вы можете помнить, из Главы 1 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", что когда Windows устанавливает приложение для пользователя (и все приложения для Магазина Windows доступны только тому пользователю, который их устанавливает), она автоматически создает папки LocalState, TempState и RoamingState внутри папки AppData текущего пользователя. Те же папки удаляются при деинсталляции приложения. В файловой системе, если вы, с помощью Проводника, перейдете в папку %localappdata%\packages, вы увидите множество папок для различных приложений в вашей системе. Если вы зайдете в любую из них, вы увидите вышеописанные папки вместе с еще одной, которая называется "Settings", как показано на рис. 2.1 для встроенного в систему приложения Sports (Спорт). На рисунке так же показано различное содержимое этих папок. (рис 2.1) Папка AppData приложения Sports (Спорт) и ее содержимое

    В папке LocalState на рис. 2.1 вы можете видеть файл с именем _sessionState.json. Это файл, где WinJS хранит, и откуда загружает содержимое объекта WinJS.Application.sessionState, как мы видели в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". Так как это обычный текстовый файл в формате JSON, вы можете просто открыть его в приложении Notepad (Блокнот) или в любом другом просмотрщике JSON для того, чтобы просмотреть его содержимое. Если вы взглянете на открытый файл приложения Sports (Спорт), который показан на рисунке, вы увидите что-то вроде {"lastSuspendTime":1340057531501}. Приложение Sports (Спорт) (вместе с приложениями News (Новости), Weather (Погода), и так далее), отображает содержимое, зависящее от времени, таким образом, это и другие приложения сохраняют время, когда они были приостановлены и проверяют прошедшее время при возобновлении. Если это время превышает интервал обновления данных, они могут запросить новые данные с сервиса, с которым связаны. В случае приложения Sports (Спорт), один из его параметров позволяет пользователю настроить интервал обновления данных.

    Если ваше приложение использует любое API хранения данных HTML5, такое, как локальное хранилище, IndexedDB, и кэш приложения, их данные так же появятся в папке LocalState.

    Примечание. Если вы внимательно посмотрите на рис. 2.1 вы увидите, что все папки с данными приложения, включая перемещаемые данные, находятся в папке пользователя AppData/Local. Есть и папка, родственная ей, AppData/Roaming, но она применяется лишь для параметров перемещаемых учетных записей пользователей в интранет-сети, как в случае, когда пользователь из присоединенного домена входит в систему с другого компьютера в корпоративной сети. Эта папка AppData/Roaming никак не связана с папкой AppData/Local…/RoamingState приложений для Магазина Windows.

    Вы можете обращаться к этим расположениям различными программными способами. Во-первых, вы можете использовать URI-схему ms-appdata:///, как мы видели в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". Здесь ms-appdata:///local, ms-appdata:///roaming, и ms-appdata:///temp позволяют обратиться к отдельным папкам и их содержимому. (Обратите внимание на тройной слэш, что является сокращением, позволяющим вам опускать имя пакета приложения). Так же вы можете использовать объект, который возвращает метод Windows.Storage.ApplicationData.current, который содержит все необходимые API, которые нужны вам для работы с состоянием приложения.

    Кстати, у вас могут быть данные только для чтения прямо в пакете приложения. С помощи URI вы можете просто использовать относительные пути, которые начинаются с /. Если вы хотите открыть и прочитать содержимое файла напрямую, вы можете использовать объект StorageFolder из свойства Windows.ApplicationModel.Package.current.installedLocation. Скоро мы вернемся к классу StorageFolder.

    API AppData (WinRT и WinJS)

    Когда вы запрашиваете у Windows свойство ), который полностью настроен для вашего приложения. Вот, что содержит этот объект:

  • Свойства localFolder, temporaryFolder, и roamingFolder, каждое из которых является объектом Windows.Storage.StorageFolder, который позволяет вам создавать любые файлы и дополнительные структуры папок в соответствующих расположениях (но помните о параметре roamingStorageQuota, который описан ниже).
  • Свойства ) и позволяют управлять иерархией контейнеров, состоящих из пар ключ-значение, или составными группами подобных пар значений. Все эти установки хранятся среди других данных приложения в папке Settings, в файле settings.dat.
  • Свойство roamingStorageQuota, которое содержит сведения об объеме данных, в килобайтах, которые Windows автоматически перемещает для целей приложения (обычно – 100). Если общий объем данных, сохраненных в папках roamingFolder и roamingSettings, превышает указанный лимит, перемещение будет приостановлено до тех пор, пока объем данных не упадет ниже квоты. Вы должны контролировать объем хранимых данных, если вы полагаете, что их объем близок к лимиту.
  • Событие dataChanged указывает на синхронизацию папок roamingFolder или roamingSettings с данными, хранящимися в облаке. По данному событию приложению следует повторно прочесть данные перемещаемого состояния. Это событие WinRT, для которого нужно использовать removeEventListener, как было описано в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript".
  • Метод signalDataChanged вызывает событие dataChanged. Это позволяет вам объединить обновления локальных и перемещаемых состояний в одном обработчике для события dataChanged.
  • Свойство version и метод setVersionAsync предназначены для управления отметками версий данных приложения. Версии применимы к полному объему данных – к локальным, временным и перемещаемым данным. Отдельные версии для разных данных не предусмотрены.
  • Метод clearAsync позволяет очищать состояние всех папок AppData и контейнеров параметров. Используйте его, когда вы хотите повторно инициализировать состояние по умолчанию, что особенно полезно, когда вы перезапускаете приложение из-за нарушения данных его состояния.
  • Метод clearAsync(<locality>) это вариант clearAsync, который ограничен одним расположением (локальным, временным, перемещаемым). Расположение идентифицируется с помощью значения из Windows.Storage.ApplicationDataLocality, такое, как Windows.Storage.ApplicationDataLocality.local. В случае с локальными и перемещаемыми данными, содержимое обеих папок и содержимого контейнеров очищается. Параметр temp воздействует только на папку TempState.
  • Теперь давайте посмотрим на то, как использовать это API для управления различными видами состояния приложения, что включает в себя некоторые вспомогательные функции WinRT, используемые для тех же целей.

    Подсказка. API, которые работают с состоянием приложения, вызывают события в Средстве просмотра событий (Event Viewer), если вы включили эту возможность, как было описано в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". Убедитесь в том, что функция Вид > Отобразить аналитический и отладочный журналы (View > Show Analytic and Debug logs) включена. Затем пройдите в раздел Application and Services Log (Журналы приложения и служб), разверните раздел Microsoft/Windows/AppModelState, где вы найдете группы Debug (Отладка) и Diagnostic (Диагностика).

    Контейнеры параметров

    Для начинающих, давайте посмотрим на свойства localSettings и roamingSettings, которые обычно называют контейнерами параметров (settings containers). Вы работаете с ними с помощью API ApplicationDataContainer, которое устроено довольно просто. Каждый контейнер имеет четыре свойства только для чтения: name (строка) , locality (значение из Windows.Storage.ApplicationDataLocality, здесь есть лишь значения local и roaming), и коллекции, которые называются values и containers.

    Параметры контейнеров верхнего уровня имеют пустые имена. Свойство устанавливается на дочерние контейнеры, которые вы создаете с помощью метода createContainer (и удаляете с помощью deleteContainer). Эти дочерние контейнеры могут содержать другие контейнеры, что позволяет вам создавать иерархию настроек. Таким образом, эти контейнеры настроек предназначены для хранения небольших объемов данных, обычно – параметров пользователя, и отдельных параметров, объем которых ограничен 8 Кб, а так же любые наборы взаимосвязанных параметров (смотрите ниже) размером до 64 Кб. Учитывая эти ограничения, превышение объема в один мегабайт предусматривает довольно сложную иерархию настроек, которой сложно управлять, и доступ к которой осуществляется сравнительно медленно. Поэтому не поддавайтесь искушению воспринимать эти настройки как своего рода базу данных. Для этих целей гораздо лучше подходят иные механизмы, такие, как IndexedDB и SQLite, и с их помощью вы можете хранить любые объемы данных, так же, как и в папках AppData (помните об ограничении на объем перемещаемых данных, когда вы записываете данные в roamingFolder).

    Для любого контейнера, который у вас есть, его коллекция ), с помощью которого вы можете просматривать содержимое контейнера. Коллекция values, с другой стороны, это обычный массив (с технической точки зрения – объект IPropertySet в WinRT, который проецируется в WinJS в виде массива с методами IPropertySet). Таким образом, хотя свойство values в любом контейнере – это свойство только для чтения, что означает, что вы не можете назначить ему какой-либо произвольный массив, вы можете управлять содержимым данного массива так, как вам нужно.

    Мы можем увидеть это в примере "Данные приложения" (http://code.msdn.microsoft.com/windowsapps/ApplicationData-sample-fb043eb2), в котором есть много примеров базовых операций с данными приложения. Сценарий 2, например, (js/settings.js) показывает простоту использование массива localSettings.value:

    var localSettings = Windows.Storage.ApplicationData.current.localSettings;
    var settingName = "exampleSetting";
    var settingValue = "Hello World";
    
    function settingsWriteSetting() {
    localSettings.values[settingName] = settingValue;
    }
    
    function settingsDeleteSetting() {
    localSettings.values.remove(settingName);
    }
     

    Многие параметры, похожие на те, которые показаны выше, это простые пары ключ-значение, но другие параметры могут быть объектами с множеством свойств. Это являет собой особую проблему: хотя вы можете, конечно, записывать и считывать отдельные свойства данного объекта внутри массива values, что случится, если в одном из них произойдет сбой? Это приведет к тому, что состояние приложения окажется поврежденным.

    Для защиты от этого API для работы с данными приложения предоставляет возможность работы с взаимосвязанными параметрами (composite settings) как с неделимой единицей. (Повторюсь, каждый набор взаимосвязанных параметров ограничен размером в 64 Кб). Это похоже на идеальное групповое сознание: либо все преуспеют, либо всех ждет неудача и ничего кроме этих двух вариантов! Таким образом, если возникает ошибка при чтении или записи любой части взаимосвязанных параметров, вся операция признается несостоявшейся. В случае с перемещаемыми данными, либо перемещается вся группа взаимосвязанных параметров, либо они не перемещаются вовсе.

    Объект взаимосвязанных параметров создается с помощью ), как показано в Сценарии 4 примера работы с данными приложения (js/compositeSetting.js) нет такого сценария:

    var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
    var settingName = "exampleCompositeSetting";	
    var settingName1 = "one";	
    var settingName2 = "hello";	
    function compositeSettingsWriteCompositeSetting() {
    var composite = new Windows.Storage.ApplicationDataCompositeValue();
    composite[settingName1] = 1; // пример значения	
    composite[settingName2] = "world"; // пример значения
    roamingSettings.values[settingName] = composite;
    }	
    
    
    function compositeSettingsDeleteCompositeSetting() {
    roamingSettings.values.remove(settingName);
    }
    
    
    function compositeSettingsDisplayOutput() {	
    var composite = roamingSettings.values[settingName];
    // ...	
     }
     

    Объект ApplicationDataCompositeValue имеет, как вы можете увидеть в документации, некоторые дополнительные методы и события для того, чтобы помочь в управлении им, это такие методы, как clear, insert и mapchanged.

    Взаимосвязанные параметры, во многом, напоминают контейнер параметров, однако, они не могут содержать другие контейнеры. Важно не путать их с обычными контейнерами. Дочерние контейнеры внутри параметров используются лишь для создания иерархии (посмотрите Сценарий 3 примера). Взаимосвязанные параметры, с другой стороны, специально созданы для создания более сложных наборов параметров, которые работают как неделимая единица, подобное поведение не гарантировано для обычных контейнеров параметров.

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

    Управление версиями состояния приложения

    С точки зрения Windows, локальное, временное и перемещаемое состояние – это части единого целого, и все они имеют одну и ту же версию. Номер версии устанавливается посредством ), прочитать номер версии можно, воспользовавшись свойством только для чтения Windows.Storage.ApplicationData.version. Если хотите, вы можете поддерживать собственную систему назначения версий, с помощью отдельного файла или параметра приложения. Однако, я рекомендую, чтобы вы избегали подобного с перемещаемым состоянием, так как сложно предсказать, как Windows будет управлять синхронизацией слегка отличающихся структур. Даже в случае с локальным состоянием, попытка играть в сложные игры версий, на самом деле, может оказаться гораздо сложнее, чем кажется, и, вероятно, подобного лучше избегать вообще.

    Версия данных вашего приложения и версия приложения – это разные вещи. На самом деле, они никак не связаны. В то время, как версия данных приложения устанавливается с помощью setVersionAsync, версией приложения управляют в разделе Упаковка (Packaging). У вас может быть приложение, которое от версии 1.0.0.0 до версии 4.3.9.3 использует данные приложения версии 1.0.0.0, или, может быть, версия приложения 1.2.1.9 переходит на версию 1.0.1.0. данных приложения, и версия 2.1.1.3 использует версию 1.2.0.0 данных приложения. На самом деле, это неважно, до тех пор, пока вы контролируете этот процесс и старые данные приложения могут переходить к новым версиями приложений!

    Переход (migration) происходит при вызове ), который содержит свойства ).

    Можно осуществлять перенос данных приложения и тогда, когда устанавливается новое обновление приложения. Для этого пользуются фоновой задачей для вызова sevicingComplete. Смотрите Главу 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", в особенности – раздел "Фоновые задачи и приложения на экране блокировки" ближе к концу.

    Управление папками и файлами

    Так как часто очень удобно сохранять данные приложения напрямую в файл, настало время для того, чтобы внимательно рассмотреть файловые API приложений для Магазина Windows.

    Для начала, однако, взглянем на другие API, такие, как URL.createObjectURL – работающее с тем, что мы называем большим двоичным объектом (blob), делая возможным выполнять множество действий в приложения без необходимости спускаться на уровень файлового ввода/вывода. Мы уже видели, как этим пользоваться, устанавливая свойство ).

    Для того чтобы работать напрямую с файлами, рассмотрим то, что имеется в нашем распоряжении, использовав конкретные образцы из примера "Доступ к файлам" (http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597).

    Основные API WinRT для работы с файлами расположены в пространстве имен ) и StorageFile (http://msdn.microsoft.com/library/windows/apps/windows.storage.storagefile.aspx). И на то и на другое иногда ссылаются как на "элементы хранения", так как и тот и другой класс унаследованы от IStorageItem (http://msdn.microsoft.com/library/windows/apps/windows.storage.istorageitem.aspx) и имеют одинаковые свойства, такие, как name, path, dateCreated и attributes, а так же методы deleteAsync и renameAsync.

    Файловые операции ввода-вывода в WinRT практически всегда начинаются с получения объекта StorageFolder посредством одного из нижеперечисленных способов. В некоторых случаях вы так же можете получить объект StorageFile напрямую:

  • Свойство ) получает StorageFolder, посредством которого вы можете загружать данные из файлов, которые находятся в пакете приложения (все файлы – только для чтения).
  • Свойства Windows.Storage.ApplicationData.current.localFolder, roamingFolder, или temporaryFolder обеспечивают объекты StorageFolder для различных расположений данных приложения (для чтения и записи).
  • Приложение может позволить пользователю выбирать папку или файл напрямую, используя средство выбора файлов, запущенное посредством ) а так же ) и ). Для приложений это – предпочтительный способ, используя который нет необходимости в просмотре содержимого библиотеки (смотрите следующий пункт списка). Это так же единственное средство, с помощью которого приложение может получить доступ к безопасным (несистемным) областям файловой системы без необходимости объявления дополнительных возможностей в манифесте.
  • Объект ) предоставляет объекты StorageFolder для библиотек "Документы", "Музыка", "Видео", так же, как и для доступа к съемным устройствам. Задавая соответствующие возможности в манифесте, вы можете работать с содержимых этих папок. (Попытка получить доступ к папке без объявления соответствующих возможностей приведет к выдаче исключения "Доступ запрещен").
  • Объект ) предоставляет метод createFolderAsync, посредством которого вы можете получить StorageFolder для папки "Загрузки". Он так же предоставляет метод createFileAsync для непосредственного создания объектов StorageFile. Данное API следует использовать, если ваше приложение управляет загруженными файлами напрямую. Обратите внимание на то, что DownloadFolder предоставляет лишь эти два метода, она не является StorageFolder.
  • Статический метод ) возвращает ), к нему применимы те же ограничения. ) открывает файлы с помощью URI ms-appx:// (package) и ms-appdata:/// . Другие схемы не поддерживаются.
  • Как только объект, соответствующий папке или файлу, получен, его можно сохранить в кэше ), который позволяет приложению получать эти объекты позже, с теми же программными разрешениями. Это нужно, преимущественно, для файлов или папок, выбранным с помощью средств выбора, так как разрешения на доступ к элементу хранения выдаются лишь на период существования данного объекта в памяти. Всегда следует использовать данное API, как показано в Сценарии 6 примера о доступе к файлам, где вы принимаете решение о сохранении пути к файлу. Опять же, StorageFolder.getFolderFromPathAsync и StorageFile.getFileFromPathAsync выдадут исключение "Доступ запрещен", если они указывают на любое расположение, для доступа к которому у вас уже нет разрешения. Пути к файлам, так же, не будут работать для файлов, предоставленных другими приложениями через средство выбора файлов, так как объект StorageFile, на самом деле, может не указывать на файл, который реально существует в файловой системе.
  • Как только у вас есть ) (подключенного для ), который, в свою очередь, имеет метод ). С помощью этого метода вы можете получить любое количество свойств Windows (http://msdn.microsoft.com/library/windows/desktop/dd561977.aspx). Свойство наподобие System.FreeSpace даст вам реальный размер свободного пространства на диске, где расположена папка, которой соответствует StorageFolder . .

    ). Кроме того обратите внимание на то, что доступ к UNC-путям требует объявления возможностей Частные сети (клиент и сервер) (Private Networks (ClientServer)) и Корпоративная аутентификация (Enterprise Authentication) в манифесте вместе с объявлением типов файлов, к которым вы хотите получить доступ.

    С помощью любого StorageFolder, в особенности для расположений, соответствующих данным приложения, вы можете создать любую необходимую структуру папок с помощью методов createFolderAsync/getFolderAsync, которые дают вам больше объектов StorageFolder. В любой из этих папок вы затем используете методы createFileAsync/getFileAsync для доступа к отдельным файлам, каждый из которых будет представлен в виде объекта StorageFile.

    Каждый ) обеспечивает соответствующие свойства наподобие name, path, dateCreated, fileType, contentType, и attributes, конечно, вместе с методами наподобие getThumbnailAsync, copyAsync, deleteAsync, moveAsync, moveAndReplaceAsync, и renameAsync для управления файлами. Файл можно открыть разными способами, зависящими от того, доступ какого рода вам нужен:

  • Методы ) и ), соответственно, оба находящиеся в пространстве имен Windows.Storage.Streams. Первый из них работает с исходным двоичным потоком. Второй работает с данными, используя их тип, что может быть нужно для работы с HTTP-ответом, который добавляет в поток данных сведения о типе содержимого.
  • Метод ), посредством которого можно читать содержимое файла блоками байтов, но нельзя возвращаться к ранее прочитанной области. Данный метод следует использовать во всех случаях, когда вам просто нужно прочесть данные из потока, так как он обладает лучшей производительностью, чем поток для произвольного доступа (источник можно оптимизировать для последовательного чтения данных).
  • Метод ), который является вспомогательным объектом, построенным на основе IRandomAccessStream , который имеет методы commitAsync и close для обработки транзакций. Это необходимо при сохранении данных со сложной структурой, для того, чтобы быть уверенным в том, что вся операция записи произошла атомарным образом, и файлы не были повреждены при ее прерывании. Сценарий 4 в примере о доступе к файлам показывает этот подход.
  • Класс StorageFile так же предоставляет два статических метода: createStreamedFileAsync и createStreamedFileFromUriAsync. Результатом их работы является объект StorageFile, который обычно передают другим приложениям посредством контракта, как мы увидим в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой". Полезность этих методов заключается в том, что доступ к файлу, лежащему в их основе, не осуществляется до тех пор, пока его данные не будут запрошены в первый раз, если такой запрос вообще произойдет.

    Соберем теперь все это воедино. Вот небольшой фрагмент кода, использующий исходные API, которые мы рассматривали, для создания и открытия файла "data.tmp" в папке временных данных приложения, расположенной в папке AppData, и для записи в него заданной строки. Это – код из упражнения RawWriteFile к этой лекции. Позвольте мне пояснить, что то, что здесь показано, использует низший уровень API в WinRT для этих целей, и это не то, чем обычно пользуются, как мы увидим в следующем разделе. Тем не менее, это полезно знать, так как бывают случаи, когда нужно использовать нечто подобное:

    var fileContents = "Congratulations, you're written data to a temp file!";
    writeTempFileRaw("data.tmp", fileContents);
    
    
    function writeTempFileRaw(filename, contents) {
    var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;
    var outputStream;
    
    //Ей-богу!
    tempFolder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting)
    .then(function (file) {
    return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
    }).then(function (stream) {
    outputStream = stream.getOutputStreamAt(0);
    var writer = new Windows.Storage.Streams.DataWriter(outputStream);
    writer.writeString(contents);
    return writer.storeAsync();
    }).done();
    }
     

    Хорошо, что недавно мы узнали об асинхронных операциях, объединенных в цепочку! Для начала мы создаем или открываем заданный файл в папке temporaryFolder среди данных приложения (createFileAsync), затем получаем выходной поток для файла (openAsync и getOutputStream). Затем мы создаем на основе потока объект DataWriter, записываем в файл данные (writeString) и убеждаемся, что информация сохранена в файле (storeAsync).

    Но вы скажете: "Вы, должно быть, шутите! Четыре объединенных в цепочку асинхронных операции только для того, чтобы записать обычную строку в файл! Кто разрабатывал это API?" Действительно, когда мы начинали создавать самое первое приложение для Магазина Windows в Microsoft, у нас было лишь это, и мы задавали себе те же вопросы. В конце концов, выполнение некоторых ожидаемо простых файловых операций ввода-вывода – это обычно первое, что добавляют в приложение "Hello World", и это в данном случае совсем не просто. Что еще хуже, тогда у нас не было promise-объектов для асинхронных операций в JavaScript, поэтому мы должны были написать это на основе исходных вложенных операций. Такие были времена.

    К счастью, более простые API уже были доступны, и многое было сделано уже после этого. Это те API, которые вы обычно будете использовать, при работе с файлами, и это мы рассмотрим в следующем разделе. Тем не менее, важно понимать структуру вышеприведенного низкоуровневого кода, так как класс ) и родственный ему ) – это очень важные механизмы для работы с множеством различных потоков ввода-вывода, и они необходимы для процессов кодирования данных. Контроль над мелкими деталями, кроме того, позволяет реализовывать сценарии, когда различные компоненты вашего приложения вносят собственный вклад в структуру файла. Поэтому хорошо будет взглянуть на документацию по ним, и на пример "Чтение и запись данных" (http://code.msdn.microsoft.com/windowsapps/Reading-and-writing-data-75ea10a3) лишь для того, чтобы вы были знакомы с их возможностями.

    Врезка: Закрытие потоков против закрытия файлов

    Разработчики, которые работали ранее с API ввода-вывода иногда спрашивают, почему у объекта StorageFile нет чего-то вроде метода close. Причина в том, что StorageFile представляет собой объект, соответствующий файлу, но не поток данных, посредством которого можно получать доступ к содержимому файла. Таким образом, когда вы вызываете методы вроде StorageFile.openAsync для получения потока, при этом файл открывается, и файл закрывается только при закрытии потока посредством его метода close.

    В вышеприведенном коде вы не увидите подобного вызова, так как и DataReader, и DataWriter заботятся о подобных деталях для вас, когда такие вызовы опущены. Однако если вы отделите поток от этих объектов посредством их методов detachStream, вы ответственны за вызов метода потока close .

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

    FileIO, PathIO и вспомогательные классы WinJS (а так же FileReader)

    Простота – это очень хорошо, если речь идет о файловых операциях ввода-вывода, и дизайнеры WinRT убедились в том, что наиболее распространенные сценарии не нуждаются в длинных цепочках асинхронных операций, которые мы видели в предыдущем разделе. Классы ) и ) предоставляют усовершенствованный интерфейс, а разница между ними заключается в том, что методы FileIO принимают параметр типа StorageFile, а методы PathIO принимают строковое имя файла. В остальном они имеют одинаковые методы, в частности, [read | write]BufferAsyn c (работают с байтовыми массивами), [append | read | write]LinesAsync (работают со строковыми массивами),и [append | read | write]TextAsync (работают с отдельными строками). В последнем случае класс WinJS.IOHelper предоставляет даже более простой интерфейс посредством своих методов readText и writeText.

    Посмотрим, как все это работает, начнем с нескольких образцов кода из примера "Доступ к файлу" (http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597). Сценарий 2 демонстрирует запись текстовой строки из элемента управления в файл (этот код упрощен, для большей понятности):

     var userContent = textArea.innerText;
    
    //sampleFile создается при старте с помощью Windows.Storage.KnownFolders.documentsLibrary.getFileAsync
    Windows.Storage.FileIO.writeTextAsync(sampleFile, userContent).done(function () {	
    outputDiv.innerHTML = "The following text was written to '" + sampleFile.name	
    + "':<br /><br />" + userContent;	
    });
    

    Для сравнения с кодом из предыдущего раздела, мы можем заменить все, что касается потоков и объекта DataWriter, одной строкой кода:

    tempFolder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting)
    .then(function (file) {	
    Windows.Storage.FileIO.writeTextAsync(file, contents).done();	
    })
     

    Чтобы сделать это еще проще, объект )) сокращает все до одной строки (которая является асинхронной операцией и возвращает promise-объект:

    WinJS.Application.temp.writeText(file, contents); 

    Чтение текста посредством асинхронного метода Если вам интересно, почему асинхронные методы, такие, как readText и writeText не имеют слова Async в своих названиях, это потому, что дизайнеры WinJS сознательно решили следовать существующим соглашениям об именам, принятых в JavaScript, где такой суффикс обычно не используется. API WinRT, с другой стороны, с другой стороны, не зависит от языков программирования, и имеет собственное соглашение об именовании, допускающее использование суффикса Async. . Тем не менее, эти вспомогательные функции WinJS доступны лишь для папок в AppData, но не для других областей файловой системы. Для работы с другими областями следует использовать классы FileIO и PathIO.

    Кроме того, вы можете пользоваться классом HTML5 ). Как следует из его названия (reader), он подходит только для чтения файлов и не обладает возможностью записи в них, но одно из его преимущества заключается в том, что он может работать не только с файлами, но и с большими двоичными объектами. Некоторые образцы подобных действий можно найти в примере "Использование больших двоичных объектов для сохранения и загрузки содержимого" (http://code.msdn.microsoft.com/windowsapps/Blob-Sample-0e35889e).

    Шифрование и сжатие

    WinRT предоставляет две возможности, которые может быть весьма полезны для управления состоянием приложения: шифрование и сжатие данных.

    Возможности шифрования предоставляют API ) и ). Первое содержит методы для базовых операций кодирования и декодирования (для форматов base64, hex, text). Второе занимается шифрованием в соответствии с различными алгоритмами. Как показано в примере "Сохранение секретных данных с помощью шифрования" (http://code.msdn.microsoft.com/windowsapps/Secret-Saver-f8a69623), данные обычно кодируют каким-либо образом с использованием метода Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary, а затем создают или получают алгоритм и передают его вместе с буфером данных методу Windows.Security.Cryptography.Core.CryptographicEngine.encrypt. Другие методы, такие как decrypt и convertBinaryToString, выполняют обратные операции.

    Механизмы сжатия выглядят немного проще, их единственная цель – предоставить встроенное API, с помощью которого можно уменьшить объем данных (например, для уменьшения размера перемещаемых данных). API для этих целей находится в ), оно включает в себя классы ). Хотя это API может использовать различные алгоритмы сжатия, включая алгоритм под названием MSZIP, оно не предоставляет средств для управления .ZIP-файлами и их содержимым. Для подобных целей вам понадобится либо использовать JavaScript-библиотеки сторонних производителей, либо написать WinRT-компонент на C# или VisualBasic, который может использовать API System.IO.Compression (смотрите Главу 5 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой").

    Использование API данных приложения для управления состоянием

    Сейчас, когда мы ознакомились с сущностью API, посмотрим, как их можно использовать для работы с различными видами данных приложения, а так же рассмотрим специальные соглашения, которые применимы в данной работе

    Состояние сеанса

    Как было описано выше, состояние сеанса это то, что приложение сохраняет при приостановке, и, таким образом, может восстановить свое состояние после того, как было остановлено системой и запущено снова. Единственный вариант развития подобных событий – это остановка приложения системой, поэтому все, что включают в состояние сеанса, всегда должно быть рассчитано на то, чтобы давать пользователю иллюзию непрерывной работы приложения. В некоторых случаях, как описано в лекции курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", вы можете, на самом деле, не восстанавливать это состояние, особенно, если приложение было остановлено в течение длительного времени и маловероятно, чтобы пользователь помнил, как все выглядело во время последнего сеанса работы. Это решение вам нужно будет принять для собственного приложения, от него зависит опыт взаимодействия пользователя и приложения.

    Состояние сеанса следует сохранять в папке данных приложения localFolder , или в объекте localSettings . Не следует сохранять его в области временных данных, так как пользователь может запустить средство очистки диска в то время, когда приложение приостановлено или остановлено, и в таком случае данне состояния сеанса будут удалены (смотрите следующий раздел).

    Объект WinJS sessionState самостоятельно создает файл, который называется _sessionState.json внутри localFolder. В этом файле хранится обычный текст в формате JSON, поэтому вы можете в любое время его просмотреть. Вы можете записать переменные сеанса работы в объект sessionState , в любое время, когда они изменяются, используя sessionState как пространство имен для этих переменных, и именно так следует поступать. При таком подходе эти значения сохраняются и перезагружаются автоматически, без необходимости управлять этими переменными где-либо еще.

    Если вам нужно сохранить дополнительные значения внутри sessionState , прежде чем данные будут записаны, сделайте это в обработчике WinJS.Application.oncheckpoint . Хороший пример подобных данных – это навигационный стек элементов управления страниц, который доступен посредством WinJS.Navigation.history . Так же вы можете скопировать эти данные в sessionState внутри метода PageControlNavigation.navigated (он находится в navigation.js и предоставляется шаблонами проектов). В любом случае, у WinJS есть собственный обработчик checkpoint, который всегда вызывается последним (после вашего обработчика) для того, чтобы убедиться, что любые изменения, которые вы внесли в sessionState после этого события, были сохранены.

    Если вы не используете объект WinJS sessionState , а просто используете API WinRT для работы с данными приложения, вы можете сохранять состояние сеанса в любое время (в том числе – в checkpoint ), и вам понадобится восстанавливать их в событии активации при выполнении условия previousExecutionState == terminated .

    Кроме того, хорошей практикой является обеспечение некоторой устойчивости в обработке состояния сеанса: если загруженные данные кажутся неподходящими или имеются другие проблемы, можно вернуться к данным сеанса по умолчанию. Помните так же, что вы можете использовать контейнер localSettings с взаимосвязанными параметрами, что гарантирует то, что группа значений будет сохраняться и извлекаться как единое целое. Так же может оказаться полезным при разработке иметь команду, которая дает вам возможность очищать состояние сеанса в том случае, если оно заполняется ненужными данными, но, в то же время, обычная деинсталляция приложения так же очищает состояние сеанса. В то же время, нет необходимости предоставлять пользователям команду для очищения состояния приложения: если ваше приложение не может запуститься после завершения, флаг previousExecutionState будет иметь состояние notRunning , когда пользователь в следующий раз попытается запустить приложение, в подобной ситуации вы не будете пытаться восстановить состояние.

    Кроме того, нет необходимости включать в состояние сеанса номер версии. Если пользователь установил обновление в то время, когда ваше приложение было приостановлено и остановлено, и версия данных приложения была изменена, значение previousExecutionState будет сброшено. Если по каким-либо причинам вы не изменяете версию данных приложения – например, если обновления весьма незначительны, тогда ранее сохраненные данные состояния приложения могут использоваться дальше. Но в данном случае перед нами – то же самое приложение, поэтому управление версиями состояния сеанса не требуется.

    Врезка: использование sessionStorage и localStorage HTML5

    Если хотите, вы можете использовать объект HTML5 localStorage для хранения данных состояния сеанса приложения и других данных приложения. Содержимое объекта хранится в папке localFolder . Содержимое localStorage не загружается до первой попытки доступа к нему и ограничено объемом в 10 Мб на приложение. API WinRT и WinJS, с другой стороны, ограничены лишь емкостью файловой системы.

    Что касается объекта HTML5 sessionStorage , он, на самом деле, не нужен, когда вы используете элементы управления страниц и поддерживаете общий контекст скрипта для этих страниц, так как переменные, находящиеся в памяти уже выполняют нужную функцию. Однако, если вы изменяете контекст страниц, используете ссылки <a> или document.location для целей навигации, sessionStorage способен быть полезным. Кроме того, вы можете кодировать информацию в URI, как обычно делается в веб-приложениях.

    И sessionStorage , и localStorage полезны внутри страниц iframe , исполняющихся в веб-контексте, так как API WinRT недоступны. В то же время, вы можете загрузить WinJS в веб-контекст (такая возможность поддерживается) и объекты WinJS.Application.local , roaming , и temp будут работать, используя буферы для данных, расположенные в памяти, вместо файловой системы.

    Локальное и временное состояние

    В отличие от состояния сеанса, которое восстанавливается лишь в особых обстоятельствах, локальное состояние приложения, которое состоит из этих параметров и других данных, всегда применяется при запуске приложения. Сюда попадает все, что пользователь может настроить, несмотря на то, что это так же часть перемещаемых данных, в таком случае эти данные так же загружаются при запуске приложения. Любые другие кэшированные данные, сохраненные результаты поиска, недавно использованные элементы, экранные элементы, предпочитаемые медиа-форматы, настройки, зависящие от устройства, так же попадают сюда. Коротко говоря, если какие-то данные не являются чистым состоянием сеанса, либо – частью перемещаемого состояния, это – либо локальное, либо временное состояние приложения. (Помните, что учетные данные следует хранить в Хранилище учетных данных вместо хранения их среди данных приложения).

    Те же API, которые мы видели, работают и для этих видов состояния, включая все API WinRT, объекты WinJS.Application.local и temp , и HTML localStorage . Так же вы можете использовать HTML5 API IndexedDB, SQLite, и HML App Cashe – это лишь другие формы локальных данных приложения.

    При работе с локальными и временными данными очень важно назначать им номер версии, так как они сохраняются и при обновлении приложения (хотя временное состояние в это время очищается). В процессе любого обновления приложения будьте готовы к тому, чтобы загрузить старую версию состояния приложения и выполнить необходимые обновления, или просто решить, что версия слишком стара и очистить данные (Windows.Storage.ApplicationData.current.clearAsync ), прежде чем задавать новые значения по умолчанию. Как упоминалось выше, возможно осуществить перенос состояния с использованием фоновой задачи (смотрите Главу 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой").

    Вообще говоря, локальные и временные данные приложения – это одно и то же – они имеют одинаковые API, и хранятся в папках, расположенных в одном и том же месте. Временные данные, однако, не поддерживают параметры и контейнеры параметров. Другое различие заключается в том, что содержимое в папке временных данных (вместе с HTML5-кэшем приложения) могут подвергнуться воздействию средства очистки диска Windows. Это означает, что временные данные могут исчезнуть в любой момент, когда пользователь захочет освободить немного дискового пространства. Так же вы можете использовать фоновую задачу с триггером обслуживания для самостоятельного выполнения очистки (опять же, смотрите Главу 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой").

    По этим причинам, временные данные следует использовать для хранения информации, которая оптимизирует производительность приложения, но не для данных, которые критически важны для работы приложения. Например, если в пакете приложения имеется JSON-файл, который вы обрабатываете или распаковываете при первом запуске программы, чтобы в дальнейшем приложение работало быстрее, и вы не выполняете никаких изменений этих данных из приложения, вы можете решить хранить это среди временных данных. То же самое справедливо для графических ресурсов, которые вы можете обработать для применения на конкретном устройстве, на котором исполняется приложение. Вы всегда можете повторить этот процесс, воспользовавшись исходным источником, таким образом, эти данные – так же хороший кандидат для хранения среди временных данных. Похожим образом, если вы получили данные из онлайнового сервиса для целей оптимизации производительности (таким образом, вы можете обновлять локальные данные инкрементно), вы всегда можете запросить их снова. Это особенно полезно для обеспечения возможности работы без подключения к сети, хотя в некоторых случаях может понадобиться предоставить пользователям выбрать, следует ли сохранять эту информацию среди локальных данных приложения или среди временных (параметр, который может появиться в интерфейсе чудо-кнопки Параметры вместе с командой, которая позволяет очистить кэш).

    Врезка: AppCache HTML5

    Приложения для Магазина Windows могут использовать кэш приложения HTML5 как часть стратегии кэширования и работы в оффлайновом режиме. Это особенно полезно в элементах веб-контекста iframe, где этот механизм можно использовать для любого содержимого. Например, приложение для чтения книг в онлайн-режиме может показывать содержимое в iframe, и если страницы включают теги кэша приложения, они будут сохраняться и будут доступны в режиме, когда сетевое соединение недоступно. В локальном контексте, кэш приложения работает для неисполняемых ресурсов, таких, как изображения, аудио, видео, но не для HTML или JavaScript.

    IndexedDB и другие технологии баз данных

    Многие виды локальных данных приложения прекрасно подходят для хранения в базе данных. В приложениях для Магазина Windows API IndexedDB доступно посредством объектов ), в справочных материалах по Indexed Database API (http://msdn.microsoft.com/library/windows/apps/hh466139.aspx) и в примере "IndexedDB" (http://code.msdn.microsoft.com/windowsapps/IndexedDB-sample-eb1e95af).

    Хотя база данных IndexedDB хранится среди локальных данных приложения, знайте, что существуют некоторые ограничения, так как нет средств, с помощью которых приложение или операционная система могут уменьшить размер файла базы данных и очистить неиспользуемое пространство:

  • У IndexedDB есть ограничение в 250 Мб на приложение и общий системный лимит в 375 Мб на жестких дисках меньше 32 Гб, или 4% (максимум – 20 Гб) на дисках, больше 32 Гб. Таким образом возможна ситуация, что ваше приложение может не иметь достаточно места для хранения данных, в подобном случае вам нужно иметь некий запасной механизм. (При превышении лимита API будет выдавать исключение "Quota Exceeded").
  • IndexedDB в Windows 8 не поддерживает составные ключи – таким образом, сейчас не поддерживается несколько значений для ключа или индекса (multientry).
  • По умолчанию, доступ к IndexedDB предоставляется только HTML-страницам, которые являются частью пакета приложения, и тем, которые объявлены как URI содержимого (смотрите раздел "Локальный и веб-контексты внутри хост-процесса приложения" Главы 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript"). Произвольные веб-страницы, которые могут быть загружены в iframe , не имеют доступа к IndexeDB, преимущественно для того, чтобы не занимать место в базе данных, объем которой ограничен 250 Мб и сохранить его для страниц приложения. Однако, вы можете предоставить произвольным страница доступ, включив следующий тег в домашнюю страницу и не устанавливая атрибут src элемента iframe до тех пор, пока не будет запущено событие DOMContentLoaded или activated :
    <meta name="ms-enable-external-database-usage" content="true"/> 
  • Помимо IndexedDB существуют и другие технологии баз данных, доступные для приложений Магазина Windows. Для создания локальных реляционных баз данных попробуйте SQLite. Это API, которое хорошо подходит для приложений, написанных на языке наподобие C#, как описано в блоге Тима Хейера (http://timheuer.com/blog/archive/2012/08/07/updated-how-to-using-sqlite-from-windows-store-apps.aspx), но, к счастью, есть и версия, которая называется SQL.js, где SQLite скомпилирован для JavaScript с использованием Emscripten (http://badassjs.com/post/18857332551/sql-js-sqlite-compiled-to-javascript-via-emscripten). Очень хорошо! В сообществе разработчиков можно найти и другие решения для JavaScript.

    Если вас беспокоят ограничения IndexedDB, вы можете воспользоваться API Win32 "Jet" или Extensible Storage Engine (ESE) (http://msdn.microsoft.com/library/windows/apps/br205753.aspx) (на них построена реализация IndexedDB). Для этого вам понадобится написать оболочку в виде компонента WinRT на C# или C++ (этому посвящена Глава 5 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой"), так как из JavaScript нельзя получить прямой доступ к этим API.

    То же самое справедливо для API баз данных сторонних разработчиков. До тех пор, пока они используют лишь API Win32, использование которых разрешено приложениям для Магазина Windows (они перечислены на странице "Win32 и COM для приложения Магазина Windows" (http://msdn.microsoft.com/library/windows/apps/br205757.aspx)), они отлично работают.

    Следует так же отметить, что Библиотека OData для JavaScript (http://www.odata.org/libraries#JavaScript) так же отлично работает с приложениями для Магазина Windows, реализуя доступ к онлайновым SQL-серверам, так как протокол OData работает посредством REST.

    И, наконец, еще одна возможность для организации данных, хранящихся в файлах, по которым можно организовать поиск, заключается в использовании системного индекса (system index) путем создания папки с именем "Indexed" в локальной папке данных приложения. Содержимое файлов в этой папке будет проиндексировано системной службой индексирования и к этому содержимому можно обращаться посредством запросов, использующих Advanced Query Syntax (AQS) с помощью API, описанного ниже в разделе "Расширенные возможности запросов к файлам". Так же вы можете осуществлять поиск, основанный на свойствах Windows (http://msdn.microsoft.com/library/windows/desktop/dd561977.aspx), делая такой подход простой альтернативой использования баз данных.

    Перемещаемое состояние

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

    Этот механизм работает очень просто. Во-первых,папка roamingFolder и контейнер roamingSettings ведут себя точно так же, как соответствующие локальные объекты. До тех пор, пока их общий размер не превышает Windows.Storage.ApplicationData.current.roamingStorageQuota , Windows будет копировать эти данные на другие устройства, на которых авторизовался тот же самый пользователь, и на которых установлено то же приложение. На самом деле, когда приложение установлено, Windows пытается скопировать перемещаемые данные, таким образом, они уже присутствуют при первом запуске приложения.

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

    Принятие решения о том, как должен выглядеть опыт взаимодействия пользователя с перемещаемым состоянием, это больше вопрос дизайна, чем разработки. Для этого нужно взять все параметры приложения, которые не зависят от аппаратного обеспечения устройства (такие, как параметры, связанные с размером экрана, с возможностями видео, с наличием периферийного оборудования или сенсоров) и подумать о том, имеет ли смысл перемещать тот или иной параметр. Списки избранного пользователя, например, подходят для перемещения, если они относятся к данным, которые не хранятся локально. Таким образом, избранные URI или элементы, расположенные в облачных хранилищах данных, таких, как SkyDrive, Facebook или Flickr подходят для перемещения, а списки избранного и недавно использованные файлы из локальных библиотек пользователя – не подходят. Позиция просмотра в видеофайле из облачного сервиса, наподобие потокового видео, так же может подойти для перемещения, так же, как и информация о месте, где пользователь остановился, читая журнал или книгу. Но, опять же, если данное содержимое локально, тогда, возможно – нет. Конфигурации учетных записей, наподобие параметров почтового ящика, так же часто хорошие кандидаты, таким образом пользователю не придется настраивать приложение снова на другом устройстве.

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

    Для того чтобы минимизировать размер перемещаемого состояния и не превышать квоту, вы можете задействовать API ), из материала "Основные принципы работы SkyDrive" (http://msdn.microsoft.com/library/live/hh826545.aspx) (здесь есть список поддерживаемых типов файлов), и из примера "PhotoSky" (http://msdn.microsoft.com/library/live/hh826545.aspx). Разъяснения, касающиеся этого и других сервисов Windows Live вы можете найти в блоге "Создание Windows 8", в материале "Реализация возможностей по работе с облаком в приложениях Windows 8 с помощью SkyDrive" (http://blogs.msdn.com/b/b8_ru/archive/2011/10/03/windows-8-skydrive.aspx).

    Сейчас, возможно, у вас есть множество других вопросов о том, как, на самом деле, работает перемещение данных: "Как часто синхронизируются данные", "Как можно управлять различными версиями данных?", "Что еще нужно об этом знать?". Это хорошие вопросы, и, к счастью, на них есть достойные ответы!

  • Учитывая наличие сетевого соединения, перемещаемое состояние на активном компьютере обновляется каждые 30 минут. Так же перемещение происходит немедленно, когда пользователь входит в систему или блокирует компьютер. Блокирование компьютера всегда – лучший способ инициировать синхронизацию с облаком. Обратите внимание на то, что если облачные сервисы знают лишь о пользователе (то есть, об учетной записи Microsoft), имеющем лишь одно устройство, синхронизация с облачным сервисом происходит лишь раз в день. Когда сервисы получают информацию о том, что у пользователя есть несколько устройств, синхронизация происходит каждые 30 минут. Если приложение деинсталлировано со всех компьютеров кроме одного, период синхронизации увеличивается.
  • При сохранении перемещаемого состояния вы можете записывать данные в любое время, например, при их изменении. Вам не нужно заботиться о групповой записи параметров, так как у Windows есть встроенный механизм для комбинирования изменений и уменьшения общей нагрузки на сеть.
  • Если у вас есть группа параметров, которая по объективным причинам должна перемещаться как единое целое, реализуйте ее в виде взаимосвязанных параметров в контейнере roamingSettings .
  • В случае с файлами, созданными внутри roamingFolder , они не будут перемещаться до тех пор, пока они открыты для записи (то есть, до тех пор, пока открыты потоки, связанные с ними). Полезно проверить, закрыты ли все потоки при приостановке приложения.
  • Windows позволяет всем приложениям иметь до 8 Кб параметров с "высоким приоритетом", которые будут перемещены в течение одной минуты, таким образом, экземпляры приложения на нескольких устройствах оказываются лучше синхронизированными. Для того, чтобы это использовать, создайте отдельный параметр или группу взаимосвязанных параметров в корневой части roamingSettings и дайте этому объекту имя HighPriority, таким образом, мы получим roamingSettings.values["HighPriority"] (контейнер с этим именем будет перемещаться обычным образом). До тех пор, пока размер этого параметра не превышает 8 Кб, он будет перемещаться в течение минуты после изменения. Если размер будет превышен, он будет перемещаться с обычным приоритетом. Демонстрацию этого вы можете найти в Сценарии 6 примера "Данные приложения".
  • На доверенном компьютере, параметры пользователя общеситемного значения, наподобие конфигурации начальной страницы, автоматически перемещаются независимо от приложений. Они так же включают в себя зашифрованные учетные данные, которые приложения записали в хранилище учетных данных. Приложениям никогда не следует пытаться перемещать пароли. Приложения, которые создают дополнительные плитки (как мы увидим в лекции 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой") могут указать, следует ли копировать эти плитки на новое устройство при установке на него приложения.
  • Когда существует несколько версий данных приложения, используемых одним и тем же приложением (с несколькими версиями приложения, конечно), Windows будет управлять каждой версией данных приложения раздельно, что означает, что более новые данные приложения не переместятся на устройство с более старой версией приложения. В свете этого, полезно не применять слишком агрессивное изменение версий данных приложения, так как это может прервать связь между приложениями.
  • Облачные сервисы хранят несколько версий перемещаемых данных приложения до тех пор, пока множество версий приложения используются в рамках одной и той же учетной записи Microsoft. Только когда все экземпляры приложения будут обновлены, старая версия данных может быть удалена.
  • Когда обновленное приложение воспринимает старую версию перемещаемого состояния, ему следует загрузить его как старую версию, но сохранить – как новую и вызвать setVersionAsync .
  • Избегайте использования дополнительной схемы назначения версий внутри перемещаемого состояния, как, например, внесение структурных изменений без изменения версии данных приложения посредством setVersionAsync . Так как облачный сервис управляет перемещаемыми состояниями, основываясь на номере их версии, и так как последние записанные данные выигрывают, некоторые версии приложения, которые ожидают некоторых дополнительных данных, и, на самом деле, сохраняют эти данные, могут обнаружить, что эти данные были удалены, так как немного более старые версии приложения их не записали.
  • Даже если все экземпляры приложения были удалены с устройств пользователя, облачный сервис хранит перемещаемые данные в течение "разумного срока" (около 30 дней), таким образом, если пользователь переустановит приложение в течение этого периода, он обнаружит, что ранее заданные параметры сохранились. Для того чтобы избежать этого и явным образом удалить перемещаемое состояние из облака, воспользуйтесь методом clearAsync .
  • Панель параметров и пользовательский интерфейс

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

    Когда пользователь нажимает на чудо-кнопку Параметры (это можно сделать и напрямую, использовав комбинацию клавиш Win + i), Windows отображает панель параметров – часть пользовательского интерфейса, которая заполнена различными командами для настройки параметров, а так же, в нижней части – системными настройками. Приложения могут добавлять собственные команды для настройки параметров, но не обязаны этого делать. Windows гарантирует, что какие-то настройки для приложения всегда будут присутствовать на этой панели: она автоматически показывает названия приложения и разработчика, команду "Отзывы и оценки", которая ведет к странице приложения в Магазине Windows, команду "Обновить", если обновление для приложения доступно в Магазине Windows, и команду "Разрешения", если приложение объявило какие-либо возможности в манифесте. (Обратите внимание на то, что команда "Отзывы и оценки" не отображается, если приложение запущено из Visual Studio, так как эта возможность предоставляется Магазином Windows).

    Чудо-кнопка Параметры доступна всегда, независимо от места в приложении, где вы находились, поэтому нет нужды думать о реализации подобной команды в панели приложения, не нужна подобная команда и на холсте приложения. Тем не менее, вы можете программно активировать чудо-кнопку Параметры, когда, например, вы обнаружили, что какая-то возможность выключена и оповещаете об этом пользователя. Вы можете задать ему вопрос наподобие: "Вы хотите включить функцию определения местоположения для этого приложения?", и если он ответит "Да", вы можете активировать чудо-кнопку Параметры. Это делается посредством объекта панели параметров, полученного из ), метод show которого отображает пользовательский интерфейс (или выдает исключение, если приложение находится в прикрепленном режиме просмотра, или не является приложением переднего плана, поэтому не выполняйте подобный вызов при таких обстоятельствах!). Свойство edge объекта панели параметров сообщает вам о том, с левой или с правой стороны экрана находится панель, в зависимости от ориентации интерфейса системы слева направо или справа налево (зависит от региональных установок).

    Теперь мы рассмотрели все методы и свойства этого объекта! Гораздо более интересная часть нашего рассказа посвящена тому, как можно добавлять собственные команды на панель параметров. Но сначала давайте посмотрим на руководство по использованию панели параметров.

    Руководства по дизайну панели параметров

    Помимо команд, которые Windows автоматически добавляет на панель параметров, приложение может самостоятельно добавить туда до восьми команд, обычно – около четырех. Все, что больше восьми, вызовет исключение. Так как параметры глобальны для приложения, команды, которые вы добавляете, никогда не меняются: они не чувствительны к контексту. Другими словами, на панели параметров располагают только те команды, которые воздействуют на приложение в целом. Команды, применимые лишь к определенным страницам или контексту внутри страниц, следует размещать на панели приложения или на полотне. Некоторые примеры команд верхнего уровня на панели приложения показаны на рис. 2.2. (рис 2.2) Примеры команд верхнего уровня на панели параметров. Обратите внимание на то, что нижняя часть панели всегда занята системными параметрами, а названия приложения и разработчика всегда расположены сверху. Команды "Разрешения" и "Оценки и отзывы" добавляются автоматически

    Каждая команда, предоставленная приложением, может выполнять одно из двух действий. Во-первых, эта команда может быть обычной гиперссылкой, которая ведет к страницам приложения "Справка", "Соглашение о конфиденциальности", "Условия использования", "Лицензионное соглашение" и так далее, по нажатию на которую соответствующая страница будет открыта в браузере. Другая возможность заключается в том, что команда вызывает дополнительную всплывающую панель со специализированными элементами управления, или просто iframe для отображения веб-содержимого. Вы можете реализовать страницы "Помощь", "Условия использования" и другое текстовое содержимое обоими способами вместо того, чтобы переключаться в браузер.

    Примечание. Как указано в "Сертификационных требованиях к приложениям для Windows 8" (http://msdn.microsoft.com/library/windows/apps/hh694083.aspx), в разделе 4.1., приложения, которые тем или иным образом собирает персональные данные, должны иметь политику конфиденциальности или соответствующее заявление. Это должно быть, как минимум, отражено на странице описания приложения в Магазине Windows. Хотя это и не требуется, подразумевается, что вы так же включите в панель приложения соответствующую команду.

    Дополнительные всплывающие элементы создают с помощью элемента управления WinJS.UI.SettingsFlyout . На рис. 2.3. есть примеры. Обратите внимание на то, что дополнительные панели параметров бывают двух размеров: узкая (346 пикселей) и широкая (646 пикселей). Руководства по дизайну предлагают делать все дополнительные панели параметров приложения одного размера – то есть, не делать некоторые из них узкими, а некоторые – широкими. В любом случае, у вас будет лишь пара подобных панелей, так что это не должно превратиться в проблему. Кроме того, обратите внимание на о, что всплывающий элемент Разрешения (Permissions), показанный в левой части На рис. 2.3. предоставляется Windows автоматически и он настроен в соответствии с возможностями, заявленными в манифесте. Некоторыми возможностями, наподобие определения местоположения, можно управлять из этой панели. Другие, наподобие доступа к Интернету и к библиотекам, просто перечислены, так как пользователь не может включать или выключать их. (рис 2.3) Примеры дополнительных панелей параметров в приложениях Windows 8 Travel, Weather, News и Music. Первые три – узкие, четвертая – широкая. Обратите внимание на то, что каждая из панелей, предоставленная приложением, соответствующим образом брендирована и имеет кнопку "Назад", ведущую к основной панели параметров. Панель Разрешения (Permissions) предоставлена системой, и, таким образом, отражает системную тему. Ее нельзя настроить.

    Обычно используемые здесь группы параметров – это те, которые позволяют пользователю настроить особенности перемещения данных приложения – то есть, группа параметров, которая определяет, какие данные состояния приложения перемещаются (это можно увидеть, выполнив команду Изменение параметров компьютера > Синхронизация параметров (PC Settings > Sync You Settings)). Кроме того, рекомендуется включать в панель параметров команды управления учетной записью/профилем, так же как и возможности по входу и выходу. Как отмечено в лекции 1, вход в приложение и лицензионное соглашение, которые необходимы для продолжения работы следует показать при запуске приложения. Для текущих возможностей, связанных со входом в приложение, для просмотра лицензионного соглашения и так далее, создайте соответствующие команды и панели в интерфейсе чудо-кнопки Параметры. Обратитесь к материалу "Руководство и контрольный список для элементов управления входом" (http://msdn.microsoft.com/library/windows/apps/hh965453.aspx) для получения более подробных сведений по этому вопросу. Руководство по добавлению справки можно найти в материале "Добавление справки по приложению" (http://msdn.microsoft.com/library/windows/apps/hh465043.aspx).

    В плане поведения, дополнительные панели автоматически скрываются, когда они неактивны, но так же имеют заголовок с кнопкой "Назад" для возврата на основную панель параметров со всеми командами. Из-за возможности автоматического скрытия, изменения, которые вносят на панелях, применяются немедленно: здесь нет кнопок "OK" или "Применить" или чего-то подобного. Если пользователь хочет вернуться к прежнему варианту настроек, ему следует просто восстановить исходные параметры.

    По этой причине, хорошо использовать простые элементы управления, которые легко переключить в прежнее состояние, вместо сложных наборов элементов управления, которые сложнее вернуть к исходному виду. Рекомендовано использовать тумблеры для параметров, имеющих значения включено/выключено (вместо флагов), кнопки для выполнения некоторых действий (но без закрытия панели параметров), гиперссылки (для открытия браузера), текстовые поля ввода (следует задать им соответствующий тип – адрес электронной почты (email address), пароль (password) и так далее), переключатели для групп, включающих в себя до пяти взаимоисключающих элементов, и списки (элемент select) для четырех-шести текстовых элементов.

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

    Вот еще некоторые вещи, которых надо избегать, работая с панелью параметров:

  • Не используйте панель параметров для размещения команд, имеющих отношение к рабочему процессу. Они должны располагаться на панели приложения, или на полотне, как показано в лекции 1.
  • Не используйте команды верхнего уровня в панели параметров для выполнения действий, которые не относятся к связи с другим приложениям (как в случае с браузером). Таким образом, команды верхнего уровня никогда не следует использовать для выполнения каких-либо действий внутри приложения.
  • Не используйте команды панели параметров для навигации по приложению.
  • Не используйте элемент управления WinJS.UI.SettingsFlyout как обычный элемент управления.
  • Теперь давайте посмотрим на то, как соответствующим образом использовать чудо-кнопку Параметры и элемент управления SettingsFlyout.

    Расположение команд на панели параметров

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

    Есть два пути реализации этого в приложениях, написанных на HTML и JavaScript: использовать WinRT напрямую, или применить вспомогательные функции WinRT. Рассмотрим это на примере простой команды Справка (Help).

    Для того чтобы знать, когда чудо-кнопка активируется посредством WinRT, получим объект панели параметров из ) и добавим прослушиватель для его события commandsrequested (это событие WinRT, поэтому удостоверьтесь в том, что прослушиватель, если это необходимо, удален):

    // Переменная n здесь – это удобное краткое имя	
    var n = Windows.UI.ApplicationSettings;	
    var settingsPane = n.SettingsPane.getForCurrentView();	
    settingsPane.addEventListener("commandsrequested", onCommandsRequested);
     

    В обработчике события создадим объект ) для каждой команды, где каждая команда имеет свойства id, label, и функцию invoked, которая вызывается, когда пользователь коснулся элемента команды или щелкнул по нему мышью. Все это может быть задано в конструкторе, как показано ниже:

    function onCommandsRequested(e) {
    // n все еще является кратким именем для Windows.UI.ApplicationSettings
    var commandHelp = new n.SettingsCommand("help", "Help", helpCommandInvoked);
    e.request.applicationCommands.append(commandHelp);
    }	
     

    Вторая строка кода – это место, где вы затем добавляете подобные команды на панель параметров. Это выполняется путем присоединения их к объекту ). Этот объект – конструкция WinRT, которая называется вектор (vector) и используется для управления коллекцией элементов с помощью команд наподобие append и insertAt. В данном случае у нас есть вектор объектов SettingsCommand, как вы можете видеть выше, к нему довольно просто присоединять команды. Подобный вызов выполняется для каждой команды, можно и передать массив команд методу replaceAll вместо метода append. То, что потом происходит в обработчике invoked для каждой команды, весьма интересно, и мы вернемся к этому в следующем разделе.

    Кроме того, вы можете заранее заполнить вектор ) показывает пример подобного подхода, который я модифицировал здесь для того, чтобы показать использование replaceAll:

    var n = Windows.UI.ApplicationSettings;
    var settingsPane = n.SettingsPane.getForCurrentView();
    var vector = settingsPane.applicationCommands;
    
    //Гарантирует отсутствие заданных команд в интерфейсе чудо-кнопки Параметры 
    vector.clear();
    
    var commands = [ new settingsSample.SettingsCommand("Custom.Help", "Help", OnHelp),
    new n.SettingsCommand("Custom.Parameters", "Parameters", OnParameters)];
    vector.replaceAll(commands);
     

    При таком подходе вам не нужно добавлять прослушиватель для commandsrequested или напрямую обрабатывать это событие.

    Теперь, так как большинство приложений, вероятнее всего, будет использовать некоторое количество настроек, WinJS предоставляет несколько вспомогательных механизмов для всего процесса. Во-первых, вместо прослушивания события WinRT, можно просто назначить обработчик для WinJS.Application.onsettings (это – контейнер для commandsrequested):

    WinJS.Application.onsettings = function (e) {
    // ...
    };
     

    В вашем обработчике, создайте JSON-объект, описывающий ваши команды и сохраните этот объект в )):

    WinJS.Application.onsettings = function (e) {	
    e.detail.applicationcommands =	
    { "help": { title: "Help", href: "/html/2-SettingsFlyout-Help.html" } };
    WinJS.UI.SettingsFlyout.populateSettings(e);	
    };
     

    Метод populateSettings обходит объект e.details.applicationcommands и вызывает метод WinRT applicationCommands.append для каждого элемента. Это предоставляет вам более компактный способ для выполнения тех же действий, что вы выполняли с помощью WinRT и так же упрощает реализацию команд параметров, как мы увидим ниже.

    Примечание. Вспомогательные функции WinJS специально разработаны для создания элемента управления SettingsFlyout, заполненного из HTML-файла, который вы указываете в свойстве href. Это свойство должно ссылаться на содержимое, находящееся в пакете приложения; его нельзя использовать для создания элементов управления параметров, которые осуществляют переход по URI (что обычно используется для команд "Условия предоставления услуг" и "Заявление о конфиденциальности"). В подобных случаях вы должны использовать API WinRT напрямую вместе с WinJS.UI.SettingsFlyout.populateSettings. Опять же, это просто – поместить веб-содержимое прямо во всплывающий элемент параметров с помощью iframe, который поддерживает параметры в соответствии с опытом использования приложения.

    Реализация команд: ссылки и всплывающие элементы параметров

    С технической точки зрения внутри функции invoked команды параметров вы можете делать все, что угодно. Правда! Конечно, как описано выше в руководстве по дизайну, есть рекомендации, касающиеся того, как следует и как не следует использовать эти команды. Например, команды в панели параметров не должны действовать как команды панели приложения, которые воздействуют на содержимое, их не следует использовать для навигации внутри приложения. В идеальном варианте эти команды выполняют одну из двух функций: либо открывают гиперссылки (в браузере), либо отображают дополнительные панели параметров.

    На базе модели параметров WinRT, при открытии гиперссылки используется API x) как показано ниже:

    function helpCommandInvoked(e) {	
    var uri = new Windows.Foundation.Uri("http://example.domain.com/help.html"); 
    Windows.System.Launcher.launchUriAsync(uri).done();	
    }	
     

    Во втором случае дополнительные панели реализуются с помощью элемента управления ). Опять же, с технической точки зрения, вы не обязаны использовать этот элемент управления: вы можете отобразить в обработчике Как насчет краткой комбинации из четырех имен событий? Стоит так же отметить, что будет срабатывать событие document.body.DOMNodeInserted, когда всплывающий элемент будет появляться. и имеет другие полезные возможности. И хотя вы можете поместить любой HTML-код в элемент управления, включая другие элементы управления, и обычный всплывающий элемент поддерживает вертикальную прокрутку, на самом деле нет причин не использовать его.

    Так как он является элементом управления WinJS, вы можете объявить ) содержит следующий всплывающий элемент, отображающий справку (здесь текстовое содержимое опущено, код немного переформатирован), в результате получается то, что показано на рис. 2.4.

    <div data-win-control="WinJS.UI.SettingsFlyout" aria-label="Help settings flyout" 
     data-win-options="{settingsCommandId:'help', width:'wide'}">
    <!-- Используем либо 'win-ui-light' либо 'win-ui-dark' в зависимости от различия
    цвета заголовка и фона; фоновый цвет отражает индивидуальность приложения -->
    <div class="win-ui-dark win-header" style="background-color:#00b2f0">
    <button type="button" onclick="WinJS.UI.SettingsFlyout.show()" class="win-backbutton"></button>
    <div class="win-label">Help</div>
    <img src="../images/smallTile-sdk.png" style="position: absolute; right: 40px;"/>
    </div>
    <div class="win-content ">
    <div class="win-settings-section">
    <h3>Settings charm usage guidelines summary</h3>
    <!-- Другое содержимое опущено -->
    <li>For more in-depth usage guidance, refer to the
    <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh770544"> 
     App settings UX guide</a>.</li>
    </div>
    </div>
    </div>
    

    Как всегда, у этого элемента управления есть параметры, так же, как и несколько применимых классов стилей win-*. Есть два параметра, это settingCommandId, идентификатор элемента, назначение которого очевидно, и width, который может принимать значения 'narrow' или 'wide'. И тот и другой присутствуют в вышеприведенном примере. Здесь применены стили win-settingsflyout, который задает стиль всего элемента управления (обычно не используется, за исключением основы для других правил стиля), а так же win-ui-light и win-ui-dark, которые применяют темную или светлую тему к частям всплывающего элемента. В данном примере использована темная тема для заголовка, в то время как остальные части элемента управления стилизованы с помощью светлой темы по умолчанию. (рис 2.4) Всплывающий элемент среди параметров, отображающий справку (обрезанный вертикально) из Сценария 2 примера о "Параметры приложения". Обратите внимание на гиперссылку в правом нижнем углу

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

    Как мы показываем этот всплывающий элемент, когда активирована команда верхнего уровня на панели параметров? Самый простой способ – позволить WinJS позаботиться о деталях, используя сведения, которые вы предоставили для WinJS.UI.SettingsFlyout.populateSettings. Вот пример, снова из Сценария 2, который мы видели в предыдущем разделе:

    e.detail.applicationcommands =	
    { "help": { title: "Help", href: "/html/2-SettingsFlyout-Help.html" } };
    WinJS.UI.SettingsFlyout.populateSettings(e);
    };
     

    В JSON-коде, который вы назначили applicationCommand, каждый объект определяет и команду и связанный с ней всплывающий элемент. Имя объекта – это id всплывающего элемента ("help"), его свойство title задает надпись для команды верхнего уровня на панели параметров ("Help"), свойство href задает HTML-страницу, где описан всплывающий элемент с заданным id ("/html/2-SettingsFlyout-Help.html").

    Используя эту информацию, WinJS может и заполнить панель параметров верхнего уровня, и обеспечить автоматическую активацию нужного всплывающего элемента (вызывая WinJS.UI.Process для этого), и вам не нужно писать для этого какой-либо код. Поэтому в сценариях примера вы не увидите явного вызова showSettings, а лишь вызовы populateSettings.

    Вызов всплывающего элемента параметров из программного кода

    Посмотрим теперь на то, что происходит внутри описываемых процессов. В дополнении к элементу управления, который используется для определения конкретного всплывающего элемента, ) отображает панель параметров Windows верхнего уровня – то есть - Windows.UI.ApplicationSettings.SettingsPane. Поэтому вы можете видеть, что событие click кнопки "Назад" в вышеприведенной разметке привязано напрямую к методу show, так как нажатие на кнопку "Назад" должно возвратить нас к интерфейсу верхнего уровня.

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

    Метод ), с другой стороны, показывает конкретный всплывающий элемент настроек, который определен где-то в приложении. Сигнатура метода выглядит как showSettings(<id> [, <page>]) , где <id> идентифицирует всплывающий элемент, который вам нужен, и необязательный параметр <page> указывает на HTML-документ, в котором следует искать всплывающий элемент с заданным <id> , который не найден в текущем документе. Таким образом, showSettings всегда начинает с просмотра текущего объекта document на предмет элемента WinJS.UI.SettingsFlyout, который имеет совпадающее с заданным свойство settingsCommandId или HTML-атрибут id. Если подобный всплывающий элемент найден, он показывается.

    Если разметка в предыдущем разделе (с рис. 2.4.) содержится в той же HTML-странице, которая загружена в приложении, следующая строка кода покажет этот всплывающий элемент:

    WinJS.UI.SettingsFlyout.showSettings("help"); 

    В подобном случае вы так же можете опустить часть href JSON-объекта, который передается в populateCommands, но только если всплывающий элемент уже содержится в текущем HTML-документе.

    Параметр <page>, в свою очередь, позволяет вам разделить всплывающие элементы параметров и остальные страницы приложения. Его значение – это относительный URI, относящийся к пакету приложения. В примере "Параметры приложения" подобный подход используется для помещения всплывающих элементов для каждого сценария в отдельный HTML-файл. Вы так же можете поместить все ваши всплывающие элементы в один HTML-файл, до тех пор, пока они имеют уникальные id. В любом случае, если вы предоставляете параметр <page>, showSettings загрузит код указанного HTML-файла в текущую страницу, используя WinJS.UI.Page.load (который вызовет WinJS.UI.processAll), просматривает полученное дерево DOM на предмет id всплывающего элемента, совпадающего с заданным <id> и показывает его. Если всплывающий элемент найти не удается, вызывается исключение.

    Сценарий 5 примера показывает этот способ программной активации элемента. Это так же хороший пример (рис. 2.5.) всплывающего элемента с вертикальной прокруткой:

     WinJS.UI.SettingsFlyout.showSettings("defaults", "/html/5-SettingsFlyout-Settings.html");

    (рис 2.5) Всплывающий элемент настроек из Сценария 5 примера "Параметры приложения", показывающий, как всплывающие элементы поддерживают вертикальную прокрутку. Обратите внимание на позицию полосы прокрутки при отображении верхней части элемента (слева), и нижней (справа)

    Вызов showSettings, таким образом, это то, что используется в любом обработчике invoked команды, и то, что WinJS выполняет внутри populateCommands. Но это так же означает, что вы можете вызвать showSettings из любого места вашего кода, когда вам нужно показать конкретную панель параметров. Например, если вы столкнулись с ошибкой, с которой можно справиться, изменив параметры приложения, вы можете предоставить в сообщении об этом кнопку, которая вызывает showSettings для открытия конкретной панели. И, если это нужно, метод hide всплывающего элемента может скрыть его. Это не действует на панель параметров верхнего уровня, для скрытия которой нужно использовать Windows.UI.ApplicationSettings.SettingsPane.getForCurrentView.hide.

    Вы можете использовать showSettings и hide вместе, на самом деле, если вам нужно организовать перемещение к панелям параметров третьего уровня. Таким образом, одна из ваших собственных панелей параметров может содержать, команду, которая вызывает hide для текущего всплывающего элемента, и затем – showSettings для открытия другого. Кнопка "Назад" этого дополнительного элемента (у них всегда должна быть такая кнопка), похожим образом, вызывает hide для текущего элемента, и showSettings для того, чтобы всплывающий элемент второго уровня снова появился. Тем не менее, мы не рекомендуем делать ваши параметры настолько сложными, чтобы понадобились всплывающие элементы третьего уровня, но такая возможность есть, если у вас есть необходимость в подобном.

    Зная о том, как showSettings ищет всплывающий элемент так же полезно, если вы хотите программно создать элемент WinJS.UI.SettingsFlyout. До тех пор, пока подобный элемент управления находится в DOM, когда вы вызываете showSettings с его id, WinJS может найти его и отобразить, как и другие элементы. Подобный подход так же работает, хотя я не пробовал это сделать и не подготовил соответствующего примера, использующего такой гибридный подход. Так как showSettings загружает заданную HTML-страницу как элемент управления страницы с помощью WinJS.UI.Pages.load, эта страница так же может включать собственный скрипт, в котором вы можете задать объект элемента управления страницы с помощью методов вроде processed и ready. В этих методах вы, затем, можете выполнить необходимые настройки всплывающих элементов настроек, заданных в разметке.

    Врезка: Изменение разрешений

    Обычный вопрос, который связан с параметрами, заключается в том, может ли приложение получить событие, когда пользователь меняет параметры на панели Разрешения. Ответ на этот вопрос отрицательный. Что означает, что вы можете понять, что доступ к какой-то возможности закрыт, либо обрабатывая исключение Access Denied (Доступ запрещен), когда пытаетесь воспользоваться той или иной возможностью. Вам всегда следует обрабатывать ошибки отказа в доступе, так как пользователь может запретить доступ к возможности при первой попытке использования соответствующего API. Когда это происходит, вы отображаете сообщение об отключенных разрешениях (как показано на примере приложения "Here My Am!" в лекции 1) и предоставляете некоторые интерфейсные элементы для выполнения нужной операции. Однако, пользователю все еще нужно самостоятельно активировать команду Разрешения. Дополнительные подробности вы можете узнать в материале "Руководство для устройств, осуществляющих доступ к персональным данным" (http://msdn.microsoft.com/library/windows/apps/Hh768223.aspx).

    Данные пользователя: библиотеки, средства выбора файлов и файловые запросы

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

    Наша первая задача, касающаяся пользовательских данных, заключается в том, чтобы решить, где их разместить, и как получить к ним доступ. Реализация этой задачи включает в себя различные библиотеки пользовательских данных, съемные носители информации и средства выбора файлов. Использование кэша прав доступа так же важно, так как позволяет запоминать факты предоставления пользователем доступа к файлу или папке, к которым мы, в обычных условиях, не имеем программного доступа. Хорошая новость обо всех этих папках и файлах заключается в том, что работа с ними происходит с помощью те же классов StorageFolder и StorageFile, с которыми мы уже знакомы. Другая важная тема, которую мы рассмотрим, касается использования файловых запросов – наиболее богатого возможностями способа для перечисления содержимого папок и библиотек, которое предоставляет возможности для качественного визуального представления данных в элементах управления наподобие ListView.

    Как мы уже видели, приложения для Магазина Windows, по умолчанию, имеют доступ лишь к собственному пакету и к папкам данных приложения. Это означает, что по умолчанию у приложения нет доступа к типичным местам хранения пользовательских файлов! Есть два способа для предоставления такого доступа:

  • Объявить возможность доступа к библиотеке в манифесте.
  • Позволить пользователю выбрать расположение посредством средства выбора файлов (File Picker).
  • Посмотрим сначала на средство выбора файлов, так как во многих случаях это все, что, на самом деле, вам понадобится! Но есть и другие сценарии, такие, как приложения, ориентированные на работу с библиотеками – при реализации которых вам нужен прямой доступ к библиотекам. Для этих целей в манифесте предусмотрено пять функциональных возможностей, как показано слева на рис. 2.6. Три из них, Библиотека музыки (Music Library), Библиотека изображений (Pictures Library) и Библиотека видео (Video Library) – предоставляют полный доступ для чтения и записи к пользовательским папкам музыки, изображений и видео. Информация об этих возможностях на странице информации о приложении в Магазине Windows и на панели параметров Разрешения, но пользователь не может управлять ими при исполнении программы. Конечно, если не вполне очевидно, зачем вы объявили эти возможности, убедитесь в том, что вы пояснили это на странице сведений о приложении. Что касается возможностей Библиотека документов (Documents Library) и Съемные носители (Removable Storage), просто объявить эти возможности недостаточно: вам так же нужно задать сопоставление с конкретными типами файлов, которыми ограничено приложение. (Возможность Библиотека документов (Documents Library) предназначена только для приложений, которые нуждаются в открытии встроенного содержимого в другом документе). (рис 2.6) Возможности, связанные с данными пользователя в редакторе манифеста (слева), и редакторе сопоставления типов файлов (справа). Обратите внимание на красный знак "Х", который появляется на панели Возможности (Capabilities), когда необходимы дополнительные объявления, связанные с выбранной возможностью. Красный X на панели Объявления (Declarations) показывает, что введенная информация пока не полна.

    Врезка: API фоновой передачи данных

    Тема, которая относится к пользовательским данным, но которую мы не будем раскрывать в подробностях до Главы 3 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", это API WinRT ). Это API позволяет вам выполнять загрузку или отправку файлов независимо от жизненного цикла приложения – то есть – делать это, когда приложение выполняется, приостановлено или полностью остановлено. Это API существует потому, что передача больших файлов на сетевые ресурсы и с них, является обычной потребностью приложений, но при подобной передаче само приложение может и не исполняться в фоновом режиме и не потреблять электроэнергию. Вместо этого приложение настраивает задачу передачи данных с помощью системных средств, и эта задача будет исполняться даже если приложение будет закрыто. Когда приложение будет запущено снова, оно может проверить статус выполнения этой задачи.

    Использование средства выбора файлов

    Хотя словосочетание "Средство выбора файлов" звучит не особенно шикарно, это, по-моему, одна из самых замечательных возможностей Windows 8. "Подождите минуту!", - скажете вы, "Как, элемент пользовательского интерфейса может выбирать папки и файлы. Да, это здорово!". Причина заключается в том, что используя это средство пользователь может просматривать и выбирать любые данные. Это не только то, что хранится в локальной файловой системе или в локальных сетевых хранилищах, но и те данные, которые доступны благодаря так называемым поставщикам выбора файлов (file picker providers). Эти приложения обычно содержат библиотеки данных, которые в противном случае были бы расположены на веб-сервисе, внутри собственной базы данных приложения, или даже предоставляют файлы, создаваемые по запросу, и предоставляют к ним доступ как к части локальной файловой системы.

    Немного подумайте об этом (как я предлагал вам сделать в лекции 1 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript"). Когда вы хотите поработать с изображением с фото-сервиса, наподобие Flickr или Picasa, что вы обычно делаете? Первым шагом является загрузка нужного файла и сохранение его в локальной файловой системе с помощью некоторого приложения, которое предоставляет вам интерфейс к веб-сервису (это может быть веб-приложение). Затем вы можете выполнить желаемые правки и модификации, после чего обычно нужно снова загрузить файл в сервис. На самом деле, все не так уж и плохо, за исключением того, что вы тратите время на переключение между разными приложениями, и, очевидно, загрязняете систему множеством временных файлов, взаимоотношения которых с вашими файлами в Интернете скоро будут забыты.

    Если у вас есть поставщик выбора файлов, который позволяет получать прямой доступ к подобным файлам, и для записи, и для чтения, все эти дополнительные шаги становятся ненужными, равно как и становится ненужным переключение между приложениями. Это означает, что поставщик выбора файлов фото-сервиса открывает другим приложениям возможность загружать, править и сохранять онлайновое содержимое так, как если бы оно находилось в локальной файловой системе. Приложениям, принимающим данные, не нужно ничего знать о подобных веб-сервисах, и они автоматически получают доступ к тем большему количеству сервисов, чем больше приложений-поставщиков будет установлено. Более того, поставщики могут представлять данные, которые обычно не хранятся в виде файлов так, если бы они были файлами. Например, приложение Camera (Камера) в Windows 8 – это поставщик выбора файлов, который позволяет вам активировать камеру, сделать снимок и затем возвращает этот снимок так, если бы он был взят из файловой системы. Все это дает пользователям естественные средства для работы с данными, и неважно, где эти файлы расположены. Как я и сказал, я думаю, что это – замечательная возможность!

    Мы поговорим подробнее о поставщиках выбора файлов в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой". Наша более близкая цель заключается в изучении средств выбора файлов для получения объектов StorageFile или StorageFolder.

    Пользовательский интерфейс средства выбора файлов

    Прежде чем смотреть на код, познакомимся поближе с пользовательским интерфейсом средства выбора файлов. Когда средство запущено, вы увидите его полноэкранное представление ( рис. 2.7), которое представляет средство выбора файлов в режиме выбора одного элемента, данные отображаются в виде миниатюр. В подобном режиме просмотра элементы отображаются в виде значков в элементе управления ListView, со всплывающим элементом управления, содержащим подробную информацию, который появляется, когда указатель мыши зависает над элементом. В некотором смысле, средство выбора файлов похож на приложение, запущенное для определенных целей, и оно создано для того, чтобы быть привлекательным и иммерсивным, как и прочие приложения для Магазина Windows.

    На рис. 2.7. заголовок Pictures (Изображения) показывает текущее расположение, открытое в средстве выбора файлов. Выпадающий список Sort By Name (Сортировать по имени) позволяет вам выбирать другие критерии сортировки, так же, как выпадающий список в области заголовка Files (Файлы) позволяет вам выбирать другое расположение, как показано на рис. 2.8. Это расположения включают в себя другие области файловой системы (за исключением защищенных областей, наподобие папок Windows и Program Files), сетевые расположения и другие приложения – поставщики информации. (рис 2.7) Средство выбора файлов в режиме выбора одного элемента, открытое для Библиотеки изображений в режиме просмотра миниатюр, со всплывающим элементом подсказки, показанным для одного из элементов (для головы Сфинкса), в то же время рамка выделения присутствует у другого элемента (Тадж-Махал) (рис 2.8) Выбор другого расположения для просмотра файлов. Обратите внимание на то, что приложения-поставщики перечислены вместе с расположениями файловой системы

    Выбор другого расположения в файловой системе переносит нас туда, конечно, из него можно перейти в другие папки. Выбор приложения, с другой стороны, запускает это приложение посредством контракта поставщика выбора файлов. В подобном случае появляется пользовательский интерфейс, предоставляемый системой (но настраиваемый приложением), наподобие того, который показан на рис. 2.9. Здесь выпадающий список около заголовка позволяет вам переключаться к другим расположениям средства выбора файлов, и кнопки Открыть (Open) и Отменить (Cancel) работают так, как и должны для того, что выделено в средстве выбора файлов. Коротко говоря, приложение-поставщик, на самом деле, лишь расширение пользовательского интерфейса средства выбора файлов, но очень мощное расширение. И в итоге, подобное приложение просто возвращает соответствующий объект StorageFile, который задает его связь с исходным приложением. Много всего происходит всего лишь при одном вызове API средства выбора файлов! (рис 2.9) Приложение для работы с камерой, запущенное с помощью средства выбора файлов. Откуда взялся этот поползень?

    У средства выбора файлов есть пара других режимов. Один из них позволяет выделять сразу несколько файлов – даже из разных приложений! – как показано на рис. 2.10, где все выделенные файлы помещены в корзину элементов (basket) в нижней части экрана. Средство выбора так же можно использовать для выбора папок, как показано на рис. 2.11. (в данном случае приложения-поставщики не показаны), или место для сохранения файла и его имя ( рис. 2.12.). (рис 2.10) Средство выбора файлов в режиме множественного выбора с корзиной выделенных элементов в нижней части. Здесь так же показан режим просмотра в виде "списка", что задается независимо от режима выбора файлов (рис 2.11) Средство выбора файла используется для выбора папок – обратит внимание на то, что текст на кнопке изменился, и на область предварительного просмотра содержимого папки справа (рис 2.12) Средство выбора файлов используется для выбора места сохранения файла и задания его имени

    API средства выбора файлов и его друзья

    Теперь, когда мы видели визуальную часть средства выбора файлов, посмотрим, как можно вызвать его из кода приложения с использованием API Windows.Storage.Pickers (http://msdn.microsoft.com/library/windows/apps/br207928.aspx). Все изображения, которые мы только что видели, взяты из примера "Средство выбора файлов" (http://code.msdn.microsoft.com/windowsapps/File-picker-sample-9f294cba), и мы так же используем его как источник кода.

    Для начинающих, Сценарий 1 в функции pickSinglePhoto (js/scenario1.js) использует средство выбора для получения одного объекта StorageFile для открытия (чтения и записи):

    function pickSinglePhoto() {	
    // Удостоверяемся, что приложение не в прикрепленном режиме, или что мы можем перейти в иной режим для запуска
    // средства выбора файлов
    var currentState = Windows.UI.ViewManagement.ApplicationView.value;	
    if (currentState === Windows.UI.ViewManagement.ApplicationViewState.snapped 	
    !Windows.UI.ViewManagement.ApplicationView.tryUnsnap()) {	
    // Не выводим дополнительных сообщений,
     если приложение не вышло из прикрепленного режима	
    return;	
    }	
    
    // Создаем объект средства выбора файлов и настраиваем параметры	
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();	
    openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
    openPicker.suggestedStartLocation =	
    Windows.Storage.Pickers.PickerLocationId.picturesLibrary;	
    
    // Пользователи ожидают увидеть папки, к содержимому которых 
    применен фильтр, который зависит от сценария.	
    // Например, при выборе папки документов, ограничьте типы файлов документами вашего приложения
    openPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);	
    
    
    // Открываем средство выбора файлов, чтобы позволить пользователю выбрать файл
     openPicker.pickSingleFileAsync().done(function (file) {
    if (file) {
    // Теперь у приложения есть доступ к выбранному файлу для чтения и записи
    } else {
    // Средство выбора файлов было закрыто без выбора файла
    }
    });
    }
    
     

    Как вы можете видеть, вызывать средство выбора в прикрепленном режиме не следует. Это, как и попытка вызова панели параметров, приведет к исключению. Вы можете проверить это, как показано здесь, или добавить обработчик ошибки в метод Я должен отметить, что пример использует вместо done метод then в последнем асинхронном вызове. Хотя и then работает, там следует использовать done, особенно если вы собираетесь обрабатывать там исключения.. В любом случае, для вызова средства выбора файлов мы создаем экземпляр ), настраиваем его и затем вызываем его метод pickSingleFileAsync. Результат работы pickSingleFileAsync – это аргумент file, передаваемый в обработчик завершения, который может быть либо объектом типа StorageFile, либо содержать null, если пользователь не сделал выбор и закрыл интерфейс средства выбора файла. Именно поэтому всегда нужно проверять результат выбора файлов на null.

    Настраивая средство выбора файлов, мы задали его viewMode как thumbnail (из перечисления Windows.Storage.Pickers.PickerViewMode), что привело к тому виду, который показан на рис. 2.7. Другая возможность – это list, что показано на рис. 2.10.

    Кроме того, мы установили suggestedStartLocation в значение picturesLibrary, что является значением, взятым из перечисления Windows.Storage.Pickers.PickerLocationId. Другие возможности - documentsLibrary, computerFolder, desktop, downloads, homeGroup, musicLibrary, и videosLibrary, практически все остальные расположения вы можете видеть на рис. 2.8. Обратите внимание на то, что использование этих расположений не требует от вас объявления возможностей в манифесте, так как пользователь, используя средство выбора файлов, дает разрешение на доступ к этим файлам. Если вы посмотрите манифест этого примера, вы увидите, что он не объявляет никаких возможостей.

    Другой свойство, которое мы задаем, это )), который отражает типы файлов, которые нас интересуют (PNG и JPEG). Помимо этого, FileOpenPicker так же имеет свойство commitButtonText, которое задает подпись для основной кнопки в пользовательском интерфейсе (та из них, которая не является кнопкой Отмена (Cancel), и settingsIndentifier, средство для запоминания различных контекстов для средства выбора файлов. Например, приложение может использовать один идентификатор для выбора изображений, где начальное расположение установлено на библиотеку изображений и режим просмотра – на просмотр в виде миниатюр, и другой идентификатор для выбора документов с другим начальным расположением, и, возможно, с режимом просмотра в виде списка.

    Этот пример, как вы можете видеть, помимо получения файлов, ничего не делает с ними, но очень легко увидеть, что мы можем сделать с ними. Мы можем, например, просто передать ), о котором я говорил ранее. Этот пример так же показывает чтение содержимого файла посредством ), или использовать методы StorageFile для создания копии файла в другом расположении, переименования файла, и так далее. Но, с точки зрения средства выбора файлов, его работа здесь сделана!

    Возвращаясь к примеру о средстве выбора файлов, выбор нескольких файлов, во многом – это то же самое, как показано в функции pickMultipleFiles в js/scenario2.js. Здесь мы используем режим просмотра list и начинаем просмотр с documentLibrary. Опять же, это начальное расположение не требует объявления возможностей в манифесте.

    function pickMultipleFiles() {
    // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена)
    
    // Создаем объект средства выбора файлов и настраиваем параметры	
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();	
    openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.list;
    openPicker.suggestedStartLocation =	
    Windows.Storage.Pickers.PickerLocationId.documentsLibrary;	
    openPicker.fileTypeFilter.replaceAll(["*"]);	
    
    // Открываем средство выбора файлов, чтобы позволить пользователю выбрать файл
    openPicker.pickMultipleFilesAsync().done(function (files) {
    if (files.size > 0) {
    // Теперь у приложения есть доступ к выбранному файлу (файлам) для чтения и записи
    } else {
    // Средство выбора файлов было закрыто без выбора файла
    }
    });
    }
     

    При выборе нескольких файлов, результат ), доступ к которому осуществляется как к любому другому массиву, с использованием [ ] (хотя у него меньше методов, чем у обычного массива).

    Сценарий 3 примера демонстрирует вызов pickSingleFolderAsync, результат этой операции – объект StorageFolder. Здесь вы должны задать fileTypeFilter, что поможет пользователям выбрать подходящее расположение, в котором существуют файлы нужного типа, или то, где они смогут создать новые подобные файлы (js/scenario3.js):

     function pickFolder() {
    // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена)
    
    
    // Создаем объект средства выбора файлов и настраиваем параметры	
    var folderPicker = new Windows.Storage.Pickers.FolderPicker;	
    folderPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.desktop;
    folderPicker.fileTypeFilter.replaceAll([".docx", ".xlsx", ".pptx"]);	
    
    folderPicker.pickSingleFolderAsync().then(function (folder) {
    if (folder) {
    // Кэшируем папку, таким образом позже мы сможем получить доступ к ее содержимому
    Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList
    .addOrReplace("PickedFolderToken", folder);
    } else {
    // Средство выбора файлов было закрыто без выбора объекта
    }
    });
    }
    

    В этом примере мы так же видим, как сохранить выбранный объект StorageFolder в ) для последующего использования. Опять же, выбирая эту папку, пользователь дает приложению программный доступ к ее содержимого, но только на время текущего сеанса работы. Для того, чтобы сохранить полученные права, приложение должно записать элемент хранения в ) для того, чтобы больше узнать об этой возможности, и обратите внимание на то, что API AccessCache так же можно применять для недавно использованных элементов. Ключевая вещь, которую нужно здесь запомнить, заключается в том, что для любого расположения за пределами пакета приложения, данных приложения, или библиотек, доступ к которым вы объявили в манифесте, вы должны использовать AccessCashe для того, чтобы подобный доступ был у вас в будущем. Обычное сохранение пути к расположению и попытка открыть файлы из него позже не дадут результата.

    Последний пример использования средства выбора файлов, в Сценарии 4 примера, создается объект ) и вызывается метод pickSaveAsync, что приводит к появлению интерфейса, показанного на рис. 2.12:

    function saveFile() {
    // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена)
    
    // Создаем объект средства выбора файлов и настраиваем параметры	
    var savePicker = new Windows.Storage.Pickers.FileSavePicker();
    savePicker.suggestedStartLocation =	
    Windows.Storage.Pickers.PickerLocationId.documentsLibrary;
    // Выпадающий список типов файлов, применимый при сохранении	
    savePicker.fileTypeChoices.insert("Plain Text", [".txt"]);	
    savePicker.pickSaveFileAsync().done(function (file) {	
    if (file) {	
    // Предотвращает обновление удаленной версии файла до тех пор, пока мы не завершим
    // изменения и не вызовем CompleteUpdatesAsync.	
    Windows.Storage.CachedFileManager.deferUpdates(file);	
    
    
    // записываем в файл
    Windows.Storage.FileIO.writeTextAsync(file, file.name).done(function () {
    // Дадим Windows знать, что мы завершили изменение файла и другие приложения
    // могут обновлять удаленную версию файла.
    // Завершение обновлений может потребовать у Windows запросить у пользователя ввод данных. 
    Windows.Storage.CachedFileManager.completeUpdatesAsync(file)
    .done(function (updateStatus) {
    if (updateStatus === Windows.Storage.Provider.FileUpdateStatus.complete) {
    } else {
    // ...
    }
    }
    });
    });
    } else {
    // Интерфейс был закрыт
    }
    });
    }
     

    У объекта ). Этот объект помогает поставщику средства выбора файлов узнать, следует ли ему синхронизировать локальные файлы и файлы, хранящиеся на удаленном сервисе, что необходимо, когда пользователь файла сохраняет новое содержимое, как мы видим здесь. Со стороны потребителя, то, что мы здесь видим – это обычный шаблон для работы с файлами, полученными от средства выбора файлов (или из кэша доступа, если эти данные были сохранены в предыдущих сеансах работы): нам просто нужно дать знать объекту CashedFileManager, что мы осуществляем запись в файл, и сообщить ему, когда сделаем это. Конечно, этого делать не нужно, когда вы работаете с файлами, о которых вы знаете, что они локальные, как с теми, которые находятся в папках, расположенных в AppData. Больше об этом механизме мы узнаем в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", посмотрим на него со стороны поставщика.

    Медиабиблиотеки

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

    Вам нужен доступ к определенной библиотеке, если вы собираетесь работать с ней вне средства выбора файлов. Например, если вы хотите перебрать содержимое папок Изображения или Музыка для того, чтобы отобразить список файлов в элементе управления ListView или FlipView, как мы делали в лекции курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", вам нужно объявлять возможности.

    Чтобы быть более конкретным, без использования средства выбора файлов, это – единственный способ получить программный доступ к медиабиблиотекам: получения объекта ). В случае с медиаданными, применимые возможности здесь – picturesLibrary, musicLibrary и videoLibrary. Без объявления соответствующих возможностей, попытка получить одно из этих значения приведет к исключению отказа в доступе.

    Если вы не собираетесь пользоваться KnownFolders, это означает, что вам не нужно объявлять возможности! Помните, что объявленные возможности перечислены на странице приложения в Магазине Windows и могут вызвать у пользователя размышления о том, стоит ли устанавливать ваше приложение, поэтому, чем меньше возможностей будет объявлено – тем лучше.

    Тем не менее, если вы решите, что вам нужен прямой доступ к медиа-библиотекам, работа с ними включает в себя объекты StorageFolder и StorageFile так же, как при работе с любым другим расположением. Единственная разница, однако, это то, что вы можете работать с метаданными, которые часто существуют вместе с медиафайлами, подробнее об этом мы поговорим в лекции 4.

    Документы и съемные носители

    Как и в случае с доступом к папкам с медиаданными, программный доступ к папке с документами пользователя, так же, как и к съемным носителям, контролируется через объявление возможностей. Важно понимать и то, что обе эти возможности так же требуют, чтобы вы объявили сопоставление типов файлов, что означает, что вы не можете просто просмотреть содержимое папки напрямую, или записать в нее любой файл, какой захотите. Иными словами, получать непосредственный доступ к этим папкам с помощью Windows.Storage.KnownFolders.documentsLibrary и removableDevices, где и то и другое является объектом StorageFolder – просто для работы с ограниченным набором типов файлов, полезно лишь при реализации некоторых сценариев. Для библиотеки документов, на самом деле, документация говорит о том, что "единственное приемлемое использование [возможности] – это поддержка открытия содержимого, внедренного в другие документы". Магазин Windows так же требует оправданного использования объявления возможностей и так же требует, чтобы у вас была корпоративная учетная запись в Магазине Windows, а не только учетная запись индивидуального разработчика.

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

    Например, в примере "Съемные носители информации" (http://code.msdn.microsoft.com/windowsapps/Removable-Storage-52cc49f0), для демонстрации доступа к съемным носителям информации, объявляются сопоставления с .gif, .jpg и .png-файлами. В результате, приложение отображается в списке Открыть с помощью… (Open With) в контекстном меню, в Проводнике Windows на Рабочем столе, и в средстве выбора программ по умолчанию:

    То же самое справедливо и для документов (снова посмотрите пример Доступ к файлам" ( http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597)), таким образом, если ваше приложение не позиционируется как приложение для работы с подобными файлами, вам, возможно, не нужны эти возможности.

    На самом деле, объявление сопоставления типов файлов, это разновидность контрактов, мы рассмотрим это подробно в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой".

    Расширенные возможности запросов к файлам

    Для того чтобы перечислить файлы в определенном расположении (помимо возможностей), вы используете то, что называется файловым запросом (file query), или просто, поиском. Файловый запрос – это то, что Проводник Windows на рабочем столе использует для поиска по файловой систем, и может включать в себя поиск по содержимому файла, так же, как любое количество других свойств и метаданных. Эти запросы используют то, что называется строками Advanced Query Syntax (AQS) (http://msdn.microsoft.com/library/windows/desktop/bb266512.aspx) и могут идентифицировать и описать столько специфических критериев, сколько вам нужно. Вся эта тема несколько не вписывается в рамки курса, но мы можем, по крайней мере, взглянуть на то, как WinRT предоставляет богатые возможности файловых запросов приложениям посредством ). Достаточно будет заглянуть в глубокую кроличью нору!

    На самом деле, существуют буквально тысячи параметров, которые можно использовать в AQS-строках, так как они могут быть построены из любого количества свойств Windows (http://msdn.microsoft.com/library/windows/desktop/dd561977.aspx), таких, как System.ItemDate, System.Author, System.Keywords, System.Photo.LightSource и так далее Вопреки любым примерам в документации, в запросах всегда следует использовать полные имена свойств Windows, как, например System.ItemDate:, вместо удобного для программистов сокращения date:, так как последний вариант не будет работать в локализованных версиях Windows. . Каждое из свойств может содержать целевое значение, такое, как System.Author(Patrick or Bob) и System.ItemType: "mp3", и условия могут объединяться с помощью операторов AND, OR и NOT. Больше примеров мы увидим в лекции 4, где мы будем использовать запросы для получения коллекций файлов во множестве различных "форм", например, в виде одномерного списка, в иерархическом виде, в различных вариантах сортировки, включая те, которые основаны на медиа-свойствах. В дополнение, файловые запросы так же позволяют получать эскизы и автоматически получать альбомную графику для музыкальных произведений.

    Сконцентрируемся теперь на основных принципах работы файловых запросов, начнем с основ, которые показаны в упражнении FileQuery, которое включено в материалы к этой лекции. Это упражнение – копия примера "Программный поиск файлов" (http://code.msdn.microsoft.com/windowsapps/Programmatically-searching-25e1a56b) из Windows SDK, там присутствует лишь один сценарий, ориентированный на музыкальную библиотеку, который позволяет вам непосредственно вводить AQS-строку. Однако, это не то, что вы всегда будете использовать в приложениях, поэтому я хочу показать вам и другие варианты.

    Запросы всегда начинаются со ), методы которого createFileQuery[WithOptions], createFolderQuery[WithOptions] , и createItemQuery[WithOptions] (всего 6) используются для перечисления файлов, папок, или и того и другого в заданной папке StorageFolder . Простейшие запросы создают на основе методов StorageFolder.create* без параметров:

    folder.createFileQuery(); 
    folder.createFolderQuery(); 
    folder.createItemQuery(); 

    Здесь первые два метода – это лишь сокращения для варианта с одним параметром с одним и тем же именем, где параметр – это значение из перечисления ) или ). Эти короткие имена просто используют значение defaultQuery для обычного перечисления всего содержимого папки в алфавитном порядке. В свою очередь, createItemQuery имеет лишь эту единственную форму.

    Само по себе создание запроса ничего не перечисляет до тех пор, пока вы не запросите перечисление посредством асинхронного метода: для файловых запросов это метод getFilesAsync, для папок – getFoldersAsync, а для элементов хранения – getItemsAsync (Видите здесь повторяющуюся последовательность?). Таким образом, в Сценарии 2 упражнения FileQuery, у меня есть все три функции, подключенные к кнопкам:

    function fileQuery() {	
    var query = picturesLibrary.createFileQuery();
    SdkSample.showResults(query.getFilesAsync());	
    }	
    
    function folderQuery() {	
    var query = picturesLibrary.createFolderQuery();
    SdkSample.showResults(query.getFoldersAsync());	
     }
    
    function itemQuery() {
    var query = picturesLibrary.createItemQuery();
    SdkSample.showResults(query.getItemsAsync());
    }	
     

    Здесь функция SdkSample.showResults в js/default.js просто создает список элементов в коллекции. Запустив этот пример, вы увидите список файлов или папок в вашей библиотеке изображений.

    Совет. Реальный тип объектов, возвращаемый API create*Query, это StorageFileQueryResult, StorageFolderQueryResult, и StorageItemQueryResult, все они находятся в пространстве имен Windows.Storage.Search. Все они предоставляют некоторые дополнительные свойства, наподобие folder, методы наподобие findStartIndexAsync и getItemCountAsync, и события вроде optionschanged and contentschanged (оба - события WinRT). Последнее событие – это то, что вы можете использовать для отслеживания изменений в файловой системе, которые воздействуют на результаты запроса.

    Помимо получения неглубокого (shallow) представления, запросы к файлам и папкам имеют множество других возможностей, которые отражены в перечислениях CommonFileQuery и CommonFolderQuery:

  • В CommonFileQuery это: orderByName (порядок по имени), orderByTitle (порядок по заголовку), orderByDate (порядок по дате), orderByMusicProperties (порядок по свойствам аудиозаписи), и orderBySearchRank (порядок по рейтингу поиска).
  • В CommonFolderQuery это : groupByType (группировка по типу), groupByTag (группировка по тегу), groupByAuthor (группировка по автору), groupByYear (группировка по году), groupByMonth (группировка по месяцу), groupByArtist, groupByComposer (группировка по композитору), groupByGenre (группировка по жанру), groupByPublishedYear (группировка по жанру публикации), и groupByRating (группировка по рейтингу).
  • Очевидно, что эффект указания этих вариантов зависит от того, имеются ли у запрошенных элементов метаданные, которые поддерживают соответствующую группировку или упорядочение, но можно выполнить запрос ко всем папкам для всех типов файлов и папок. Для демонстрации этого Сценарий 3 упражнения FileQuery позволяет вам выбирать библиотеку музыки, изображений или видео. Затем вы можете выбрать, нужно ли строить запрос по файлам или папкам, указывать общепринятые параметры и запускать поиск для того, чтобы получить результат. Обратите внимание на то, что использование orderBySearchRank с файлами не имеет смысла в этом контексте, так как это предназначено для поисковых запросов, основанных на AQS. Мы увидим еще кое-что об этом позже (Кроме того – можете назвать меня бездельником! – результыты сгруппированного запроса к папке не особенно интересны, когда не выводятся в некие экранные элементы, но пример реализации подобного механизма вы можете увидеть в Сценарии 2 примера "Перечисление папок" (http://code.msdn.microsoft.com/windowsapps/Folder-enumeration-sample-33ebd000)). Код в js/scenario3.js, в основном, реализует механизм отображения выделенных элементов пользовательского интерфейса в createFileQuery или createFolderQuery с верными параметрами, таким образом вам не нужно просматривать большую их часть. Один важный участок кода – это использование методов isCommonFileQuerySupported и isCommonFolderQuerySupported объекта StorageFolder. Они используются для проверки того, поддерживает ли текущая папка тот запрос, который вы пытаетесь выполнить:

    if (folder.isCommonFileQuerySupported(selectedQuery)) {
    query = folder.createFileQuery(selectedQuery);	
    if (query) {	
    promise = query.getFilesAsync();	
    }	
    }	
     

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

    Похожий метод, ) (стандартные запросы – это лишь предварительно заполненные экземпляры этого объекта) и создаются путем передачи этого объекта в createFileQueryWithOptions, createFolderQueryWithOptions, и createItemQueryWithOptions.

    Объект QueryOptions обычно создается с нуля, с использованием оператора new, после чего вы заполняете его свойства. Так же вы можете использовать new QueryOptions(<CommonFolderQuery>) для получения объекта для одного из обычных запросов к папкам, и new QueryOptions(<CommonFileQuery> [, <file type filter>]) для того, чтобы сделать то же самое для файловых запросов. В последнем случае можно передать необязательный массив типов файлов. Это – короткое имя для часто настраиваемого стандартного запроса с особым набором типов файлов. Без него, фильтр установлен в"*" по умолчанию. Таким образом, если вам просто нужно найти .mp3-файлы в вашей музыкальной библиотеке, упорядоченные по заголовку (title), вы можете использовать что-то вроде нижеприведенного кода (смотрите js/scenario4.js в упражнении FileQuery):

    var musicLibrary = Windows.Storage.KnownFolders.musicLibrary;
    var options = new Windows.Storage.Search.QueryOptions( Windows.Storage.Search.CommonFileQuery.orderByTitle, [".mp3"]);
    
    if (musicLibrary.areQueryOptionsSupported(options)) {	
    var query = musicLibrary.createFileQueryWithOptions(options);
    SdkSample.showResults(query.getFilesAsync());	
    }	
     

    Если вы создаете Другое свойство, <code> dateStackOption</code> (значение из <code>Windows.Storage.Search.DateStackOption</code>), в данной структуре представлено в виде только для чтения, но оно может быть установлено при создании <code>QueryOptions</code>; из CommonFolderQuery. :

  • fileTypeFilter вектор из строк, который описывает желаемые расширения типов файлов, такие, как ".mp3". Значение по умолчанию – пустой список (фильтрация не применяется).
  • folderDepth принимает либо значение Windows.Storage.Search.FolderDepth.shallow (по умолчанию, неглубокое представление содержимого ), либо deep (глубокое рекурсивное представление всех вложенных папок и файлов.
  • indexerOption значение из Windows.Storage.Search.IndexerOption, оно может быть одним из следующих: useIndexerWhenAvailable, onlyUseIndexer (ограничивает поиск индексированным содержимым), и doNotUseIndexer (запрос направлен напрямую на файловую систему, без использования индекса). Последний вариант по умолчанию, обычно данное свойство явно устанавливают в значение useIndexerWhenAvailable.
  • sortOrder вектор из структур Windows.Storage.Search.SortEntry, каждая из которых содержит булево значение с именем ascendingOrder (значение false для убывающего порядка) и строку propertyName. Каждая запись в векторе определяет критерий сортировки. Эти критерии применяются в том порядке, в котором они расположены в векторе. Пример этого будет дан немного позже.
  • Три свойства QueryOptions затем примняются к поиску с AQS-строками:

  • applicationSearchFilter – AQS-строка.
  • userSearchFilter – другая AQS-строка.
  • language строка, содержащая идентификатор языка BCP-47, связанный с AQS-строками.
  • Когда запрос построен с помощью метода, наподобие createFileQueryWithOptions, строки пользовательского фильтра и фильтра приложения комбинируются. Это означает, что вы можете раздельно управлять любым фильтром, который вы хотите применять везде в вашем приложении (applicationSearchFilter) с помощью условий поиска, заданных пользователем (userSearchFilter). Таким образом, вы можете применить некоторые поисковые фильтры без необходимости ввода их пользователем, и без того, чтобы всегда выполнять объединение их со строками, заданными вами.

    Как упоминалось выше, запрос CommonFileQuery.orderBySearchRank имеет смысл лишь тогда, когда он скомбинирован с AQS-строкой, что говорит о том, что поиск, основанный на ключевых словах, возвращает ранжированный результат, к которому может быть применен обычный файловый запрос. Возвращаясь к Сценарию 1 примера о программном поиске файлов, мы можем увидеть, как здесь используется такое упорядочение вместе со свойством userSearchFilter:

    var musicLibrary = Windows.Storage.KnownFolders.musicLibrary;	
    var options = new Windows.Storage.Search.QueryOptions(	
    Windows.Storage.Search.CommonFileQuery.orderBySearchRank, ["*"]);
    options.userSearchFilter = searchFilter;	
    var fileQuery = musicLibrary.createFileQueryWithOptions(options);	
     

    На моем компьютере, где у меня есть несколько музыкальных композиций со словом "Nightingale" в заголовке, где есть и альбом, названный "Nightingale Lullaby", поиск с использованием строки "Nightingale" System.ItemType: "mp3" в вышеприведенном коде, дает мне следующий результат:

    Здесь можно видеть, что при поисковом ранжировании отобраны предпочитаемые композиции с "Nightingale" в заголовке, но так же в поиск включены композиции из альбома, который имеет это слово в имени.

    Моя поисковая строка, кстати, показывает, как вы можете использовать свойства applicationSearchFilter и userSearchFilter вместе. Если мое приложение может работать только с mp3 или с некоторыми другими форматами, я могу сохранить "System.Item.Type: 'mp3'" в applicationSearchFilter, а условия, которые задает пользователь, в userSearchFilter. Тем самым я избегаю самостоятельного объединения этих условий в коде.

    Помимо свойств, которые устанавливают в объекте QueryOptions существуют некоторые данные и возможности этого объекта. Так, groupPropertyName, это строковое свойство, которое показывает тип свойства, по которому будет сгруппирован запрос. Так же вы можете получить параметры запроса в виде строки, используя метод saveToString и создать объект на основе строки, используя loadFromString (это – аналог JSON.stringify и JSON.parse).

    Метод Посмотрите материал "Изменения, представляющие интерес для разработчиков приложений, внесенные после выхода Consumer Preview" (http://blogs.msdn.com/b/windowsappdev_ru/archive/2012/06/07/consumer-preview.aspx) в блоге для разработчиков приложений для Windows 8 для того, чтобы узнать некоторые подробности об этом. .

    В лекции 5 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", мы уже видели пример похожего использования свойств, связанных с эскизами, когда пользовались коротким именем библиотеки изображений с WinJS.UI.StorageDataSource и могли задавать параметр, указывающий размер эскиза:

    myFlipView.itemDataSource = new WinJS.UI.StorageDataSource("Pictures",
    { requestedThumbnailSize: 480 });
     

    Более общий пример, который так же включает вектор QueryOptions.sortOrder, можно найти в примере "Использование StorageDataSource и GetVirtualizedFilesVector" (http://code.msdn.microsoft.com/windowsapps/Data-source-adapter-sample-3d32e535), который упомянут в лекции 5 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". В примере, в js/scenario2.js, мы можем видеть создание QueryOptions с нуля, установку двух критериев sortOrder, и задание параметров эскизов в источнике данных:

    function loadListViewControl() {
    // Создаем источник данных из библиотеки изображений
    var library = Windows.Storage.KnownFolders.picturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions;
    // Неглубокий запрос для получения иерархии файлов
    queryOptions.folderDepth = Windows.Storage.Search.FolderDepth.shallow;
    queryOptions.sortOrder.clear();
    // Упорядочиваем элементы по типу, таким образом, первыми идут папки 
    queryOptions.sortOrder.append({ascendingOrder: false, propertyName: "System.IsFolder"}); 
    queryOptions.sortOrder.append({ascendingOrder: true, propertyName: "System.ItemName"}); 
    queryOptions.indexerOption =
    Windows.Storage.Search.IndexerOption.useIndexerWhenAvailable;
    
    var fileQuery = library.createItemQueryWithOptions(queryOptions);	
    var dataSourceOptions = {	
    mode: Windows.Storage.FileProperties.ThumbnailMode.picturesView,	
    requestedThumbnailSize: 190,	
    thumbnailOptions: Windows.Storage.FileProperties.ThumbnailOptions.none
    };	
    
    var dataSource = new WinJS.UI.StorageDataSource(fileQuery, dataSourceOptions);
    
    // Создаем ListView...
    };
     

    Если вам хочется разобраться с этим глубже, вы можете посмотреть, как заданы файловые запросы в StorageDataFolder. Просто найдите этот класс в файле ui.js в WinJS. По пути вы столкнетесь с другим набором API WinRT – возможно, это – дно кроличьей норы. Я хочу упомянуть о них, прежде чем рассматривать эту тему: Windows.Storage.BulkAccess. Они действительно существуют исключительно для использования в StorageDataSource и не предназначены для прямого использования в приложениях. Даже если вы создадите собственный источник данных или элемент управления коллекцией, лучше всего – использовать средства перечисления и API для упреждающей выборки данных, о которых мы уже говорили, так как они дают такой же уровень производительности.

    Обновление "Here My Am!"

    Для того, чтобы собрать воедино некоторые темы, изученные в этой лекции, дополнительные материалы включают в себя новую версию приложения "Here My Am!", в которую внесены следующие изменения и дополнения (в основном, в страницу pages/home/home.js, если не указано иное):

  • Теперь программа включает в себя Bing Maps SDK (http://msdn.microsoft.com/library/hh846481.aspx), таким образом, соответствующий элемент управления является частью пакета приложения, а не загружается с удаленного ресурса. Это устраняет необходимость в iframe, который мы использовали для поддержки карты, теперь весь код из html/map.html можно переместить в js/default.js. Обратите внимание на то, что для того, чтобы запустить этот пример в Visual Studio, вам нужно самостоятельно загрузить и установить этот SDK.
  • Вместо копирования изображения, полученного с камеры, в область данных приложения, теперь оно копируется в папку HereMyAm в библиотеке изображений. Объявлена возможность Библиотека изображений (Pictures Library).
  • Вместо сохранения пути к последнему полученному изображению, который используется, когда приложение было остановлено и перезапущено, StorageFile сохраняется в Windows.Storage.AccessCache для того, чтобы гарантировать возможность программного доступа к изображению в будущем.
  • На панель приложения добавлена команда, которая позволяет вам использовать средство выбора файлов для выбора изображения, вместо того, чтобы полностью полагаться на возможности камеры. Это так же позволяет вам использовать приложение для работы с камерой, если хотите. Обратите внимание, что в этом случае мы используем собственный settingsIdentifier со средством выбора файлов, что отличает его от обычного средства выбора файлов для существующих изображений.
  • Другая команда панели приложения позволяет вам выбирать из последних снимков, полученных с камеры. По умолчанию команда направлена на нашу папку в библиотеке изображений, она использует другой settingdIdentifier.
  • Дополнительные команды – О программе (About), Помощь (Help) и Заявление о конфиденциальности (Privacy Stating) включены в панель параметров с использованием события WinJS.Application.onsettings (смотрите js/default.js). Первые две отображают содержимое из приложения, в то время, как третья команда загружает веб-содержимое в iframe. Все страницы параметров можно найти в папке проекта html.
  • Что мы только что изучили

  • Преемственность или сохранение состояния важны в приложениях для Магазина Windows для поддержания состояния непрерывности работы приложения между сеансами работы, даже если приложение приостановлено или остановлено.
  • Данные приложения – это данные состояния сеанса, локальные, временные и перемещаемые состояния, которые привязаны к существованию приложения. Доступ к ним может получить только приложение.
  • Пользовательские данных хранятся в местах, отличных от мест хранения данных приложения (таких, как библиотеки музыки, изображений, видео, документов, вместе со съемными носителями информации) и существуют независимо от любого отдельно взятого приложения. Открывать пользовательские файлы и манипулировать ими могут различные приложения.
  • Доступ к данным приложения можно получить посредством API Windows.Storage.ApplicationData, что включает в себя и доступ к структурированным контейнерам параметров, и к данных, основанных на файлах. Так же доступны дополнительные API, наподобие IndexedDB и HTML5 localStorage.
  • Важно задавать версии состоянию приложения, особенно если используется перемещаемое состояние, от управления версиями зависит то, как служба перемещения данных будет направлять данные на устройства, на которых установлены определенные версии приложений.
  • Размер перемещаемого состояния ограничен квотой (она предоставляется API), при превышении которой Windows не будет перемещать данные. Для перемещения больших объемов данных, в том числе – пользовательских, можно использовать сервисы наподобие SkyDrive.
  • Обычный период перемещения данных – 30 минут или менее. Отдельный или составной параметр, имеющий имя "HighPriority", до тех пор, пока его размер не будет превышать 8 Кб, может перемещаться в течение минуты.
  • Классы WinRT StorageFolder и StorageFile – это основные объекты для работы с папками и файлами. Все виды программного доступа к файловой системе, начинаются, на самом деле, со StorageFolder. В противном случае, пользователь может указать на файл или папку с использованием API средства выбора файлов, который, на самом деле, является первым вариантом выбора для доступа к файлов.
  • Большие двоичные объекты (blob) – это удобные средства для работы с файлами, как и WinRT API в WindowsStorage.FileIO и PathIO. WinJS предлагает некоторые упрощенные методы для чтения и записи текстовых файлов (особенно они полезны при работе с состоянием приложения), так же поддерживается FileReader из HTML5.
  • WinRT предлагает средства шифрования с помощью Windows.Security.Cruptography, а так же встроенный механизм сжатия данных в Windows.Storage.Compression.
  • Для использования панели параметров, приложение заполняет панель верхнего уровня, которая предоставлена Windows, собственными командами. Эти команды связаны с обработчиками, которые либо открывают гиперссылки (в браузере), либо отображают всплывающие элементы настроек с использованием элемента управления WinJS.UI.SettingsFlyout. Эти всплывающие элементы могут включать в себя любой необходимый HTML-код, в том числе – элементы iframe для загрузки удаленного содержимого.
  • Доступ к папкам пользовательских данных, таким, как медиа-библиотеки, библиотека документов, съемные носители, контролируется возможностями, объявленными в манифесте. Подобные возможности нужно объявлять лишь тогда, если приложению нужен доступ к файловой системе таким способом, для которого не подходит применение средства выбора файлов.
  • Средство выбора файлов – это инструмент, с помощью которого пользователи могут выбирать файлы из любого безопасного расположения в файловой системе, а так же – файлы, предоставляемые другими приложениями (это могут быть удаленные файлы, файлы, хранящиеся в базах данных, даже те, которые не существуют в виде файловых записей в локальной файловой системе). Одна из наиболее удобных и мощных функций приложений для Магазина Windows – это возможность выбора файлов непосредственно из других приложений, в том числе – файлов, которые приложения могут генерировать по запросу.
  • Объекты типа StorageFolder обеспечивают обширные возможности по поиску в их содержимом и по доступу к нему с помощью файловых запросов. Запросы могут быть простыми и сложными и могут задействовать строки поиска Advanced Query Syntax (AQS).
  • Страницы:

    Файлы к данной лекции Вы можете скачать здесь.

    Было бы очень интересно, если бы, когда вы путешествуете, каждый гостиничный номер, в котором вы останавливаетесь, автоматически подстраивался бы под ваши предпочтения. Чтобы там были подушки и простыни, которые вам нравятся, правильные стулья, ваша любимая еда в минибаре – вместо непристойно дорогих и невероятно маленьких банок с закусками. Если вы достаточно богаты, конечно, вы можете заранее отправить своих людей для того, чтобы они все подготовили, но подобное для множества из нас – лишь мечта.

    Программное обеспечение, к счастью, не связано подобными ограничениями. Отправить своих людей в гостиницу перед своим приездом не означает необходимость бронирования для них авиабилетов, не нужно платить им зарплату и обеспечивать медицинскую страховку, не нужно делать вклады в их пенсионное обеспечение. Все, что нужно – подключение к Интернету, облачные сервисы, и вуаля! Все ваши предпочтения могут автоматически путешествовать вместе с вами. То есть – перемещаться между различными устройствами, которыми вы пользуетесь.

    Этот опыт работы с перемещаемыми данными (roaming experience), как он называется, встроен в Windows 8 для параметров, оказывающих влияние на систему, таких, как изображение вашего профиля, установки начального экрана, избранные интернет-страницы, тема рабочего стола, сохраненные учетные данные и так далее. Когда вы используете учетную запись Microsoft для входа в Windows на доверенном компьютере, эти параметры безопасно сохраняются в облаке и автоматически перемещаются на другие доверенные устройства под управлением Windows 8, на которых вы используете ту же учетную запись. Я был приятно удивлен, когда в ходе разработки Windows 8 мне не приходилось вручную переносить все эти данные, когда я обновлял предварительные релизы системы на своем компьютере!

    Если подобное возможно для системных параметров, пользователи будут ожидать похожего поведения и от приложений. Они будут ожидать, что параметры приложения будут надлежащим образом перемещаться с одного устройства на другое. Я сказал "надлежащим образом", так как некоторые настройки не имеет смысла перемещать, особенно те, которые специфичны для аппаратного обеспечения устройства. С другой стороны, если я настраиваю почтовые учетные записи в приложении на одном компьютере, я, конечно, надеюсь на то, что они окажутся и на других! (Не могу точно сказать вам, сколько раз я настраивал четыре своих активных почтовых учетных записи в Outlook). В общем, как пользователь, я ожидаю, что мой переход между устройствами – как на уровне системы, так и на уровне приложений – будет прозрачным и гладким.

    Таким образом, это означает, что каждое приложение должно выполнять свою работу по управлению собственным состоянием (включая – перемещение документов и других пользовательских данных посредством служб наподобие SkyDrive), и даже обеспечивать те виды кэширования, которые помогут увеличить производительность и сформировать хороший опыт взаимодействия пользователя и программы в условиях, когда устройство не подключено к Интернету. Как я уже говорил о многих подобных функциональных деталях, усилия, которые вы вкладываете в них, могут сыграть важную роль в том, как пользователи воспринимают ваше приложение и в том, какие оценки и отзывы о приложени они оставят в Магазине Windows.

    Многие подобные параметры будут полностью внутренними по отношению к приложению, а другие пользователь может настраивать и обычно так и поступает. В прошлом это порождало сложные наборы из вложенных диалоговых окон с множеством закладок, каждая из котоых была украшена кнопками, выпадающими меню и большими взаимосвязаными группами флажков и переключателей. Как результат, в деле настройки приложений не было единообразия. Не было и постоянного места, где располагались настройки приложений. Это могли быть, кроме прочих, команды меню Инструменты > Параметры, или Правка > Предустановки, или Файл > Сведения

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

    Очевидно, данные приложения – параметры и внутренние состояния – лишь часть рассказа. Пользовательские данные (user data), такие, как документы, картинки, музыкальные и видео-файлы – тоже весьма важны. Для работы с ними мы ищем соответствующие возможности в манифесте приложения, позволяющие приложению работать с документами и медиа-библиотеками, со сменными носителями информации, позволяющие ему получать доступ к содержимому папок с помощью запросов. Мы решаем, как средство выбора файлов (file picker) позволит пользователю принять решение о доступе к другим безопасным областям файловой системы (но не к системным областям и папкам данных других приложений).

    И здесь Windows 8, на самом деле, выводит нас за пределы локальной файловой системы. Подавляющее большинство данных, к которым имеет доступ современный пользователь, обычно расположены в сетевых хранилищах данных, а не в локальной файловой системе. Проблема здесь в том, что подобные данные обычно скрыты за специализированными API или веб-сервисами, что означает, что пользователь должен самостоятельно работать с веб-приложениями для просмотра данных, загружать и сохранять их в локальную файловую систему, и затем импортировать их в другие приложения. Видя такую модель взаимодействия, разрабочтики Windows 8 нашли другую возможность, которая представляет новый уровень интеграции и единообразия, которая позволяет приложениям представлять данные, хранящиеся в различных сервисах так, что они выглядят для других приложений как часть локальной файловой системы. Подобное реализуется посредством контракта средства выбора файлов (file picker contract), предоставляя пользователям возможность бесшовного опыта взаимодействия с локальными и сетевыми данными. Здесь мы рассмотрим ситуацию с точки зрения пользователя, а в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", поговорим о провайдерах данных.

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

    Рассказ о состояниях приложения

    Продолжая сравнение, о котором мы говорили в начале лекции, когда мы приезжаем в новые места и останавливаемся в гостинице, большинство из нас признает тот факт, что им, по прибытии, придется потратить некоторое время на то, чтобы распаковать вещи и расставить все в комнате так, как нам нравится. С другой стороны, мы ожидаем полной противоположености от наших домов: мы ожидаем преемственности или сохранения состояния (statefulness). За последний год я дважды переезжал (один раз – во временное жилище, пока наш дом не был достроен), и я способен оценить достоинства сохранения состояния. Представьте себе, что все в вашем доме упаковывается в коробки каждый раз, когда вы уезжаете. В итоге вам приходится тратить несколько часов, дней или недель на то, чтобы все распаковать! Нет, дом – это место, в котором, по нашим ожиданиям, вещи остаются на своих местах, даже если мы на некоторое время уезжаем. Думаю, именно поэтому многие люди любят путешествовать в домах на колесах!

    Приложения для Магазина Windows рассчитаны на такую вот неизменность состояния, что означает, что они поддерживают у пользователя ощущение преемственности между сеансами работы, даже если приложение было приостановлено или остановлено между сеансами. Таким образом, приложения воспринимаются больше как дом, а не как временное пристанище. Они становятся местом, в которое пользователь приходит, чтобы отдохнуть среди данных, которые ему нужны. В итоге, чем меньше усилий ему потребуется, чтобы начать наслаждаться подобным опытом взаимодействия с программой – тем лучше.

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

    Чтобы четко осознавать понятие "состояние приложения", вернемся ненадолго к пользовательским данным. Пользовательские данные, наподобие документов, изображений, музыкальных записей, видеофайлов, плейлистов и других подобных данных, создаются и используются приложением, но не зависят от приложения. Пользовательские данные подразумевают возможность работы с ними из разных приложений, и такие данные всегда остаются в системе, вне зависимости от существования приложения. Поэтому данные пользователя не являются частью состояния приложения. То есть, хотя приложение может запоминать пути (paths) к документам и другим файлам в составе списков избранных материалов или среди недавно использованных объектов реальное содержимое (content) этих файлов не является частью состояния приложения. Пользовательские данные, таким образом, не имеют прочной взаимосвязи с событиями жизненного цикла приложения. Их обычно сохраняют либо по непосредственной команде пользователя, либо, неявно, по событию наподобие visibilitychange, вместо использования такого события, как suspending. Опять же, приложение может запомнить список загруженных файлов как часть состояния сеанса работы при обработке события suspending, но содержимое файлов следует сохранить вне этого события, так как у вас есть лишь пять секунд на то, чтобы совершить все необходимые действия.

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

    Данные приложения используются для управления следующими видами состояний:

  • Состояние сеанса (Session state). Это состояние, которое приложение сохраняет при приостановке для восстановления его после возможной остановки. Сюда включаются данные форм, история навигации по страницам и так далее. Как мы видели в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", перезапуск после приостановки и последующей остановки – это единственный случай, в котором приложение восстанавливает состояние сеанса. Состояние сеанса обычно сохраняют инкрементно (при изменении состояния), либо при обработке событий suspending или checkpoint.
  • Локальное состояние приложения (Local app state). Это – параметры, которые обычно загружаются при запуске приложения. Состояние приложения включает в себя кэшированные данные, сохраненные результаты поиска, списки недавно просмотренных элементов и различные параметры поведения приложения, которые отображаются в панели Параметры в виде настроек отображаемых элементов, предпочитаемых видеоформатов, настроек, зависящих от устройства и так далее. Локальное состояние приложения обычно сохраняется при его изменении, а не при обработке событий жизненного цикла приложения.
  • Перемещаемое состояния приложения (Roaming app state). Это состояние приложения, которое перемещается между экземплярами одного и того же приложения, исполняющимися на различных Windows 8 – устройствах, на которых пользователь выполнил вход. Это – списки избранного, позиция воспроизведения видео, параметры учетной записи, URI для важных файлов в облачном хранилище данных, возможно, некоторые сохраненные результаты поиска или запросы, и так далее. Так же, как локальном состоянием приложения, этим состоянием ожно управлять посредством панели Параметры. Перемещаемое состояние так же лучше всего сохранять при изменении значений. Больше об этом мы узнаем далее в этой лекции.
  • Есть два других компонента состояния приложени, которыми, на самом деле, управляют вне папки данных приложения или контейнеров параметров. Один из них – это список файлов, которые изначально получены посредство средства выбора файлов, к которым приложению может понадобиться программный доступ в будущем. Для подобных файлов недостаточно сохранить лишь путь – нужно сохранить и сведения о факте предоставления пользователем разрешения на доступ к ним с помощью средства выбора файлов. Это – цель использования API ), и, в целом, является частью локального состояния приложения.

    Второй компонент – это учетные данные, которые вы получили от пользователя и хотите использовать в будущем. Так как эти данные имеют критическую важность, в плане безопасности, приложению никогда не следует хранить их в составе собственных данных. Вместо этого используйте API хранилища учетных данных ). Содержимое хранилища будет перемещаться между доверенными ПК пользователя, и, таким образом, составлять часть перемещаемого состояния приложения. Больше об этом вы узнаете в лекции 3 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой".

    Параметры и состояние приложения

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

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

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

    Вот некоторые примеры хороших кандидатов на размещение в интерфейсе чудо-кнопки.

  • Отображение предустановок, наподобие единиц измерения, цветовых тем, выравнивающих сеток и предустановок.
  • Предпочтения, касающихся перемещаемых данных, которые позволяют пользователю настроить перемещение данных приложения, такое, как, например, раздельное хранение настроек для рабочего и домашнего компьютеров.
  • Настройки учетной записи и профиля, а так же – команды для входа в аккаунт и выхода от него, и для управления аккаунтами и профилями. Никогда не следует хранить пароль в составе локальных или перемещаемых состояний, используйте вместо этого Хранилище учетных данных.
  • Параметры, влияющие на поведение приложения, наподобие оффлайнового и онлайнового режима, авто-обновления данных, интервалов обновления данных, предпочитаемого качества потокового аудио и видео. Здесь же находятс параметры передачи данных в сетях с лимитными тарифными планами, расположения, из которых приложению следует загружать данные и так далее.
  • Форма или ссылка для обратной связи, с помощью которой вы можете получить от пользователя какую-то особую информацию.
  • Дополнительные сведения о приложении, такие, как Справка, О программе, страница с информацией об авторских правах, заявление о конфиденциальности, лицензионное ограничение, условия использования. Часто подобные команды перенаправляют пользователя на специальный сайт, такой подход отлично подходит для реализации.
  • Я настоятельно рекомендую вам ознакомиться с приложениями, которые встроены в Windows и исследовать особенности использования ими чудо-кнопки Параметры. Так же вы можете изучить и то, как чудо-кнопка Параметры используется другими приложениями в Магазине Windows, однако, эти приложения не всегда следуют руководствам по проектированию приложений, которые декларируют единообразие интерфейса, а это очень важно для настройки параметров.

    Если говорить об этом, то Windows автоматически предоставляет всем приложениям команды, которые называются Разрешения (Permissions) и Отзывы и оценки (Rate and Review). Команда Отзывы и оценки ведет пользователя к странице приложения в Магазине Windows, где пользователь может поставить приложению оценку и написать отзыв. Команда Разрешения, в свою очередь, позволяет пользователю контролировать доступ к критически важным ресурсам, таким, как определение местоположения, камера, микрофон и так далее. То, что появляется в данном разделе, зависит от набора возможностей, объявленных в манифесте приложения, и это то место, где пользователь может отозвать то или иное разрешение или предоставить его приложению. Конечно, если приложение не использует подобных возможностей, команда Разрешения не отображается.

    Вы можете обратить внимание на то, что я не упоинал отображение сведений об обновлениях приложения внутри интерфейса чудо-кнопки Параметры. В этом нет необходимости, так как уведомления об обновлениях обеспечиваются напрямую Магазином Windows. Это – еще один способ уменьшения количества ненужного содержимого, с которым ранее сталкивались пользователи, когда каждое приложение по-своему представляло информацию об обновлениях (и иногда это происходило слишком часто!).

    Расположение данных приложения

    Теперь, когда мы понимаем, какик виды информации составляют состояние приложения, следующий вопрос заключается в том, где все это хранится. Вы можете помнить, из Главы 1 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", что когда Windows устанавливает приложение для пользователя (и все приложения для Магазина Windows доступны только тому пользователю, который их устанавливает), она автоматически создает папки LocalState, TempState и RoamingState внутри папки AppData текущего пользователя. Те же папки удаляются при деинсталляции приложения. В файловой системе, если вы, с помощью Проводника, перейдете в папку %localappdata%\packages, вы увидите множество папок для различных приложений в вашей системе. Если вы зайдете в любую из них, вы увидите вышеописанные папки вместе с еще одной, которая называется "Settings", как показано на рис. 2.1 для встроенного в систему приложения Sports (Спорт). На рисунке так же показано различное содержимое этих папок. (рис 2.1) Папка AppData приложения Sports (Спорт) и ее содержимое

    В папке LocalState на рис. 2.1 вы можете видеть файл с именем _sessionState.json. Это файл, где WinJS хранит, и откуда загружает содержимое объекта WinJS.Application.sessionState, как мы видели в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". Так как это обычный текстовый файл в формате JSON, вы можете просто открыть его в приложении Notepad (Блокнот) или в любом другом просмотрщике JSON для того, чтобы просмотреть его содержимое. Если вы взглянете на открытый файл приложения Sports (Спорт), который показан на рисунке, вы увидите что-то вроде {"lastSuspendTime":1340057531501}. Приложение Sports (Спорт) (вместе с приложениями News (Новости), Weather (Погода), и так далее), отображает содержимое, зависящее от времени, таким образом, это и другие приложения сохраняют время, когда они были приостановлены и проверяют прошедшее время при возобновлении. Если это время превышает интервал обновления данных, они могут запросить новые данные с сервиса, с которым связаны. В случае приложения Sports (Спорт), один из его параметров позволяет пользователю настроить интервал обновления данных.

    Если ваше приложение использует любое API хранения данных HTML5, такое, как локальное хранилище, IndexedDB, и кэш приложения, их данные так же появятся в папке LocalState.

    Примечание. Если вы внимательно посмотрите на рис. 2.1 вы увидите, что все папки с данными приложения, включая перемещаемые данные, находятся в папке пользователя AppData/Local. Есть и папка, родственная ей, AppData/Roaming, но она применяется лишь для параметров перемещаемых учетных записей пользователей в интранет-сети, как в случае, когда пользователь из присоединенного домена входит в систему с другого компьютера в корпоративной сети. Эта папка AppData/Roaming никак не связана с папкой AppData/Local…/RoamingState приложений для Магазина Windows.

    Вы можете обращаться к этим расположениям различными программными способами. Во-первых, вы можете использовать URI-схему ms-appdata:///, как мы видели в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". Здесь ms-appdata:///local, ms-appdata:///roaming, и ms-appdata:///temp позволяют обратиться к отдельным папкам и их содержимому. (Обратите внимание на тройной слэш, что является сокращением, позволяющим вам опускать имя пакета приложения). Так же вы можете использовать объект, который возвращает метод Windows.Storage.ApplicationData.current, который содержит все необходимые API, которые нужны вам для работы с состоянием приложения.

    Кстати, у вас могут быть данные только для чтения прямо в пакете приложения. С помощи URI вы можете просто использовать относительные пути, которые начинаются с /. Если вы хотите открыть и прочитать содержимое файла напрямую, вы можете использовать объект StorageFolder из свойства Windows.ApplicationModel.Package.current.installedLocation. Скоро мы вернемся к классу StorageFolder.

    API AppData (WinRT и WinJS)

    Когда вы запрашиваете у Windows свойство ), который полностью настроен для вашего приложения. Вот, что содержит этот объект:

  • Свойства localFolder, temporaryFolder, и roamingFolder, каждое из которых является объектом Windows.Storage.StorageFolder, который позволяет вам создавать любые файлы и дополнительные структуры папок в соответствующих расположениях (но помните о параметре roamingStorageQuota, который описан ниже).
  • Свойства ) и позволяют управлять иерархией контейнеров, состоящих из пар ключ-значение, или составными группами подобных пар значений. Все эти установки хранятся среди других данных приложения в папке Settings, в файле settings.dat.
  • Свойство roamingStorageQuota, которое содержит сведения об объеме данных, в килобайтах, которые Windows автоматически перемещает для целей приложения (обычно – 100). Если общий объем данных, сохраненных в папках roamingFolder и roamingSettings, превышает указанный лимит, перемещение будет приостановлено до тех пор, пока объем данных не упадет ниже квоты. Вы должны контролировать объем хранимых данных, если вы полагаете, что их объем близок к лимиту.
  • Событие dataChanged указывает на синхронизацию папок roamingFolder или roamingSettings с данными, хранящимися в облаке. По данному событию приложению следует повторно прочесть данные перемещаемого состояния. Это событие WinRT, для которого нужно использовать removeEventListener, как было описано в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript".
  • Метод signalDataChanged вызывает событие dataChanged. Это позволяет вам объединить обновления локальных и перемещаемых состояний в одном обработчике для события dataChanged.
  • Свойство version и метод setVersionAsync предназначены для управления отметками версий данных приложения. Версии применимы к полному объему данных – к локальным, временным и перемещаемым данным. Отдельные версии для разных данных не предусмотрены.
  • Метод clearAsync позволяет очищать состояние всех папок AppData и контейнеров параметров. Используйте его, когда вы хотите повторно инициализировать состояние по умолчанию, что особенно полезно, когда вы перезапускаете приложение из-за нарушения данных его состояния.
  • Метод clearAsync(<locality>) это вариант clearAsync, который ограничен одним расположением (локальным, временным, перемещаемым). Расположение идентифицируется с помощью значения из Windows.Storage.ApplicationDataLocality, такое, как Windows.Storage.ApplicationDataLocality.local. В случае с локальными и перемещаемыми данными, содержимое обеих папок и содержимого контейнеров очищается. Параметр temp воздействует только на папку TempState.
  • Теперь давайте посмотрим на то, как использовать это API для управления различными видами состояния приложения, что включает в себя некоторые вспомогательные функции WinRT, используемые для тех же целей.

    Подсказка. API, которые работают с состоянием приложения, вызывают события в Средстве просмотра событий (Event Viewer), если вы включили эту возможность, как было описано в лекции 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". Убедитесь в том, что функция Вид > Отобразить аналитический и отладочный журналы (View > Show Analytic and Debug logs) включена. Затем пройдите в раздел Application and Services Log (Журналы приложения и служб), разверните раздел Microsoft/Windows/AppModelState, где вы найдете группы Debug (Отладка) и Diagnostic (Диагностика).

    Контейнеры параметров

    Для начинающих, давайте посмотрим на свойства localSettings и roamingSettings, которые обычно называют контейнерами параметров (settings containers). Вы работаете с ними с помощью API ApplicationDataContainer, которое устроено довольно просто. Каждый контейнер имеет четыре свойства только для чтения: name (строка) , locality (значение из Windows.Storage.ApplicationDataLocality, здесь есть лишь значения local и roaming), и коллекции, которые называются values и containers.

    Параметры контейнеров верхнего уровня имеют пустые имена. Свойство устанавливается на дочерние контейнеры, которые вы создаете с помощью метода createContainer (и удаляете с помощью deleteContainer). Эти дочерние контейнеры могут содержать другие контейнеры, что позволяет вам создавать иерархию настроек. Таким образом, эти контейнеры настроек предназначены для хранения небольших объемов данных, обычно – параметров пользователя, и отдельных параметров, объем которых ограничен 8 Кб, а так же любые наборы взаимосвязанных параметров (смотрите ниже) размером до 64 Кб. Учитывая эти ограничения, превышение объема в один мегабайт предусматривает довольно сложную иерархию настроек, которой сложно управлять, и доступ к которой осуществляется сравнительно медленно. Поэтому не поддавайтесь искушению воспринимать эти настройки как своего рода базу данных. Для этих целей гораздо лучше подходят иные механизмы, такие, как IndexedDB и SQLite, и с их помощью вы можете хранить любые объемы данных, так же, как и в папках AppData (помните об ограничении на объем перемещаемых данных, когда вы записываете данные в roamingFolder).

    Для любого контейнера, который у вас есть, его коллекция ), с помощью которого вы можете просматривать содержимое контейнера. Коллекция values, с другой стороны, это обычный массив (с технической точки зрения – объект IPropertySet в WinRT, который проецируется в WinJS в виде массива с методами IPropertySet). Таким образом, хотя свойство values в любом контейнере – это свойство только для чтения, что означает, что вы не можете назначить ему какой-либо произвольный массив, вы можете управлять содержимым данного массива так, как вам нужно.

    Мы можем увидеть это в примере "Данные приложения" (http://code.msdn.microsoft.com/windowsapps/ApplicationData-sample-fb043eb2), в котором есть много примеров базовых операций с данными приложения. Сценарий 2, например, (js/settings.js) показывает простоту использование массива localSettings.value:

    var localSettings = Windows.Storage.ApplicationData.current.localSettings;
    var settingName = "exampleSetting";
    var settingValue = "Hello World";
    
    function settingsWriteSetting() {
    localSettings.values[settingName] = settingValue;
    }
    
    function settingsDeleteSetting() {
    localSettings.values.remove(settingName);
    }
     

    Многие параметры, похожие на те, которые показаны выше, это простые пары ключ-значение, но другие параметры могут быть объектами с множеством свойств. Это являет собой особую проблему: хотя вы можете, конечно, записывать и считывать отдельные свойства данного объекта внутри массива values, что случится, если в одном из них произойдет сбой? Это приведет к тому, что состояние приложения окажется поврежденным.

    Для защиты от этого API для работы с данными приложения предоставляет возможность работы с взаимосвязанными параметрами (composite settings) как с неделимой единицей. (Повторюсь, каждый набор взаимосвязанных параметров ограничен размером в 64 Кб). Это похоже на идеальное групповое сознание: либо все преуспеют, либо всех ждет неудача и ничего кроме этих двух вариантов! Таким образом, если возникает ошибка при чтении или записи любой части взаимосвязанных параметров, вся операция признается несостоявшейся. В случае с перемещаемыми данными, либо перемещается вся группа взаимосвязанных параметров, либо они не перемещаются вовсе.

    Объект взаимосвязанных параметров создается с помощью ), как показано в Сценарии 4 примера работы с данными приложения (js/compositeSetting.js) нет такого сценария:

    var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
    var settingName = "exampleCompositeSetting";	
    var settingName1 = "one";	
    var settingName2 = "hello";	
    function compositeSettingsWriteCompositeSetting() {
    var composite = new Windows.Storage.ApplicationDataCompositeValue();
    composite[settingName1] = 1; // пример значения	
    composite[settingName2] = "world"; // пример значения
    roamingSettings.values[settingName] = composite;
    }	
    
    
    function compositeSettingsDeleteCompositeSetting() {
    roamingSettings.values.remove(settingName);
    }
    
    
    function compositeSettingsDisplayOutput() {	
    var composite = roamingSettings.values[settingName];
    // ...	
     }
     

    Объект ApplicationDataCompositeValue имеет, как вы можете увидеть в документации, некоторые дополнительные методы и события для того, чтобы помочь в управлении им, это такие методы, как clear, insert и mapchanged.

    Взаимосвязанные параметры, во многом, напоминают контейнер параметров, однако, они не могут содержать другие контейнеры. Важно не путать их с обычными контейнерами. Дочерние контейнеры внутри параметров используются лишь для создания иерархии (посмотрите Сценарий 3 примера). Взаимосвязанные параметры, с другой стороны, специально созданы для создания более сложных наборов параметров, которые работают как неделимая единица, подобное поведение не гарантировано для обычных контейнеров параметров.

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

    Управление версиями состояния приложения

    С точки зрения Windows, локальное, временное и перемещаемое состояние – это части единого целого, и все они имеют одну и ту же версию. Номер версии устанавливается посредством ), прочитать номер версии можно, воспользовавшись свойством только для чтения Windows.Storage.ApplicationData.version. Если хотите, вы можете поддерживать собственную систему назначения версий, с помощью отдельного файла или параметра приложения. Однако, я рекомендую, чтобы вы избегали подобного с перемещаемым состоянием, так как сложно предсказать, как Windows будет управлять синхронизацией слегка отличающихся структур. Даже в случае с локальным состоянием, попытка играть в сложные игры версий, на самом деле, может оказаться гораздо сложнее, чем кажется, и, вероятно, подобного лучше избегать вообще.

    Версия данных вашего приложения и версия приложения – это разные вещи. На самом деле, они никак не связаны. В то время, как версия данных приложения устанавливается с помощью setVersionAsync, версией приложения управляют в разделе Упаковка (Packaging). У вас может быть приложение, которое от версии 1.0.0.0 до версии 4.3.9.3 использует данные приложения версии 1.0.0.0, или, может быть, версия приложения 1.2.1.9 переходит на версию 1.0.1.0. данных приложения, и версия 2.1.1.3 использует версию 1.2.0.0 данных приложения. На самом деле, это неважно, до тех пор, пока вы контролируете этот процесс и старые данные приложения могут переходить к новым версиями приложений!

    Переход (migration) происходит при вызове ), который содержит свойства ).

    Можно осуществлять перенос данных приложения и тогда, когда устанавливается новое обновление приложения. Для этого пользуются фоновой задачей для вызова sevicingComplete. Смотрите Главу 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", в особенности – раздел "Фоновые задачи и приложения на экране блокировки" ближе к концу.

    Управление папками и файлами

    Так как часто очень удобно сохранять данные приложения напрямую в файл, настало время для того, чтобы внимательно рассмотреть файловые API приложений для Магазина Windows.

    Для начала, однако, взглянем на другие API, такие, как URL.createObjectURL – работающее с тем, что мы называем большим двоичным объектом (blob), делая возможным выполнять множество действий в приложения без необходимости спускаться на уровень файлового ввода/вывода. Мы уже видели, как этим пользоваться, устанавливая свойство ).

    Для того чтобы работать напрямую с файлами, рассмотрим то, что имеется в нашем распоряжении, использовав конкретные образцы из примера "Доступ к файлам" (http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597).

    Основные API WinRT для работы с файлами расположены в пространстве имен ) и StorageFile (http://msdn.microsoft.com/library/windows/apps/windows.storage.storagefile.aspx). И на то и на другое иногда ссылаются как на "элементы хранения", так как и тот и другой класс унаследованы от IStorageItem (http://msdn.microsoft.com/library/windows/apps/windows.storage.istorageitem.aspx) и имеют одинаковые свойства, такие, как name, path, dateCreated и attributes, а так же методы deleteAsync и renameAsync.

    Файловые операции ввода-вывода в WinRT практически всегда начинаются с получения объекта StorageFolder посредством одного из нижеперечисленных способов. В некоторых случаях вы так же можете получить объект StorageFile напрямую:

  • Свойство ) получает StorageFolder, посредством которого вы можете загружать данные из файлов, которые находятся в пакете приложения (все файлы – только для чтения).
  • Свойства Windows.Storage.ApplicationData.current.localFolder, roamingFolder, или temporaryFolder обеспечивают объекты StorageFolder для различных расположений данных приложения (для чтения и записи).
  • Приложение может позволить пользователю выбирать папку или файл напрямую, используя средство выбора файлов, запущенное посредством ) а так же ) и ). Для приложений это – предпочтительный способ, используя который нет необходимости в просмотре содержимого библиотеки (смотрите следующий пункт списка). Это так же единственное средство, с помощью которого приложение может получить доступ к безопасным (несистемным) областям файловой системы без необходимости объявления дополнительных возможностей в манифесте.
  • Объект ) предоставляет объекты StorageFolder для библиотек "Документы", "Музыка", "Видео", так же, как и для доступа к съемным устройствам. Задавая соответствующие возможности в манифесте, вы можете работать с содержимых этих папок. (Попытка получить доступ к папке без объявления соответствующих возможностей приведет к выдаче исключения "Доступ запрещен").
  • Объект ) предоставляет метод createFolderAsync, посредством которого вы можете получить StorageFolder для папки "Загрузки". Он так же предоставляет метод createFileAsync для непосредственного создания объектов StorageFile. Данное API следует использовать, если ваше приложение управляет загруженными файлами напрямую. Обратите внимание на то, что DownloadFolder предоставляет лишь эти два метода, она не является StorageFolder.
  • Статический метод ) возвращает ), к нему применимы те же ограничения. ) открывает файлы с помощью URI ms-appx:// (package) и ms-appdata:/// . Другие схемы не поддерживаются.
  • Как только объект, соответствующий папке или файлу, получен, его можно сохранить в кэше ), который позволяет приложению получать эти объекты позже, с теми же программными разрешениями. Это нужно, преимущественно, для файлов или папок, выбранным с помощью средств выбора, так как разрешения на доступ к элементу хранения выдаются лишь на период существования данного объекта в памяти. Всегда следует использовать данное API, как показано в Сценарии 6 примера о доступе к файлам, где вы принимаете решение о сохранении пути к файлу. Опять же, StorageFolder.getFolderFromPathAsync и StorageFile.getFileFromPathAsync выдадут исключение "Доступ запрещен", если они указывают на любое расположение, для доступа к которому у вас уже нет разрешения. Пути к файлам, так же, не будут работать для файлов, предоставленных другими приложениями через средство выбора файлов, так как объект StorageFile, на самом деле, может не указывать на файл, который реально существует в файловой системе.
  • Как только у вас есть ) (подключенного для ), который, в свою очередь, имеет метод ). С помощью этого метода вы можете получить любое количество свойств Windows (http://msdn.microsoft.com/library/windows/desktop/dd561977.aspx). Свойство наподобие System.FreeSpace даст вам реальный размер свободного пространства на диске, где расположена папка, которой соответствует StorageFolder . .

    ). Кроме того обратите внимание на то, что доступ к UNC-путям требует объявления возможностей Частные сети (клиент и сервер) (Private Networks (ClientServer)) и Корпоративная аутентификация (Enterprise Authentication) в манифесте вместе с объявлением типов файлов, к которым вы хотите получить доступ.

    С помощью любого StorageFolder, в особенности для расположений, соответствующих данным приложения, вы можете создать любую необходимую структуру папок с помощью методов createFolderAsync/getFolderAsync, которые дают вам больше объектов StorageFolder. В любой из этих папок вы затем используете методы createFileAsync/getFileAsync для доступа к отдельным файлам, каждый из которых будет представлен в виде объекта StorageFile.

    Каждый ) обеспечивает соответствующие свойства наподобие name, path, dateCreated, fileType, contentType, и attributes, конечно, вместе с методами наподобие getThumbnailAsync, copyAsync, deleteAsync, moveAsync, moveAndReplaceAsync, и renameAsync для управления файлами. Файл можно открыть разными способами, зависящими от того, доступ какого рода вам нужен:

  • Методы ) и ), соответственно, оба находящиеся в пространстве имен Windows.Storage.Streams. Первый из них работает с исходным двоичным потоком. Второй работает с данными, используя их тип, что может быть нужно для работы с HTTP-ответом, который добавляет в поток данных сведения о типе содержимого.
  • Метод ), посредством которого можно читать содержимое файла блоками байтов, но нельзя возвращаться к ранее прочитанной области. Данный метод следует использовать во всех случаях, когда вам просто нужно прочесть данные из потока, так как он обладает лучшей производительностью, чем поток для произвольного доступа (источник можно оптимизировать для последовательного чтения данных).
  • Метод ), который является вспомогательным объектом, построенным на основе IRandomAccessStream , который имеет методы commitAsync и close для обработки транзакций. Это необходимо при сохранении данных со сложной структурой, для того, чтобы быть уверенным в том, что вся операция записи произошла атомарным образом, и файлы не были повреждены при ее прерывании. Сценарий 4 в примере о доступе к файлам показывает этот подход.
  • Класс StorageFile так же предоставляет два статических метода: createStreamedFileAsync и createStreamedFileFromUriAsync. Результатом их работы является объект StorageFile, который обычно передают другим приложениям посредством контракта, как мы увидим в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой". Полезность этих методов заключается в том, что доступ к файлу, лежащему в их основе, не осуществляется до тех пор, пока его данные не будут запрошены в первый раз, если такой запрос вообще произойдет.

    Соберем теперь все это воедино. Вот небольшой фрагмент кода, использующий исходные API, которые мы рассматривали, для создания и открытия файла "data.tmp" в папке временных данных приложения, расположенной в папке AppData, и для записи в него заданной строки. Это – код из упражнения RawWriteFile к этой лекции. Позвольте мне пояснить, что то, что здесь показано, использует низший уровень API в WinRT для этих целей, и это не то, чем обычно пользуются, как мы увидим в следующем разделе. Тем не менее, это полезно знать, так как бывают случаи, когда нужно использовать нечто подобное:

    var fileContents = "Congratulations, you're written data to a temp file!";
    writeTempFileRaw("data.tmp", fileContents);
    
    
    function writeTempFileRaw(filename, contents) {
    var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;
    var outputStream;
    
    //Ей-богу!
    tempFolder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting)
    .then(function (file) {
    return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
    }).then(function (stream) {
    outputStream = stream.getOutputStreamAt(0);
    var writer = new Windows.Storage.Streams.DataWriter(outputStream);
    writer.writeString(contents);
    return writer.storeAsync();
    }).done();
    }
     

    Хорошо, что недавно мы узнали об асинхронных операциях, объединенных в цепочку! Для начала мы создаем или открываем заданный файл в папке temporaryFolder среди данных приложения (createFileAsync), затем получаем выходной поток для файла (openAsync и getOutputStream). Затем мы создаем на основе потока объект DataWriter, записываем в файл данные (writeString) и убеждаемся, что информация сохранена в файле (storeAsync).

    Но вы скажете: "Вы, должно быть, шутите! Четыре объединенных в цепочку асинхронных операции только для того, чтобы записать обычную строку в файл! Кто разрабатывал это API?" Действительно, когда мы начинали создавать самое первое приложение для Магазина Windows в Microsoft, у нас было лишь это, и мы задавали себе те же вопросы. В конце концов, выполнение некоторых ожидаемо простых файловых операций ввода-вывода – это обычно первое, что добавляют в приложение "Hello World", и это в данном случае совсем не просто. Что еще хуже, тогда у нас не было promise-объектов для асинхронных операций в JavaScript, поэтому мы должны были написать это на основе исходных вложенных операций. Такие были времена.

    К счастью, более простые API уже были доступны, и многое было сделано уже после этого. Это те API, которые вы обычно будете использовать, при работе с файлами, и это мы рассмотрим в следующем разделе. Тем не менее, важно понимать структуру вышеприведенного низкоуровневого кода, так как класс ) и родственный ему ) – это очень важные механизмы для работы с множеством различных потоков ввода-вывода, и они необходимы для процессов кодирования данных. Контроль над мелкими деталями, кроме того, позволяет реализовывать сценарии, когда различные компоненты вашего приложения вносят собственный вклад в структуру файла. Поэтому хорошо будет взглянуть на документацию по ним, и на пример "Чтение и запись данных" (http://code.msdn.microsoft.com/windowsapps/Reading-and-writing-data-75ea10a3) лишь для того, чтобы вы были знакомы с их возможностями.

    Врезка: Закрытие потоков против закрытия файлов

    Разработчики, которые работали ранее с API ввода-вывода иногда спрашивают, почему у объекта StorageFile нет чего-то вроде метода close. Причина в том, что StorageFile представляет собой объект, соответствующий файлу, но не поток данных, посредством которого можно получать доступ к содержимому файла. Таким образом, когда вы вызываете методы вроде StorageFile.openAsync для получения потока, при этом файл открывается, и файл закрывается только при закрытии потока посредством его метода close.

    В вышеприведенном коде вы не увидите подобного вызова, так как и DataReader, и DataWriter заботятся о подобных деталях для вас, когда такие вызовы опущены. Однако если вы отделите поток от этих объектов посредством их методов detachStream, вы ответственны за вызов метода потока close .

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

    FileIO, PathIO и вспомогательные классы WinJS (а так же FileReader)

    Простота – это очень хорошо, если речь идет о файловых операциях ввода-вывода, и дизайнеры WinRT убедились в том, что наиболее распространенные сценарии не нуждаются в длинных цепочках асинхронных операций, которые мы видели в предыдущем разделе. Классы ) и ) предоставляют усовершенствованный интерфейс, а разница между ними заключается в том, что методы FileIO принимают параметр типа StorageFile, а методы PathIO принимают строковое имя файла. В остальном они имеют одинаковые методы, в частности, [read | write]BufferAsyn c (работают с байтовыми массивами), [append | read | write]LinesAsync (работают со строковыми массивами),и [append | read | write]TextAsync (работают с отдельными строками). В последнем случае класс WinJS.IOHelper предоставляет даже более простой интерфейс посредством своих методов readText и writeText.

    Посмотрим, как все это работает, начнем с нескольких образцов кода из примера "Доступ к файлу" (http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597). Сценарий 2 демонстрирует запись текстовой строки из элемента управления в файл (этот код упрощен, для большей понятности):

     var userContent = textArea.innerText;
    
    //sampleFile создается при старте с помощью Windows.Storage.KnownFolders.documentsLibrary.getFileAsync
    Windows.Storage.FileIO.writeTextAsync(sampleFile, userContent).done(function () {	
    outputDiv.innerHTML = "The following text was written to '" + sampleFile.name	
    + "':<br /><br />" + userContent;	
    });
    

    Для сравнения с кодом из предыдущего раздела, мы можем заменить все, что касается потоков и объекта DataWriter, одной строкой кода:

    tempFolder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting)
    .then(function (file) {	
    Windows.Storage.FileIO.writeTextAsync(file, contents).done();	
    })
     

    Чтобы сделать это еще проще, объект )) сокращает все до одной строки (которая является асинхронной операцией и возвращает promise-объект:

    WinJS.Application.temp.writeText(file, contents); 

    Чтение текста посредством асинхронного метода Если вам интересно, почему асинхронные методы, такие, как readText и writeText не имеют слова Async в своих названиях, это потому, что дизайнеры WinJS сознательно решили следовать существующим соглашениям об именам, принятых в JavaScript, где такой суффикс обычно не используется. API WinRT, с другой стороны, с другой стороны, не зависит от языков программирования, и имеет собственное соглашение об именовании, допускающее использование суффикса Async. . Тем не менее, эти вспомогательные функции WinJS доступны лишь для папок в AppData, но не для других областей файловой системы. Для работы с другими областями следует использовать классы FileIO и PathIO.

    Кроме того, вы можете пользоваться классом HTML5 ). Как следует из его названия (reader), он подходит только для чтения файлов и не обладает возможностью записи в них, но одно из его преимущества заключается в том, что он может работать не только с файлами, но и с большими двоичными объектами. Некоторые образцы подобных действий можно найти в примере "Использование больших двоичных объектов для сохранения и загрузки содержимого" (http://code.msdn.microsoft.com/windowsapps/Blob-Sample-0e35889e).

    Шифрование и сжатие

    WinRT предоставляет две возможности, которые может быть весьма полезны для управления состоянием приложения: шифрование и сжатие данных.

    Возможности шифрования предоставляют API ) и ). Первое содержит методы для базовых операций кодирования и декодирования (для форматов base64, hex, text). Второе занимается шифрованием в соответствии с различными алгоритмами. Как показано в примере "Сохранение секретных данных с помощью шифрования" (http://code.msdn.microsoft.com/windowsapps/Secret-Saver-f8a69623), данные обычно кодируют каким-либо образом с использованием метода Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary, а затем создают или получают алгоритм и передают его вместе с буфером данных методу Windows.Security.Cryptography.Core.CryptographicEngine.encrypt. Другие методы, такие как decrypt и convertBinaryToString, выполняют обратные операции.

    Механизмы сжатия выглядят немного проще, их единственная цель – предоставить встроенное API, с помощью которого можно уменьшить объем данных (например, для уменьшения размера перемещаемых данных). API для этих целей находится в ), оно включает в себя классы ). Хотя это API может использовать различные алгоритмы сжатия, включая алгоритм под названием MSZIP, оно не предоставляет средств для управления .ZIP-файлами и их содержимым. Для подобных целей вам понадобится либо использовать JavaScript-библиотеки сторонних производителей, либо написать WinRT-компонент на C# или VisualBasic, который может использовать API System.IO.Compression (смотрите Главу 5 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой").

    Использование API данных приложения для управления состоянием

    Сейчас, когда мы ознакомились с сущностью API, посмотрим, как их можно использовать для работы с различными видами данных приложения, а так же рассмотрим специальные соглашения, которые применимы в данной работе

    Состояние сеанса

    Как было описано выше, состояние сеанса это то, что приложение сохраняет при приостановке, и, таким образом, может восстановить свое состояние после того, как было остановлено системой и запущено снова. Единственный вариант развития подобных событий – это остановка приложения системой, поэтому все, что включают в состояние сеанса, всегда должно быть рассчитано на то, чтобы давать пользователю иллюзию непрерывной работы приложения. В некоторых случаях, как описано в лекции курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", вы можете, на самом деле, не восстанавливать это состояние, особенно, если приложение было остановлено в течение длительного времени и маловероятно, чтобы пользователь помнил, как все выглядело во время последнего сеанса работы. Это решение вам нужно будет принять для собственного приложения, от него зависит опыт взаимодействия пользователя и приложения.

    Состояние сеанса следует сохранять в папке данных приложения localFolder , или в объекте localSettings . Не следует сохранять его в области временных данных, так как пользователь может запустить средство очистки диска в то время, когда приложение приостановлено или остановлено, и в таком случае данне состояния сеанса будут удалены (смотрите следующий раздел).

    Объект WinJS sessionState самостоятельно создает файл, который называется _sessionState.json внутри localFolder. В этом файле хранится обычный текст в формате JSON, поэтому вы можете в любое время его просмотреть. Вы можете записать переменные сеанса работы в объект sessionState , в любое время, когда они изменяются, используя sessionState как пространство имен для этих переменных, и именно так следует поступать. При таком подходе эти значения сохраняются и перезагружаются автоматически, без необходимости управлять этими переменными где-либо еще.

    Если вам нужно сохранить дополнительные значения внутри sessionState , прежде чем данные будут записаны, сделайте это в обработчике WinJS.Application.oncheckpoint . Хороший пример подобных данных – это навигационный стек элементов управления страниц, который доступен посредством WinJS.Navigation.history . Так же вы можете скопировать эти данные в sessionState внутри метода PageControlNavigation.navigated (он находится в navigation.js и предоставляется шаблонами проектов). В любом случае, у WinJS есть собственный обработчик checkpoint, который всегда вызывается последним (после вашего обработчика) для того, чтобы убедиться, что любые изменения, которые вы внесли в sessionState после этого события, были сохранены.

    Если вы не используете объект WinJS sessionState , а просто используете API WinRT для работы с данными приложения, вы можете сохранять состояние сеанса в любое время (в том числе – в checkpoint ), и вам понадобится восстанавливать их в событии активации при выполнении условия previousExecutionState == terminated .

    Кроме того, хорошей практикой является обеспечение некоторой устойчивости в обработке состояния сеанса: если загруженные данные кажутся неподходящими или имеются другие проблемы, можно вернуться к данным сеанса по умолчанию. Помните так же, что вы можете использовать контейнер localSettings с взаимосвязанными параметрами, что гарантирует то, что группа значений будет сохраняться и извлекаться как единое целое. Так же может оказаться полезным при разработке иметь команду, которая дает вам возможность очищать состояние сеанса в том случае, если оно заполняется ненужными данными, но, в то же время, обычная деинсталляция приложения так же очищает состояние сеанса. В то же время, нет необходимости предоставлять пользователям команду для очищения состояния приложения: если ваше приложение не может запуститься после завершения, флаг previousExecutionState будет иметь состояние notRunning , когда пользователь в следующий раз попытается запустить приложение, в подобной ситуации вы не будете пытаться восстановить состояние.

    Кроме того, нет необходимости включать в состояние сеанса номер версии. Если пользователь установил обновление в то время, когда ваше приложение было приостановлено и остановлено, и версия данных приложения была изменена, значение previousExecutionState будет сброшено. Если по каким-либо причинам вы не изменяете версию данных приложения – например, если обновления весьма незначительны, тогда ранее сохраненные данные состояния приложения могут использоваться дальше. Но в данном случае перед нами – то же самое приложение, поэтому управление версиями состояния сеанса не требуется.

    Врезка: использование sessionStorage и localStorage HTML5

    Если хотите, вы можете использовать объект HTML5 localStorage для хранения данных состояния сеанса приложения и других данных приложения. Содержимое объекта хранится в папке localFolder . Содержимое localStorage не загружается до первой попытки доступа к нему и ограничено объемом в 10 Мб на приложение. API WinRT и WinJS, с другой стороны, ограничены лишь емкостью файловой системы.

    Что касается объекта HTML5 sessionStorage , он, на самом деле, не нужен, когда вы используете элементы управления страниц и поддерживаете общий контекст скрипта для этих страниц, так как переменные, находящиеся в памяти уже выполняют нужную функцию. Однако, если вы изменяете контекст страниц, используете ссылки <a> или document.location для целей навигации, sessionStorage способен быть полезным. Кроме того, вы можете кодировать информацию в URI, как обычно делается в веб-приложениях.

    И sessionStorage , и localStorage полезны внутри страниц iframe , исполняющихся в веб-контексте, так как API WinRT недоступны. В то же время, вы можете загрузить WinJS в веб-контекст (такая возможность поддерживается) и объекты WinJS.Application.local , roaming , и temp будут работать, используя буферы для данных, расположенные в памяти, вместо файловой системы.

    Локальное и временное состояние

    В отличие от состояния сеанса, которое восстанавливается лишь в особых обстоятельствах, локальное состояние приложения, которое состоит из этих параметров и других данных, всегда применяется при запуске приложения. Сюда попадает все, что пользователь может настроить, несмотря на то, что это так же часть перемещаемых данных, в таком случае эти данные так же загружаются при запуске приложения. Любые другие кэшированные данные, сохраненные результаты поиска, недавно использованные элементы, экранные элементы, предпочитаемые медиа-форматы, настройки, зависящие от устройства, так же попадают сюда. Коротко говоря, если какие-то данные не являются чистым состоянием сеанса, либо – частью перемещаемого состояния, это – либо локальное, либо временное состояние приложения. (Помните, что учетные данные следует хранить в Хранилище учетных данных вместо хранения их среди данных приложения).

    Те же API, которые мы видели, работают и для этих видов состояния, включая все API WinRT, объекты WinJS.Application.local и temp , и HTML localStorage . Так же вы можете использовать HTML5 API IndexedDB, SQLite, и HML App Cashe – это лишь другие формы локальных данных приложения.

    При работе с локальными и временными данными очень важно назначать им номер версии, так как они сохраняются и при обновлении приложения (хотя временное состояние в это время очищается). В процессе любого обновления приложения будьте готовы к тому, чтобы загрузить старую версию состояния приложения и выполнить необходимые обновления, или просто решить, что версия слишком стара и очистить данные (Windows.Storage.ApplicationData.current.clearAsync ), прежде чем задавать новые значения по умолчанию. Как упоминалось выше, возможно осуществить перенос состояния с использованием фоновой задачи (смотрите Главу 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой").

    Вообще говоря, локальные и временные данные приложения – это одно и то же – они имеют одинаковые API, и хранятся в папках, расположенных в одном и том же месте. Временные данные, однако, не поддерживают параметры и контейнеры параметров. Другое различие заключается в том, что содержимое в папке временных данных (вместе с HTML5-кэшем приложения) могут подвергнуться воздействию средства очистки диска Windows. Это означает, что временные данные могут исчезнуть в любой момент, когда пользователь захочет освободить немного дискового пространства. Так же вы можете использовать фоновую задачу с триггером обслуживания для самостоятельного выполнения очистки (опять же, смотрите Главу 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой").

    По этим причинам, временные данные следует использовать для хранения информации, которая оптимизирует производительность приложения, но не для данных, которые критически важны для работы приложения. Например, если в пакете приложения имеется JSON-файл, который вы обрабатываете или распаковываете при первом запуске программы, чтобы в дальнейшем приложение работало быстрее, и вы не выполняете никаких изменений этих данных из приложения, вы можете решить хранить это среди временных данных. То же самое справедливо для графических ресурсов, которые вы можете обработать для применения на конкретном устройстве, на котором исполняется приложение. Вы всегда можете повторить этот процесс, воспользовавшись исходным источником, таким образом, эти данные – так же хороший кандидат для хранения среди временных данных. Похожим образом, если вы получили данные из онлайнового сервиса для целей оптимизации производительности (таким образом, вы можете обновлять локальные данные инкрементно), вы всегда можете запросить их снова. Это особенно полезно для обеспечения возможности работы без подключения к сети, хотя в некоторых случаях может понадобиться предоставить пользователям выбрать, следует ли сохранять эту информацию среди локальных данных приложения или среди временных (параметр, который может появиться в интерфейсе чудо-кнопки Параметры вместе с командой, которая позволяет очистить кэш).

    Врезка: AppCache HTML5

    Приложения для Магазина Windows могут использовать кэш приложения HTML5 как часть стратегии кэширования и работы в оффлайновом режиме. Это особенно полезно в элементах веб-контекста iframe, где этот механизм можно использовать для любого содержимого. Например, приложение для чтения книг в онлайн-режиме может показывать содержимое в iframe, и если страницы включают теги кэша приложения, они будут сохраняться и будут доступны в режиме, когда сетевое соединение недоступно. В локальном контексте, кэш приложения работает для неисполняемых ресурсов, таких, как изображения, аудио, видео, но не для HTML или JavaScript.

    IndexedDB и другие технологии баз данных

    Многие виды локальных данных приложения прекрасно подходят для хранения в базе данных. В приложениях для Магазина Windows API IndexedDB доступно посредством объектов ), в справочных материалах по Indexed Database API (http://msdn.microsoft.com/library/windows/apps/hh466139.aspx) и в примере "IndexedDB" (http://code.msdn.microsoft.com/windowsapps/IndexedDB-sample-eb1e95af).

    Хотя база данных IndexedDB хранится среди локальных данных приложения, знайте, что существуют некоторые ограничения, так как нет средств, с помощью которых приложение или операционная система могут уменьшить размер файла базы данных и очистить неиспользуемое пространство:

  • У IndexedDB есть ограничение в 250 Мб на приложение и общий системный лимит в 375 Мб на жестких дисках меньше 32 Гб, или 4% (максимум – 20 Гб) на дисках, больше 32 Гб. Таким образом возможна ситуация, что ваше приложение может не иметь достаточно места для хранения данных, в подобном случае вам нужно иметь некий запасной механизм. (При превышении лимита API будет выдавать исключение "Quota Exceeded").
  • IndexedDB в Windows 8 не поддерживает составные ключи – таким образом, сейчас не поддерживается несколько значений для ключа или индекса (multientry).
  • По умолчанию, доступ к IndexedDB предоставляется только HTML-страницам, которые являются частью пакета приложения, и тем, которые объявлены как URI содержимого (смотрите раздел "Локальный и веб-контексты внутри хост-процесса приложения" Главы 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript"). Произвольные веб-страницы, которые могут быть загружены в iframe , не имеют доступа к IndexeDB, преимущественно для того, чтобы не занимать место в базе данных, объем которой ограничен 250 Мб и сохранить его для страниц приложения. Однако, вы можете предоставить произвольным страница доступ, включив следующий тег в домашнюю страницу и не устанавливая атрибут src элемента iframe до тех пор, пока не будет запущено событие DOMContentLoaded или activated :
    <meta name="ms-enable-external-database-usage" content="true"/> 
  • Помимо IndexedDB существуют и другие технологии баз данных, доступные для приложений Магазина Windows. Для создания локальных реляционных баз данных попробуйте SQLite. Это API, которое хорошо подходит для приложений, написанных на языке наподобие C#, как описано в блоге Тима Хейера (http://timheuer.com/blog/archive/2012/08/07/updated-how-to-using-sqlite-from-windows-store-apps.aspx), но, к счастью, есть и версия, которая называется SQL.js, где SQLite скомпилирован для JavaScript с использованием Emscripten (http://badassjs.com/post/18857332551/sql-js-sqlite-compiled-to-javascript-via-emscripten). Очень хорошо! В сообществе разработчиков можно найти и другие решения для JavaScript.

    Если вас беспокоят ограничения IndexedDB, вы можете воспользоваться API Win32 "Jet" или Extensible Storage Engine (ESE) (http://msdn.microsoft.com/library/windows/apps/br205753.aspx) (на них построена реализация IndexedDB). Для этого вам понадобится написать оболочку в виде компонента WinRT на C# или C++ (этому посвящена Глава 5 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой"), так как из JavaScript нельзя получить прямой доступ к этим API.

    То же самое справедливо для API баз данных сторонних разработчиков. До тех пор, пока они используют лишь API Win32, использование которых разрешено приложениям для Магазина Windows (они перечислены на странице "Win32 и COM для приложения Магазина Windows" (http://msdn.microsoft.com/library/windows/apps/br205757.aspx)), они отлично работают.

    Следует так же отметить, что Библиотека OData для JavaScript (http://www.odata.org/libraries#JavaScript) так же отлично работает с приложениями для Магазина Windows, реализуя доступ к онлайновым SQL-серверам, так как протокол OData работает посредством REST.

    И, наконец, еще одна возможность для организации данных, хранящихся в файлах, по которым можно организовать поиск, заключается в использовании системного индекса (system index) путем создания папки с именем "Indexed" в локальной папке данных приложения. Содержимое файлов в этой папке будет проиндексировано системной службой индексирования и к этому содержимому можно обращаться посредством запросов, использующих Advanced Query Syntax (AQS) с помощью API, описанного ниже в разделе "Расширенные возможности запросов к файлам". Так же вы можете осуществлять поиск, основанный на свойствах Windows (http://msdn.microsoft.com/library/windows/desktop/dd561977.aspx), делая такой подход простой альтернативой использования баз данных.

    Перемещаемое состояние

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

    Этот механизм работает очень просто. Во-первых,папка roamingFolder и контейнер roamingSettings ведут себя точно так же, как соответствующие локальные объекты. До тех пор, пока их общий размер не превышает Windows.Storage.ApplicationData.current.roamingStorageQuota , Windows будет копировать эти данные на другие устройства, на которых авторизовался тот же самый пользователь, и на которых установлено то же приложение. На самом деле, когда приложение установлено, Windows пытается скопировать перемещаемые данные, таким образом, они уже присутствуют при первом запуске приложения.

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

    Принятие решения о том, как должен выглядеть опыт взаимодействия пользователя с перемещаемым состоянием, это больше вопрос дизайна, чем разработки. Для этого нужно взять все параметры приложения, которые не зависят от аппаратного обеспечения устройства (такие, как параметры, связанные с размером экрана, с возможностями видео, с наличием периферийного оборудования или сенсоров) и подумать о том, имеет ли смысл перемещать тот или иной параметр. Списки избранного пользователя, например, подходят для перемещения, если они относятся к данным, которые не хранятся локально. Таким образом, избранные URI или элементы, расположенные в облачных хранилищах данных, таких, как SkyDrive, Facebook или Flickr подходят для перемещения, а списки избранного и недавно использованные файлы из локальных библиотек пользователя – не подходят. Позиция просмотра в видеофайле из облачного сервиса, наподобие потокового видео, так же может подойти для перемещения, так же, как и информация о месте, где пользователь остановился, читая журнал или книгу. Но, опять же, если данное содержимое локально, тогда, возможно – нет. Конфигурации учетных записей, наподобие параметров почтового ящика, так же часто хорошие кандидаты, таким образом пользователю не придется настраивать приложение снова на другом устройстве.

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

    Для того чтобы минимизировать размер перемещаемого состояния и не превышать квоту, вы можете задействовать API ), из материала "Основные принципы работы SkyDrive" (http://msdn.microsoft.com/library/live/hh826545.aspx) (здесь есть список поддерживаемых типов файлов), и из примера "PhotoSky" (http://msdn.microsoft.com/library/live/hh826545.aspx). Разъяснения, касающиеся этого и других сервисов Windows Live вы можете найти в блоге "Создание Windows 8", в материале "Реализация возможностей по работе с облаком в приложениях Windows 8 с помощью SkyDrive" (http://blogs.msdn.com/b/b8_ru/archive/2011/10/03/windows-8-skydrive.aspx).

    Сейчас, возможно, у вас есть множество других вопросов о том, как, на самом деле, работает перемещение данных: "Как часто синхронизируются данные", "Как можно управлять различными версиями данных?", "Что еще нужно об этом знать?". Это хорошие вопросы, и, к счастью, на них есть достойные ответы!

  • Учитывая наличие сетевого соединения, перемещаемое состояние на активном компьютере обновляется каждые 30 минут. Так же перемещение происходит немедленно, когда пользователь входит в систему или блокирует компьютер. Блокирование компьютера всегда – лучший способ инициировать синхронизацию с облаком. Обратите внимание на то, что если облачные сервисы знают лишь о пользователе (то есть, об учетной записи Microsoft), имеющем лишь одно устройство, синхронизация с облачным сервисом происходит лишь раз в день. Когда сервисы получают информацию о том, что у пользователя есть несколько устройств, синхронизация происходит каждые 30 минут. Если приложение деинсталлировано со всех компьютеров кроме одного, период синхронизации увеличивается.
  • При сохранении перемещаемого состояния вы можете записывать данные в любое время, например, при их изменении. Вам не нужно заботиться о групповой записи параметров, так как у Windows есть встроенный механизм для комбинирования изменений и уменьшения общей нагрузки на сеть.
  • Если у вас есть группа параметров, которая по объективным причинам должна перемещаться как единое целое, реализуйте ее в виде взаимосвязанных параметров в контейнере roamingSettings .
  • В случае с файлами, созданными внутри roamingFolder , они не будут перемещаться до тех пор, пока они открыты для записи (то есть, до тех пор, пока открыты потоки, связанные с ними). Полезно проверить, закрыты ли все потоки при приостановке приложения.
  • Windows позволяет всем приложениям иметь до 8 Кб параметров с "высоким приоритетом", которые будут перемещены в течение одной минуты, таким образом, экземпляры приложения на нескольких устройствах оказываются лучше синхронизированными. Для того, чтобы это использовать, создайте отдельный параметр или группу взаимосвязанных параметров в корневой части roamingSettings и дайте этому объекту имя HighPriority, таким образом, мы получим roamingSettings.values["HighPriority"] (контейнер с этим именем будет перемещаться обычным образом). До тех пор, пока размер этого параметра не превышает 8 Кб, он будет перемещаться в течение минуты после изменения. Если размер будет превышен, он будет перемещаться с обычным приоритетом. Демонстрацию этого вы можете найти в Сценарии 6 примера "Данные приложения".
  • На доверенном компьютере, параметры пользователя общеситемного значения, наподобие конфигурации начальной страницы, автоматически перемещаются независимо от приложений. Они так же включают в себя зашифрованные учетные данные, которые приложения записали в хранилище учетных данных. Приложениям никогда не следует пытаться перемещать пароли. Приложения, которые создают дополнительные плитки (как мы увидим в лекции 2 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой") могут указать, следует ли копировать эти плитки на новое устройство при установке на него приложения.
  • Когда существует несколько версий данных приложения, используемых одним и тем же приложением (с несколькими версиями приложения, конечно), Windows будет управлять каждой версией данных приложения раздельно, что означает, что более новые данные приложения не переместятся на устройство с более старой версией приложения. В свете этого, полезно не применять слишком агрессивное изменение версий данных приложения, так как это может прервать связь между приложениями.
  • Облачные сервисы хранят несколько версий перемещаемых данных приложения до тех пор, пока множество версий приложения используются в рамках одной и той же учетной записи Microsoft. Только когда все экземпляры приложения будут обновлены, старая версия данных может быть удалена.
  • Когда обновленное приложение воспринимает старую версию перемещаемого состояния, ему следует загрузить его как старую версию, но сохранить – как новую и вызвать setVersionAsync .
  • Избегайте использования дополнительной схемы назначения версий внутри перемещаемого состояния, как, например, внесение структурных изменений без изменения версии данных приложения посредством setVersionAsync . Так как облачный сервис управляет перемещаемыми состояниями, основываясь на номере их версии, и так как последние записанные данные выигрывают, некоторые версии приложения, которые ожидают некоторых дополнительных данных, и, на самом деле, сохраняют эти данные, могут обнаружить, что эти данные были удалены, так как немного более старые версии приложения их не записали.
  • Даже если все экземпляры приложения были удалены с устройств пользователя, облачный сервис хранит перемещаемые данные в течение "разумного срока" (около 30 дней), таким образом, если пользователь переустановит приложение в течение этого периода, он обнаружит, что ранее заданные параметры сохранились. Для того чтобы избежать этого и явным образом удалить перемещаемое состояние из облака, воспользуйтесь методом clearAsync .
  • Панель параметров и пользовательский интерфейс

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

    Когда пользователь нажимает на чудо-кнопку Параметры (это можно сделать и напрямую, использовав комбинацию клавиш Win + i), Windows отображает панель параметров – часть пользовательского интерфейса, которая заполнена различными командами для настройки параметров, а так же, в нижней части – системными настройками. Приложения могут добавлять собственные команды для настройки параметров, но не обязаны этого делать. Windows гарантирует, что какие-то настройки для приложения всегда будут присутствовать на этой панели: она автоматически показывает названия приложения и разработчика, команду "Отзывы и оценки", которая ведет к странице приложения в Магазине Windows, команду "Обновить", если обновление для приложения доступно в Магазине Windows, и команду "Разрешения", если приложение объявило какие-либо возможности в манифесте. (Обратите внимание на то, что команда "Отзывы и оценки" не отображается, если приложение запущено из Visual Studio, так как эта возможность предоставляется Магазином Windows).

    Чудо-кнопка Параметры доступна всегда, независимо от места в приложении, где вы находились, поэтому нет нужды думать о реализации подобной команды в панели приложения, не нужна подобная команда и на холсте приложения. Тем не менее, вы можете программно активировать чудо-кнопку Параметры, когда, например, вы обнаружили, что какая-то возможность выключена и оповещаете об этом пользователя. Вы можете задать ему вопрос наподобие: "Вы хотите включить функцию определения местоположения для этого приложения?", и если он ответит "Да", вы можете активировать чудо-кнопку Параметры. Это делается посредством объекта панели параметров, полученного из ), метод show которого отображает пользовательский интерфейс (или выдает исключение, если приложение находится в прикрепленном режиме просмотра, или не является приложением переднего плана, поэтому не выполняйте подобный вызов при таких обстоятельствах!). Свойство edge объекта панели параметров сообщает вам о том, с левой или с правой стороны экрана находится панель, в зависимости от ориентации интерфейса системы слева направо или справа налево (зависит от региональных установок).

    Теперь мы рассмотрели все методы и свойства этого объекта! Гораздо более интересная часть нашего рассказа посвящена тому, как можно добавлять собственные команды на панель параметров. Но сначала давайте посмотрим на руководство по использованию панели параметров.

    Руководства по дизайну панели параметров

    Помимо команд, которые Windows автоматически добавляет на панель параметров, приложение может самостоятельно добавить туда до восьми команд, обычно – около четырех. Все, что больше восьми, вызовет исключение. Так как параметры глобальны для приложения, команды, которые вы добавляете, никогда не меняются: они не чувствительны к контексту. Другими словами, на панели параметров располагают только те команды, которые воздействуют на приложение в целом. Команды, применимые лишь к определенным страницам или контексту внутри страниц, следует размещать на панели приложения или на полотне. Некоторые примеры команд верхнего уровня на панели приложения показаны на рис. 2.2. (рис 2.2) Примеры команд верхнего уровня на панели параметров. Обратите внимание на то, что нижняя часть панели всегда занята системными параметрами, а названия приложения и разработчика всегда расположены сверху. Команды "Разрешения" и "Оценки и отзывы" добавляются автоматически

    Каждая команда, предоставленная приложением, может выполнять одно из двух действий. Во-первых, эта команда может быть обычной гиперссылкой, которая ведет к страницам приложения "Справка", "Соглашение о конфиденциальности", "Условия использования", "Лицензионное соглашение" и так далее, по нажатию на которую соответствующая страница будет открыта в браузере. Другая возможность заключается в том, что команда вызывает дополнительную всплывающую панель со специализированными элементами управления, или просто iframe для отображения веб-содержимого. Вы можете реализовать страницы "Помощь", "Условия использования" и другое текстовое содержимое обоими способами вместо того, чтобы переключаться в браузер.

    Примечание. Как указано в "Сертификационных требованиях к приложениям для Windows 8" (http://msdn.microsoft.com/library/windows/apps/hh694083.aspx), в разделе 4.1., приложения, которые тем или иным образом собирает персональные данные, должны иметь политику конфиденциальности или соответствующее заявление. Это должно быть, как минимум, отражено на странице описания приложения в Магазине Windows. Хотя это и не требуется, подразумевается, что вы так же включите в панель приложения соответствующую команду.

    Дополнительные всплывающие элементы создают с помощью элемента управления WinJS.UI.SettingsFlyout . На рис. 2.3. есть примеры. Обратите внимание на то, что дополнительные панели параметров бывают двух размеров: узкая (346 пикселей) и широкая (646 пикселей). Руководства по дизайну предлагают делать все дополнительные панели параметров приложения одного размера – то есть, не делать некоторые из них узкими, а некоторые – широкими. В любом случае, у вас будет лишь пара подобных панелей, так что это не должно превратиться в проблему. Кроме того, обратите внимание на о, что всплывающий элемент Разрешения (Permissions), показанный в левой части На рис. 2.3. предоставляется Windows автоматически и он настроен в соответствии с возможностями, заявленными в манифесте. Некоторыми возможностями, наподобие определения местоположения, можно управлять из этой панели. Другие, наподобие доступа к Интернету и к библиотекам, просто перечислены, так как пользователь не может включать или выключать их. (рис 2.3) Примеры дополнительных панелей параметров в приложениях Windows 8 Travel, Weather, News и Music. Первые три – узкие, четвертая – широкая. Обратите внимание на то, что каждая из панелей, предоставленная приложением, соответствующим образом брендирована и имеет кнопку "Назад", ведущую к основной панели параметров. Панель Разрешения (Permissions) предоставлена системой, и, таким образом, отражает системную тему. Ее нельзя настроить.

    Обычно используемые здесь группы параметров – это те, которые позволяют пользователю настроить особенности перемещения данных приложения – то есть, группа параметров, которая определяет, какие данные состояния приложения перемещаются (это можно увидеть, выполнив команду Изменение параметров компьютера > Синхронизация параметров (PC Settings > Sync You Settings)). Кроме того, рекомендуется включать в панель параметров команды управления учетной записью/профилем, так же как и возможности по входу и выходу. Как отмечено в лекции 1, вход в приложение и лицензионное соглашение, которые необходимы для продолжения работы следует показать при запуске приложения. Для текущих возможностей, связанных со входом в приложение, для просмотра лицензионного соглашения и так далее, создайте соответствующие команды и панели в интерфейсе чудо-кнопки Параметры. Обратитесь к материалу "Руководство и контрольный список для элементов управления входом" (http://msdn.microsoft.com/library/windows/apps/hh965453.aspx) для получения более подробных сведений по этому вопросу. Руководство по добавлению справки можно найти в материале "Добавление справки по приложению" (http://msdn.microsoft.com/library/windows/apps/hh465043.aspx).

    В плане поведения, дополнительные панели автоматически скрываются, когда они неактивны, но так же имеют заголовок с кнопкой "Назад" для возврата на основную панель параметров со всеми командами. Из-за возможности автоматического скрытия, изменения, которые вносят на панелях, применяются немедленно: здесь нет кнопок "OK" или "Применить" или чего-то подобного. Если пользователь хочет вернуться к прежнему варианту настроек, ему следует просто восстановить исходные параметры.

    По этой причине, хорошо использовать простые элементы управления, которые легко переключить в прежнее состояние, вместо сложных наборов элементов управления, которые сложнее вернуть к исходному виду. Рекомендовано использовать тумблеры для параметров, имеющих значения включено/выключено (вместо флагов), кнопки для выполнения некоторых действий (но без закрытия панели параметров), гиперссылки (для открытия браузера), текстовые поля ввода (следует задать им соответствующий тип – адрес электронной почты (email address), пароль (password) и так далее), переключатели для групп, включающих в себя до пяти взаимоисключающих элементов, и списки (элемент select) для четырех-шести текстовых элементов.

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

    Вот еще некоторые вещи, которых надо избегать, работая с панелью параметров:

  • Не используйте панель параметров для размещения команд, имеющих отношение к рабочему процессу. Они должны располагаться на панели приложения, или на полотне, как показано в лекции 1.
  • Не используйте команды верхнего уровня в панели параметров для выполнения действий, которые не относятся к связи с другим приложениям (как в случае с браузером). Таким образом, команды верхнего уровня никогда не следует использовать для выполнения каких-либо действий внутри приложения.
  • Не используйте команды панели параметров для навигации по приложению.
  • Не используйте элемент управления WinJS.UI.SettingsFlyout как обычный элемент управления.
  • Теперь давайте посмотрим на то, как соответствующим образом использовать чудо-кнопку Параметры и элемент управления SettingsFlyout.

    Расположение команд на панели параметров

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

    Есть два пути реализации этого в приложениях, написанных на HTML и JavaScript: использовать WinRT напрямую, или применить вспомогательные функции WinRT. Рассмотрим это на примере простой команды Справка (Help).

    Для того чтобы знать, когда чудо-кнопка активируется посредством WinRT, получим объект панели параметров из ) и добавим прослушиватель для его события commandsrequested (это событие WinRT, поэтому удостоверьтесь в том, что прослушиватель, если это необходимо, удален):

    // Переменная n здесь – это удобное краткое имя	
    var n = Windows.UI.ApplicationSettings;	
    var settingsPane = n.SettingsPane.getForCurrentView();	
    settingsPane.addEventListener("commandsrequested", onCommandsRequested);
     

    В обработчике события создадим объект ) для каждой команды, где каждая команда имеет свойства id, label, и функцию invoked, которая вызывается, когда пользователь коснулся элемента команды или щелкнул по нему мышью. Все это может быть задано в конструкторе, как показано ниже:

    function onCommandsRequested(e) {
    // n все еще является кратким именем для Windows.UI.ApplicationSettings
    var commandHelp = new n.SettingsCommand("help", "Help", helpCommandInvoked);
    e.request.applicationCommands.append(commandHelp);
    }	
     

    Вторая строка кода – это место, где вы затем добавляете подобные команды на панель параметров. Это выполняется путем присоединения их к объекту ). Этот объект – конструкция WinRT, которая называется вектор (vector) и используется для управления коллекцией элементов с помощью команд наподобие append и insertAt. В данном случае у нас есть вектор объектов SettingsCommand, как вы можете видеть выше, к нему довольно просто присоединять команды. Подобный вызов выполняется для каждой команды, можно и передать массив команд методу replaceAll вместо метода append. То, что потом происходит в обработчике invoked для каждой команды, весьма интересно, и мы вернемся к этому в следующем разделе.

    Кроме того, вы можете заранее заполнить вектор ) показывает пример подобного подхода, который я модифицировал здесь для того, чтобы показать использование replaceAll:

    var n = Windows.UI.ApplicationSettings;
    var settingsPane = n.SettingsPane.getForCurrentView();
    var vector = settingsPane.applicationCommands;
    
    //Гарантирует отсутствие заданных команд в интерфейсе чудо-кнопки Параметры 
    vector.clear();
    
    var commands = [ new settingsSample.SettingsCommand("Custom.Help", "Help", OnHelp),
    new n.SettingsCommand("Custom.Parameters", "Parameters", OnParameters)];
    vector.replaceAll(commands);
     

    При таком подходе вам не нужно добавлять прослушиватель для commandsrequested или напрямую обрабатывать это событие.

    Теперь, так как большинство приложений, вероятнее всего, будет использовать некоторое количество настроек, WinJS предоставляет несколько вспомогательных механизмов для всего процесса. Во-первых, вместо прослушивания события WinRT, можно просто назначить обработчик для WinJS.Application.onsettings (это – контейнер для commandsrequested):

    WinJS.Application.onsettings = function (e) {
    // ...
    };
     

    В вашем обработчике, создайте JSON-объект, описывающий ваши команды и сохраните этот объект в )):

    WinJS.Application.onsettings = function (e) {	
    e.detail.applicationcommands =	
    { "help": { title: "Help", href: "/html/2-SettingsFlyout-Help.html" } };
    WinJS.UI.SettingsFlyout.populateSettings(e);	
    };
     

    Метод populateSettings обходит объект e.details.applicationcommands и вызывает метод WinRT applicationCommands.append для каждого элемента. Это предоставляет вам более компактный способ для выполнения тех же действий, что вы выполняли с помощью WinRT и так же упрощает реализацию команд параметров, как мы увидим ниже.

    Примечание. Вспомогательные функции WinJS специально разработаны для создания элемента управления SettingsFlyout, заполненного из HTML-файла, который вы указываете в свойстве href. Это свойство должно ссылаться на содержимое, находящееся в пакете приложения; его нельзя использовать для создания элементов управления параметров, которые осуществляют переход по URI (что обычно используется для команд "Условия предоставления услуг" и "Заявление о конфиденциальности"). В подобных случаях вы должны использовать API WinRT напрямую вместе с WinJS.UI.SettingsFlyout.populateSettings. Опять же, это просто – поместить веб-содержимое прямо во всплывающий элемент параметров с помощью iframe, который поддерживает параметры в соответствии с опытом использования приложения.

    Реализация команд: ссылки и всплывающие элементы параметров

    С технической точки зрения внутри функции invoked команды параметров вы можете делать все, что угодно. Правда! Конечно, как описано выше в руководстве по дизайну, есть рекомендации, касающиеся того, как следует и как не следует использовать эти команды. Например, команды в панели параметров не должны действовать как команды панели приложения, которые воздействуют на содержимое, их не следует использовать для навигации внутри приложения. В идеальном варианте эти команды выполняют одну из двух функций: либо открывают гиперссылки (в браузере), либо отображают дополнительные панели параметров.

    На базе модели параметров WinRT, при открытии гиперссылки используется API x) как показано ниже:

    function helpCommandInvoked(e) {	
    var uri = new Windows.Foundation.Uri("http://example.domain.com/help.html"); 
    Windows.System.Launcher.launchUriAsync(uri).done();	
    }	
     

    Во втором случае дополнительные панели реализуются с помощью элемента управления ). Опять же, с технической точки зрения, вы не обязаны использовать этот элемент управления: вы можете отобразить в обработчике Как насчет краткой комбинации из четырех имен событий? Стоит так же отметить, что будет срабатывать событие document.body.DOMNodeInserted, когда всплывающий элемент будет появляться. и имеет другие полезные возможности. И хотя вы можете поместить любой HTML-код в элемент управления, включая другие элементы управления, и обычный всплывающий элемент поддерживает вертикальную прокрутку, на самом деле нет причин не использовать его.

    Так как он является элементом управления WinJS, вы можете объявить ) содержит следующий всплывающий элемент, отображающий справку (здесь текстовое содержимое опущено, код немного переформатирован), в результате получается то, что показано на рис. 2.4.

    <div data-win-control="WinJS.UI.SettingsFlyout" aria-label="Help settings flyout" 
     data-win-options="{settingsCommandId:'help', width:'wide'}">
    <!-- Используем либо 'win-ui-light' либо 'win-ui-dark' в зависимости от различия
    цвета заголовка и фона; фоновый цвет отражает индивидуальность приложения -->
    <div class="win-ui-dark win-header" style="background-color:#00b2f0">
    <button type="button" onclick="WinJS.UI.SettingsFlyout.show()" class="win-backbutton"></button>
    <div class="win-label">Help</div>
    <img src="../images/smallTile-sdk.png" style="position: absolute; right: 40px;"/>
    </div>
    <div class="win-content ">
    <div class="win-settings-section">
    <h3>Settings charm usage guidelines summary</h3>
    <!-- Другое содержимое опущено -->
    <li>For more in-depth usage guidance, refer to the
    <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh770544"> 
     App settings UX guide</a>.</li>
    </div>
    </div>
    </div>
    

    Как всегда, у этого элемента управления есть параметры, так же, как и несколько применимых классов стилей win-*. Есть два параметра, это settingCommandId, идентификатор элемента, назначение которого очевидно, и width, который может принимать значения 'narrow' или 'wide'. И тот и другой присутствуют в вышеприведенном примере. Здесь применены стили win-settingsflyout, который задает стиль всего элемента управления (обычно не используется, за исключением основы для других правил стиля), а так же win-ui-light и win-ui-dark, которые применяют темную или светлую тему к частям всплывающего элемента. В данном примере использована темная тема для заголовка, в то время как остальные части элемента управления стилизованы с помощью светлой темы по умолчанию. (рис 2.4) Всплывающий элемент среди параметров, отображающий справку (обрезанный вертикально) из Сценария 2 примера о "Параметры приложения". Обратите внимание на гиперссылку в правом нижнем углу

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

    Как мы показываем этот всплывающий элемент, когда активирована команда верхнего уровня на панели параметров? Самый простой способ – позволить WinJS позаботиться о деталях, используя сведения, которые вы предоставили для WinJS.UI.SettingsFlyout.populateSettings. Вот пример, снова из Сценария 2, который мы видели в предыдущем разделе:

    e.detail.applicationcommands =	
    { "help": { title: "Help", href: "/html/2-SettingsFlyout-Help.html" } };
    WinJS.UI.SettingsFlyout.populateSettings(e);
    };
     

    В JSON-коде, который вы назначили applicationCommand, каждый объект определяет и команду и связанный с ней всплывающий элемент. Имя объекта – это id всплывающего элемента ("help"), его свойство title задает надпись для команды верхнего уровня на панели параметров ("Help"), свойство href задает HTML-страницу, где описан всплывающий элемент с заданным id ("/html/2-SettingsFlyout-Help.html").

    Используя эту информацию, WinJS может и заполнить панель параметров верхнего уровня, и обеспечить автоматическую активацию нужного всплывающего элемента (вызывая WinJS.UI.Process для этого), и вам не нужно писать для этого какой-либо код. Поэтому в сценариях примера вы не увидите явного вызова showSettings, а лишь вызовы populateSettings.

    Вызов всплывающего элемента параметров из программного кода

    Посмотрим теперь на то, что происходит внутри описываемых процессов. В дополнении к элементу управления, который используется для определения конкретного всплывающего элемента, ) отображает панель параметров Windows верхнего уровня – то есть - Windows.UI.ApplicationSettings.SettingsPane. Поэтому вы можете видеть, что событие click кнопки "Назад" в вышеприведенной разметке привязано напрямую к методу show, так как нажатие на кнопку "Назад" должно возвратить нас к интерфейсу верхнего уровня.

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

    Метод ), с другой стороны, показывает конкретный всплывающий элемент настроек, который определен где-то в приложении. Сигнатура метода выглядит как showSettings(<id> [, <page>]) , где <id> идентифицирует всплывающий элемент, который вам нужен, и необязательный параметр <page> указывает на HTML-документ, в котором следует искать всплывающий элемент с заданным <id> , который не найден в текущем документе. Таким образом, showSettings всегда начинает с просмотра текущего объекта document на предмет элемента WinJS.UI.SettingsFlyout, который имеет совпадающее с заданным свойство settingsCommandId или HTML-атрибут id. Если подобный всплывающий элемент найден, он показывается.

    Если разметка в предыдущем разделе (с рис. 2.4.) содержится в той же HTML-странице, которая загружена в приложении, следующая строка кода покажет этот всплывающий элемент:

    WinJS.UI.SettingsFlyout.showSettings("help"); 

    В подобном случае вы так же можете опустить часть href JSON-объекта, который передается в populateCommands, но только если всплывающий элемент уже содержится в текущем HTML-документе.

    Параметр <page>, в свою очередь, позволяет вам разделить всплывающие элементы параметров и остальные страницы приложения. Его значение – это относительный URI, относящийся к пакету приложения. В примере "Параметры приложения" подобный подход используется для помещения всплывающих элементов для каждого сценария в отдельный HTML-файл. Вы так же можете поместить все ваши всплывающие элементы в один HTML-файл, до тех пор, пока они имеют уникальные id. В любом случае, если вы предоставляете параметр <page>, showSettings загрузит код указанного HTML-файла в текущую страницу, используя WinJS.UI.Page.load (который вызовет WinJS.UI.processAll), просматривает полученное дерево DOM на предмет id всплывающего элемента, совпадающего с заданным <id> и показывает его. Если всплывающий элемент найти не удается, вызывается исключение.

    Сценарий 5 примера показывает этот способ программной активации элемента. Это так же хороший пример (рис. 2.5.) всплывающего элемента с вертикальной прокруткой:

     WinJS.UI.SettingsFlyout.showSettings("defaults", "/html/5-SettingsFlyout-Settings.html");

    (рис 2.5) Всплывающий элемент настроек из Сценария 5 примера "Параметры приложения", показывающий, как всплывающие элементы поддерживают вертикальную прокрутку. Обратите внимание на позицию полосы прокрутки при отображении верхней части элемента (слева), и нижней (справа)

    Вызов showSettings, таким образом, это то, что используется в любом обработчике invoked команды, и то, что WinJS выполняет внутри populateCommands. Но это так же означает, что вы можете вызвать showSettings из любого места вашего кода, когда вам нужно показать конкретную панель параметров. Например, если вы столкнулись с ошибкой, с которой можно справиться, изменив параметры приложения, вы можете предоставить в сообщении об этом кнопку, которая вызывает showSettings для открытия конкретной панели. И, если это нужно, метод hide всплывающего элемента может скрыть его. Это не действует на панель параметров верхнего уровня, для скрытия которой нужно использовать Windows.UI.ApplicationSettings.SettingsPane.getForCurrentView.hide.

    Вы можете использовать showSettings и hide вместе, на самом деле, если вам нужно организовать перемещение к панелям параметров третьего уровня. Таким образом, одна из ваших собственных панелей параметров может содержать, команду, которая вызывает hide для текущего всплывающего элемента, и затем – showSettings для открытия другого. Кнопка "Назад" этого дополнительного элемента (у них всегда должна быть такая кнопка), похожим образом, вызывает hide для текущего элемента, и showSettings для того, чтобы всплывающий элемент второго уровня снова появился. Тем не менее, мы не рекомендуем делать ваши параметры настолько сложными, чтобы понадобились всплывающие элементы третьего уровня, но такая возможность есть, если у вас есть необходимость в подобном.

    Зная о том, как showSettings ищет всплывающий элемент так же полезно, если вы хотите программно создать элемент WinJS.UI.SettingsFlyout. До тех пор, пока подобный элемент управления находится в DOM, когда вы вызываете showSettings с его id, WinJS может найти его и отобразить, как и другие элементы. Подобный подход так же работает, хотя я не пробовал это сделать и не подготовил соответствующего примера, использующего такой гибридный подход. Так как showSettings загружает заданную HTML-страницу как элемент управления страницы с помощью WinJS.UI.Pages.load, эта страница так же может включать собственный скрипт, в котором вы можете задать объект элемента управления страницы с помощью методов вроде processed и ready. В этих методах вы, затем, можете выполнить необходимые настройки всплывающих элементов настроек, заданных в разметке.

    Врезка: Изменение разрешений

    Обычный вопрос, который связан с параметрами, заключается в том, может ли приложение получить событие, когда пользователь меняет параметры на панели Разрешения. Ответ на этот вопрос отрицательный. Что означает, что вы можете понять, что доступ к какой-то возможности закрыт, либо обрабатывая исключение Access Denied (Доступ запрещен), когда пытаетесь воспользоваться той или иной возможностью. Вам всегда следует обрабатывать ошибки отказа в доступе, так как пользователь может запретить доступ к возможности при первой попытке использования соответствующего API. Когда это происходит, вы отображаете сообщение об отключенных разрешениях (как показано на примере приложения "Here My Am!" в лекции 1) и предоставляете некоторые интерфейсные элементы для выполнения нужной операции. Однако, пользователю все еще нужно самостоятельно активировать команду Разрешения. Дополнительные подробности вы можете узнать в материале "Руководство для устройств, осуществляющих доступ к персональным данным" (http://msdn.microsoft.com/library/windows/apps/Hh768223.aspx).

    Данные пользователя: библиотеки, средства выбора файлов и файловые запросы

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

    Наша первая задача, касающаяся пользовательских данных, заключается в том, чтобы решить, где их разместить, и как получить к ним доступ. Реализация этой задачи включает в себя различные библиотеки пользовательских данных, съемные носители информации и средства выбора файлов. Использование кэша прав доступа так же важно, так как позволяет запоминать факты предоставления пользователем доступа к файлу или папке, к которым мы, в обычных условиях, не имеем программного доступа. Хорошая новость обо всех этих папках и файлах заключается в том, что работа с ними происходит с помощью те же классов StorageFolder и StorageFile, с которыми мы уже знакомы. Другая важная тема, которую мы рассмотрим, касается использования файловых запросов – наиболее богатого возможностями способа для перечисления содержимого папок и библиотек, которое предоставляет возможности для качественного визуального представления данных в элементах управления наподобие ListView.

    Как мы уже видели, приложения для Магазина Windows, по умолчанию, имеют доступ лишь к собственному пакету и к папкам данных приложения. Это означает, что по умолчанию у приложения нет доступа к типичным местам хранения пользовательских файлов! Есть два способа для предоставления такого доступа:

  • Объявить возможность доступа к библиотеке в манифесте.
  • Позволить пользователю выбрать расположение посредством средства выбора файлов (File Picker).
  • Посмотрим сначала на средство выбора файлов, так как во многих случаях это все, что, на самом деле, вам понадобится! Но есть и другие сценарии, такие, как приложения, ориентированные на работу с библиотеками – при реализации которых вам нужен прямой доступ к библиотекам. Для этих целей в манифесте предусмотрено пять функциональных возможностей, как показано слева на рис. 2.6. Три из них, Библиотека музыки (Music Library), Библиотека изображений (Pictures Library) и Библиотека видео (Video Library) – предоставляют полный доступ для чтения и записи к пользовательским папкам музыки, изображений и видео. Информация об этих возможностях на странице информации о приложении в Магазине Windows и на панели параметров Разрешения, но пользователь не может управлять ими при исполнении программы. Конечно, если не вполне очевидно, зачем вы объявили эти возможности, убедитесь в том, что вы пояснили это на странице сведений о приложении. Что касается возможностей Библиотека документов (Documents Library) и Съемные носители (Removable Storage), просто объявить эти возможности недостаточно: вам так же нужно задать сопоставление с конкретными типами файлов, которыми ограничено приложение. (Возможность Библиотека документов (Documents Library) предназначена только для приложений, которые нуждаются в открытии встроенного содержимого в другом документе). (рис 2.6) Возможности, связанные с данными пользователя в редакторе манифеста (слева), и редакторе сопоставления типов файлов (справа). Обратите внимание на красный знак "Х", который появляется на панели Возможности (Capabilities), когда необходимы дополнительные объявления, связанные с выбранной возможностью. Красный X на панели Объявления (Declarations) показывает, что введенная информация пока не полна.

    Врезка: API фоновой передачи данных

    Тема, которая относится к пользовательским данным, но которую мы не будем раскрывать в подробностях до Главы 3 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", это API WinRT ). Это API позволяет вам выполнять загрузку или отправку файлов независимо от жизненного цикла приложения – то есть – делать это, когда приложение выполняется, приостановлено или полностью остановлено. Это API существует потому, что передача больших файлов на сетевые ресурсы и с них, является обычной потребностью приложений, но при подобной передаче само приложение может и не исполняться в фоновом режиме и не потреблять электроэнергию. Вместо этого приложение настраивает задачу передачи данных с помощью системных средств, и эта задача будет исполняться даже если приложение будет закрыто. Когда приложение будет запущено снова, оно может проверить статус выполнения этой задачи.

    Использование средства выбора файлов

    Хотя словосочетание "Средство выбора файлов" звучит не особенно шикарно, это, по-моему, одна из самых замечательных возможностей Windows 8. "Подождите минуту!", - скажете вы, "Как, элемент пользовательского интерфейса может выбирать папки и файлы. Да, это здорово!". Причина заключается в том, что используя это средство пользователь может просматривать и выбирать любые данные. Это не только то, что хранится в локальной файловой системе или в локальных сетевых хранилищах, но и те данные, которые доступны благодаря так называемым поставщикам выбора файлов (file picker providers). Эти приложения обычно содержат библиотеки данных, которые в противном случае были бы расположены на веб-сервисе, внутри собственной базы данных приложения, или даже предоставляют файлы, создаваемые по запросу, и предоставляют к ним доступ как к части локальной файловой системы.

    Немного подумайте об этом (как я предлагал вам сделать в лекции 1 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript"). Когда вы хотите поработать с изображением с фото-сервиса, наподобие Flickr или Picasa, что вы обычно делаете? Первым шагом является загрузка нужного файла и сохранение его в локальной файловой системе с помощью некоторого приложения, которое предоставляет вам интерфейс к веб-сервису (это может быть веб-приложение). Затем вы можете выполнить желаемые правки и модификации, после чего обычно нужно снова загрузить файл в сервис. На самом деле, все не так уж и плохо, за исключением того, что вы тратите время на переключение между разными приложениями, и, очевидно, загрязняете систему множеством временных файлов, взаимоотношения которых с вашими файлами в Интернете скоро будут забыты.

    Если у вас есть поставщик выбора файлов, который позволяет получать прямой доступ к подобным файлам, и для записи, и для чтения, все эти дополнительные шаги становятся ненужными, равно как и становится ненужным переключение между приложениями. Это означает, что поставщик выбора файлов фото-сервиса открывает другим приложениям возможность загружать, править и сохранять онлайновое содержимое так, как если бы оно находилось в локальной файловой системе. Приложениям, принимающим данные, не нужно ничего знать о подобных веб-сервисах, и они автоматически получают доступ к тем большему количеству сервисов, чем больше приложений-поставщиков будет установлено. Более того, поставщики могут представлять данные, которые обычно не хранятся в виде файлов так, если бы они были файлами. Например, приложение Camera (Камера) в Windows 8 – это поставщик выбора файлов, который позволяет вам активировать камеру, сделать снимок и затем возвращает этот снимок так, если бы он был взят из файловой системы. Все это дает пользователям естественные средства для работы с данными, и неважно, где эти файлы расположены. Как я и сказал, я думаю, что это – замечательная возможность!

    Мы поговорим подробнее о поставщиках выбора файлов в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой". Наша более близкая цель заключается в изучении средств выбора файлов для получения объектов StorageFile или StorageFolder.

    Пользовательский интерфейс средства выбора файлов

    Прежде чем смотреть на код, познакомимся поближе с пользовательским интерфейсом средства выбора файлов. Когда средство запущено, вы увидите его полноэкранное представление ( рис. 2.7), которое представляет средство выбора файлов в режиме выбора одного элемента, данные отображаются в виде миниатюр. В подобном режиме просмотра элементы отображаются в виде значков в элементе управления ListView, со всплывающим элементом управления, содержащим подробную информацию, который появляется, когда указатель мыши зависает над элементом. В некотором смысле, средство выбора файлов похож на приложение, запущенное для определенных целей, и оно создано для того, чтобы быть привлекательным и иммерсивным, как и прочие приложения для Магазина Windows.

    На рис. 2.7. заголовок Pictures (Изображения) показывает текущее расположение, открытое в средстве выбора файлов. Выпадающий список Sort By Name (Сортировать по имени) позволяет вам выбирать другие критерии сортировки, так же, как выпадающий список в области заголовка Files (Файлы) позволяет вам выбирать другое расположение, как показано на рис. 2.8. Это расположения включают в себя другие области файловой системы (за исключением защищенных областей, наподобие папок Windows и Program Files), сетевые расположения и другие приложения – поставщики информации. (рис 2.7) Средство выбора файлов в режиме выбора одного элемента, открытое для Библиотеки изображений в режиме просмотра миниатюр, со всплывающим элементом подсказки, показанным для одного из элементов (для головы Сфинкса), в то же время рамка выделения присутствует у другого элемента (Тадж-Махал) (рис 2.8) Выбор другого расположения для просмотра файлов. Обратите внимание на то, что приложения-поставщики перечислены вместе с расположениями файловой системы

    Выбор другого расположения в файловой системе переносит нас туда, конечно, из него можно перейти в другие папки. Выбор приложения, с другой стороны, запускает это приложение посредством контракта поставщика выбора файлов. В подобном случае появляется пользовательский интерфейс, предоставляемый системой (но настраиваемый приложением), наподобие того, который показан на рис. 2.9. Здесь выпадающий список около заголовка позволяет вам переключаться к другим расположениям средства выбора файлов, и кнопки Открыть (Open) и Отменить (Cancel) работают так, как и должны для того, что выделено в средстве выбора файлов. Коротко говоря, приложение-поставщик, на самом деле, лишь расширение пользовательского интерфейса средства выбора файлов, но очень мощное расширение. И в итоге, подобное приложение просто возвращает соответствующий объект StorageFile, который задает его связь с исходным приложением. Много всего происходит всего лишь при одном вызове API средства выбора файлов! (рис 2.9) Приложение для работы с камерой, запущенное с помощью средства выбора файлов. Откуда взялся этот поползень?

    У средства выбора файлов есть пара других режимов. Один из них позволяет выделять сразу несколько файлов – даже из разных приложений! – как показано на рис. 2.10, где все выделенные файлы помещены в корзину элементов (basket) в нижней части экрана. Средство выбора так же можно использовать для выбора папок, как показано на рис. 2.11. (в данном случае приложения-поставщики не показаны), или место для сохранения файла и его имя ( рис. 2.12.). (рис 2.10) Средство выбора файлов в режиме множественного выбора с корзиной выделенных элементов в нижней части. Здесь так же показан режим просмотра в виде "списка", что задается независимо от режима выбора файлов (рис 2.11) Средство выбора файла используется для выбора папок – обратит внимание на то, что текст на кнопке изменился, и на область предварительного просмотра содержимого папки справа (рис 2.12) Средство выбора файлов используется для выбора места сохранения файла и задания его имени

    API средства выбора файлов и его друзья

    Теперь, когда мы видели визуальную часть средства выбора файлов, посмотрим, как можно вызвать его из кода приложения с использованием API Windows.Storage.Pickers (http://msdn.microsoft.com/library/windows/apps/br207928.aspx). Все изображения, которые мы только что видели, взяты из примера "Средство выбора файлов" (http://code.msdn.microsoft.com/windowsapps/File-picker-sample-9f294cba), и мы так же используем его как источник кода.

    Для начинающих, Сценарий 1 в функции pickSinglePhoto (js/scenario1.js) использует средство выбора для получения одного объекта StorageFile для открытия (чтения и записи):

    function pickSinglePhoto() {	
    // Удостоверяемся, что приложение не в прикрепленном режиме, или что мы можем перейти в иной режим для запуска
    // средства выбора файлов
    var currentState = Windows.UI.ViewManagement.ApplicationView.value;	
    if (currentState === Windows.UI.ViewManagement.ApplicationViewState.snapped 	
    !Windows.UI.ViewManagement.ApplicationView.tryUnsnap()) {	
    // Не выводим дополнительных сообщений,
     если приложение не вышло из прикрепленного режима	
    return;	
    }	
    
    // Создаем объект средства выбора файлов и настраиваем параметры	
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();	
    openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
    openPicker.suggestedStartLocation =	
    Windows.Storage.Pickers.PickerLocationId.picturesLibrary;	
    
    // Пользователи ожидают увидеть папки, к содержимому которых 
    применен фильтр, который зависит от сценария.	
    // Например, при выборе папки документов, ограничьте типы файлов документами вашего приложения
    openPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);	
    
    
    // Открываем средство выбора файлов, чтобы позволить пользователю выбрать файл
     openPicker.pickSingleFileAsync().done(function (file) {
    if (file) {
    // Теперь у приложения есть доступ к выбранному файлу для чтения и записи
    } else {
    // Средство выбора файлов было закрыто без выбора файла
    }
    });
    }
    
     

    Как вы можете видеть, вызывать средство выбора в прикрепленном режиме не следует. Это, как и попытка вызова панели параметров, приведет к исключению. Вы можете проверить это, как показано здесь, или добавить обработчик ошибки в метод Я должен отметить, что пример использует вместо done метод then в последнем асинхронном вызове. Хотя и then работает, там следует использовать done, особенно если вы собираетесь обрабатывать там исключения.. В любом случае, для вызова средства выбора файлов мы создаем экземпляр ), настраиваем его и затем вызываем его метод pickSingleFileAsync. Результат работы pickSingleFileAsync – это аргумент file, передаваемый в обработчик завершения, который может быть либо объектом типа StorageFile, либо содержать null, если пользователь не сделал выбор и закрыл интерфейс средства выбора файла. Именно поэтому всегда нужно проверять результат выбора файлов на null.

    Настраивая средство выбора файлов, мы задали его viewMode как thumbnail (из перечисления Windows.Storage.Pickers.PickerViewMode), что привело к тому виду, который показан на рис. 2.7. Другая возможность – это list, что показано на рис. 2.10.

    Кроме того, мы установили suggestedStartLocation в значение picturesLibrary, что является значением, взятым из перечисления Windows.Storage.Pickers.PickerLocationId. Другие возможности - documentsLibrary, computerFolder, desktop, downloads, homeGroup, musicLibrary, и videosLibrary, практически все остальные расположения вы можете видеть на рис. 2.8. Обратите внимание на то, что использование этих расположений не требует от вас объявления возможностей в манифесте, так как пользователь, используя средство выбора файлов, дает разрешение на доступ к этим файлам. Если вы посмотрите манифест этого примера, вы увидите, что он не объявляет никаких возможостей.

    Другой свойство, которое мы задаем, это )), который отражает типы файлов, которые нас интересуют (PNG и JPEG). Помимо этого, FileOpenPicker так же имеет свойство commitButtonText, которое задает подпись для основной кнопки в пользовательском интерфейсе (та из них, которая не является кнопкой Отмена (Cancel), и settingsIndentifier, средство для запоминания различных контекстов для средства выбора файлов. Например, приложение может использовать один идентификатор для выбора изображений, где начальное расположение установлено на библиотеку изображений и режим просмотра – на просмотр в виде миниатюр, и другой идентификатор для выбора документов с другим начальным расположением, и, возможно, с режимом просмотра в виде списка.

    Этот пример, как вы можете видеть, помимо получения файлов, ничего не делает с ними, но очень легко увидеть, что мы можем сделать с ними. Мы можем, например, просто передать ), о котором я говорил ранее. Этот пример так же показывает чтение содержимого файла посредством ), или использовать методы StorageFile для создания копии файла в другом расположении, переименования файла, и так далее. Но, с точки зрения средства выбора файлов, его работа здесь сделана!

    Возвращаясь к примеру о средстве выбора файлов, выбор нескольких файлов, во многом – это то же самое, как показано в функции pickMultipleFiles в js/scenario2.js. Здесь мы используем режим просмотра list и начинаем просмотр с documentLibrary. Опять же, это начальное расположение не требует объявления возможностей в манифесте.

    function pickMultipleFiles() {
    // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена)
    
    // Создаем объект средства выбора файлов и настраиваем параметры	
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();	
    openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.list;
    openPicker.suggestedStartLocation =	
    Windows.Storage.Pickers.PickerLocationId.documentsLibrary;	
    openPicker.fileTypeFilter.replaceAll(["*"]);	
    
    // Открываем средство выбора файлов, чтобы позволить пользователю выбрать файл
    openPicker.pickMultipleFilesAsync().done(function (files) {
    if (files.size > 0) {
    // Теперь у приложения есть доступ к выбранному файлу (файлам) для чтения и записи
    } else {
    // Средство выбора файлов было закрыто без выбора файла
    }
    });
    }
     

    При выборе нескольких файлов, результат ), доступ к которому осуществляется как к любому другому массиву, с использованием [ ] (хотя у него меньше методов, чем у обычного массива).

    Сценарий 3 примера демонстрирует вызов pickSingleFolderAsync, результат этой операции – объект StorageFolder. Здесь вы должны задать fileTypeFilter, что поможет пользователям выбрать подходящее расположение, в котором существуют файлы нужного типа, или то, где они смогут создать новые подобные файлы (js/scenario3.js):

     function pickFolder() {
    // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена)
    
    
    // Создаем объект средства выбора файлов и настраиваем параметры	
    var folderPicker = new Windows.Storage.Pickers.FolderPicker;	
    folderPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.desktop;
    folderPicker.fileTypeFilter.replaceAll([".docx", ".xlsx", ".pptx"]);	
    
    folderPicker.pickSingleFolderAsync().then(function (folder) {
    if (folder) {
    // Кэшируем папку, таким образом позже мы сможем получить доступ к ее содержимому
    Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList
    .addOrReplace("PickedFolderToken", folder);
    } else {
    // Средство выбора файлов было закрыто без выбора объекта
    }
    });
    }
    

    В этом примере мы так же видим, как сохранить выбранный объект StorageFolder в ) для последующего использования. Опять же, выбирая эту папку, пользователь дает приложению программный доступ к ее содержимого, но только на время текущего сеанса работы. Для того, чтобы сохранить полученные права, приложение должно записать элемент хранения в ) для того, чтобы больше узнать об этой возможности, и обратите внимание на то, что API AccessCache так же можно применять для недавно использованных элементов. Ключевая вещь, которую нужно здесь запомнить, заключается в том, что для любого расположения за пределами пакета приложения, данных приложения, или библиотек, доступ к которым вы объявили в манифесте, вы должны использовать AccessCashe для того, чтобы подобный доступ был у вас в будущем. Обычное сохранение пути к расположению и попытка открыть файлы из него позже не дадут результата.

    Последний пример использования средства выбора файлов, в Сценарии 4 примера, создается объект ) и вызывается метод pickSaveAsync, что приводит к появлению интерфейса, показанного на рис. 2.12:

    function saveFile() {
    // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена)
    
    // Создаем объект средства выбора файлов и настраиваем параметры	
    var savePicker = new Windows.Storage.Pickers.FileSavePicker();
    savePicker.suggestedStartLocation =	
    Windows.Storage.Pickers.PickerLocationId.documentsLibrary;
    // Выпадающий список типов файлов, применимый при сохранении	
    savePicker.fileTypeChoices.insert("Plain Text", [".txt"]);	
    savePicker.pickSaveFileAsync().done(function (file) {	
    if (file) {	
    // Предотвращает обновление удаленной версии файла до тех пор, пока мы не завершим
    // изменения и не вызовем CompleteUpdatesAsync.	
    Windows.Storage.CachedFileManager.deferUpdates(file);	
    
    
    // записываем в файл
    Windows.Storage.FileIO.writeTextAsync(file, file.name).done(function () {
    // Дадим Windows знать, что мы завершили изменение файла и другие приложения
    // могут обновлять удаленную версию файла.
    // Завершение обновлений может потребовать у Windows запросить у пользователя ввод данных. 
    Windows.Storage.CachedFileManager.completeUpdatesAsync(file)
    .done(function (updateStatus) {
    if (updateStatus === Windows.Storage.Provider.FileUpdateStatus.complete) {
    } else {
    // ...
    }
    }
    });
    });
    } else {
    // Интерфейс был закрыт
    }
    });
    }
     

    У объекта ). Этот объект помогает поставщику средства выбора файлов узнать, следует ли ему синхронизировать локальные файлы и файлы, хранящиеся на удаленном сервисе, что необходимо, когда пользователь файла сохраняет новое содержимое, как мы видим здесь. Со стороны потребителя, то, что мы здесь видим – это обычный шаблон для работы с файлами, полученными от средства выбора файлов (или из кэша доступа, если эти данные были сохранены в предыдущих сеансах работы): нам просто нужно дать знать объекту CashedFileManager, что мы осуществляем запись в файл, и сообщить ему, когда сделаем это. Конечно, этого делать не нужно, когда вы работаете с файлами, о которых вы знаете, что они локальные, как с теми, которые находятся в папках, расположенных в AppData. Больше об этом механизме мы узнаем в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", посмотрим на него со стороны поставщика.

    Медиабиблиотеки

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

    Вам нужен доступ к определенной библиотеке, если вы собираетесь работать с ней вне средства выбора файлов. Например, если вы хотите перебрать содержимое папок Изображения или Музыка для того, чтобы отобразить список файлов в элементе управления ListView или FlipView, как мы делали в лекции курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", вам нужно объявлять возможности.

    Чтобы быть более конкретным, без использования средства выбора файлов, это – единственный способ получить программный доступ к медиабиблиотекам: получения объекта ). В случае с медиаданными, применимые возможности здесь – picturesLibrary, musicLibrary и videoLibrary. Без объявления соответствующих возможностей, попытка получить одно из этих значения приведет к исключению отказа в доступе.

    Если вы не собираетесь пользоваться KnownFolders, это означает, что вам не нужно объявлять возможности! Помните, что объявленные возможности перечислены на странице приложения в Магазине Windows и могут вызвать у пользователя размышления о том, стоит ли устанавливать ваше приложение, поэтому, чем меньше возможностей будет объявлено – тем лучше.

    Тем не менее, если вы решите, что вам нужен прямой доступ к медиа-библиотекам, работа с ними включает в себя объекты StorageFolder и StorageFile так же, как при работе с любым другим расположением. Единственная разница, однако, это то, что вы можете работать с метаданными, которые часто существуют вместе с медиафайлами, подробнее об этом мы поговорим в лекции 4.

    Документы и съемные носители

    Как и в случае с доступом к папкам с медиаданными, программный доступ к папке с документами пользователя, так же, как и к съемным носителям, контролируется через объявление возможностей. Важно понимать и то, что обе эти возможности так же требуют, чтобы вы объявили сопоставление типов файлов, что означает, что вы не можете просто просмотреть содержимое папки напрямую, или записать в нее любой файл, какой захотите. Иными словами, получать непосредственный доступ к этим папкам с помощью Windows.Storage.KnownFolders.documentsLibrary и removableDevices, где и то и другое является объектом StorageFolder – просто для работы с ограниченным набором типов файлов, полезно лишь при реализации некоторых сценариев. Для библиотеки документов, на самом деле, документация говорит о том, что "единственное приемлемое использование [возможности] – это поддержка открытия содержимого, внедренного в другие документы". Магазин Windows так же требует оправданного использования объявления возможностей и так же требует, чтобы у вас была корпоративная учетная запись в Магазине Windows, а не только учетная запись индивидуального разработчика.

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

    Например, в примере "Съемные носители информации" (http://code.msdn.microsoft.com/windowsapps/Removable-Storage-52cc49f0), для демонстрации доступа к съемным носителям информации, объявляются сопоставления с .gif, .jpg и .png-файлами. В результате, приложение отображается в списке Открыть с помощью… (Open With) в контекстном меню, в Проводнике Windows на Рабочем столе, и в средстве выбора программ по умолчанию:

    То же самое справедливо и для документов (снова посмотрите пример Доступ к файлам" ( http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597)), таким образом, если ваше приложение не позиционируется как приложение для работы с подобными файлами, вам, возможно, не нужны эти возможности.

    На самом деле, объявление сопоставления типов файлов, это разновидность контрактов, мы рассмотрим это подробно в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой".

    Расширенные возможности запросов к файлам

    Для того чтобы перечислить файлы в определенном расположении (помимо возможностей), вы используете то, что называется файловым запросом (file query), или просто, поиском. Файловый запрос – это то, что Проводник Windows на рабочем столе использует для поиска по файловой систем, и может включать в себя поиск по содержимому файла, так же, как любое количество других свойств и метаданных. Эти запросы используют то, что называется строками Advanced Query Syntax (AQS) (http://msdn.microsoft.com/library/windows/desktop/bb266512.aspx) и могут идентифицировать и описать столько специфических критериев, сколько вам нужно. Вся эта тема несколько не вписывается в рамки курса, но мы можем, по крайней мере, взглянуть на то, как WinRT предоставляет богатые возможности файловых запросов приложениям посредством ). Достаточно будет заглянуть в глубокую кроличью нору!

    На самом деле, существуют буквально тысячи параметров, которые можно использовать в AQS-строках, так как они могут быть построены из любого количества свойств Windows (http://msdn.microsoft.com/library/windows/desktop/dd561977.aspx), таких, как System.ItemDate, System.Author, System.Keywords, System.Photo.LightSource и так далее Вопреки любым примерам в документации, в запросах всегда следует использовать полные имена свойств Windows, как, например System.ItemDate:, вместо удобного для программистов сокращения date:, так как последний вариант не будет работать в локализованных версиях Windows. . Каждое из свойств может содержать целевое значение, такое, как System.Author(Patrick or Bob) и System.ItemType: "mp3", и условия могут объединяться с помощью операторов AND, OR и NOT. Больше примеров мы увидим в лекции 4, где мы будем использовать запросы для получения коллекций файлов во множестве различных "форм", например, в виде одномерного списка, в иерархическом виде, в различных вариантах сортировки, включая те, которые основаны на медиа-свойствах. В дополнение, файловые запросы так же позволяют получать эскизы и автоматически получать альбомную графику для музыкальных произведений.

    Сконцентрируемся теперь на основных принципах работы файловых запросов, начнем с основ, которые показаны в упражнении FileQuery, которое включено в материалы к этой лекции. Это упражнение – копия примера "Программный поиск файлов" (http://code.msdn.microsoft.com/windowsapps/Programmatically-searching-25e1a56b) из Windows SDK, там присутствует лишь один сценарий, ориентированный на музыкальную библиотеку, который позволяет вам непосредственно вводить AQS-строку. Однако, это не то, что вы всегда будете использовать в приложениях, поэтому я хочу показать вам и другие варианты.

    Запросы всегда начинаются со ), методы которого createFileQuery[WithOptions], createFolderQuery[WithOptions] , и createItemQuery[WithOptions] (всего 6) используются для перечисления файлов, папок, или и того и другого в заданной папке StorageFolder . Простейшие запросы создают на основе методов StorageFolder.create* без параметров:

    folder.createFileQuery(); 
    folder.createFolderQuery(); 
    folder.createItemQuery(); 

    Здесь первые два метода – это лишь сокращения для варианта с одним параметром с одним и тем же именем, где параметр – это значение из перечисления ) или ). Эти короткие имена просто используют значение defaultQuery для обычного перечисления всего содержимого папки в алфавитном порядке. В свою очередь, createItemQuery имеет лишь эту единственную форму.

    Само по себе создание запроса ничего не перечисляет до тех пор, пока вы не запросите перечисление посредством асинхронного метода: для файловых запросов это метод getFilesAsync, для папок – getFoldersAsync, а для элементов хранения – getItemsAsync (Видите здесь повторяющуюся последовательность?). Таким образом, в Сценарии 2 упражнения FileQuery, у меня есть все три функции, подключенные к кнопкам:

    function fileQuery() {	
    var query = picturesLibrary.createFileQuery();
    SdkSample.showResults(query.getFilesAsync());	
    }	
    
    function folderQuery() {	
    var query = picturesLibrary.createFolderQuery();
    SdkSample.showResults(query.getFoldersAsync());	
     }
    
    function itemQuery() {
    var query = picturesLibrary.createItemQuery();
    SdkSample.showResults(query.getItemsAsync());
    }	
     

    Здесь функция SdkSample.showResults в js/default.js просто создает список элементов в коллекции. Запустив этот пример, вы увидите список файлов или папок в вашей библиотеке изображений.

    Совет. Реальный тип объектов, возвращаемый API create*Query, это StorageFileQueryResult, StorageFolderQueryResult, и StorageItemQueryResult, все они находятся в пространстве имен Windows.Storage.Search. Все они предоставляют некоторые дополнительные свойства, наподобие folder, методы наподобие findStartIndexAsync и getItemCountAsync, и события вроде optionschanged and contentschanged (оба - события WinRT). Последнее событие – это то, что вы можете использовать для отслеживания изменений в файловой системе, которые воздействуют на результаты запроса.

    Помимо получения неглубокого (shallow) представления, запросы к файлам и папкам имеют множество других возможностей, которые отражены в перечислениях CommonFileQuery и CommonFolderQuery:

  • В CommonFileQuery это: orderByName (порядок по имени), orderByTitle (порядок по заголовку), orderByDate (порядок по дате), orderByMusicProperties (порядок по свойствам аудиозаписи), и orderBySearchRank (порядок по рейтингу поиска).
  • В CommonFolderQuery это : groupByType (группировка по типу), groupByTag (группировка по тегу), groupByAuthor (группировка по автору), groupByYear (группировка по году), groupByMonth (группировка по месяцу), groupByArtist, groupByComposer (группировка по композитору), groupByGenre (группировка по жанру), groupByPublishedYear (группировка по жанру публикации), и groupByRating (группировка по рейтингу).
  • Очевидно, что эффект указания этих вариантов зависит от того, имеются ли у запрошенных элементов метаданные, которые поддерживают соответствующую группировку или упорядочение, но можно выполнить запрос ко всем папкам для всех типов файлов и папок. Для демонстрации этого Сценарий 3 упражнения FileQuery позволяет вам выбирать библиотеку музыки, изображений или видео. Затем вы можете выбрать, нужно ли строить запрос по файлам или папкам, указывать общепринятые параметры и запускать поиск для того, чтобы получить результат. Обратите внимание на то, что использование orderBySearchRank с файлами не имеет смысла в этом контексте, так как это предназначено для поисковых запросов, основанных на AQS. Мы увидим еще кое-что об этом позже (Кроме того – можете назвать меня бездельником! – результыты сгруппированного запроса к папке не особенно интересны, когда не выводятся в некие экранные элементы, но пример реализации подобного механизма вы можете увидеть в Сценарии 2 примера "Перечисление папок" (http://code.msdn.microsoft.com/windowsapps/Folder-enumeration-sample-33ebd000)). Код в js/scenario3.js, в основном, реализует механизм отображения выделенных элементов пользовательского интерфейса в createFileQuery или createFolderQuery с верными параметрами, таким образом вам не нужно просматривать большую их часть. Один важный участок кода – это использование методов isCommonFileQuerySupported и isCommonFolderQuerySupported объекта StorageFolder. Они используются для проверки того, поддерживает ли текущая папка тот запрос, который вы пытаетесь выполнить:

    if (folder.isCommonFileQuerySupported(selectedQuery)) {
    query = folder.createFileQuery(selectedQuery);	
    if (query) {	
    promise = query.getFilesAsync();	
    }	
    }	
     

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

    Похожий метод, ) (стандартные запросы – это лишь предварительно заполненные экземпляры этого объекта) и создаются путем передачи этого объекта в createFileQueryWithOptions, createFolderQueryWithOptions, и createItemQueryWithOptions.

    Объект QueryOptions обычно создается с нуля, с использованием оператора new, после чего вы заполняете его свойства. Так же вы можете использовать new QueryOptions(<CommonFolderQuery>) для получения объекта для одного из обычных запросов к папкам, и new QueryOptions(<CommonFileQuery> [, <file type filter>]) для того, чтобы сделать то же самое для файловых запросов. В последнем случае можно передать необязательный массив типов файлов. Это – короткое имя для часто настраиваемого стандартного запроса с особым набором типов файлов. Без него, фильтр установлен в"*" по умолчанию. Таким образом, если вам просто нужно найти .mp3-файлы в вашей музыкальной библиотеке, упорядоченные по заголовку (title), вы можете использовать что-то вроде нижеприведенного кода (смотрите js/scenario4.js в упражнении FileQuery):

    var musicLibrary = Windows.Storage.KnownFolders.musicLibrary;
    var options = new Windows.Storage.Search.QueryOptions( Windows.Storage.Search.CommonFileQuery.orderByTitle, [".mp3"]);
    
    if (musicLibrary.areQueryOptionsSupported(options)) {	
    var query = musicLibrary.createFileQueryWithOptions(options);
    SdkSample.showResults(query.getFilesAsync());	
    }	
     

    Если вы создаете Другое свойство, <code> dateStackOption</code> (значение из <code>Windows.Storage.Search.DateStackOption</code>), в данной структуре представлено в виде только для чтения, но оно может быть установлено при создании <code>QueryOptions</code>; из CommonFolderQuery. :

  • fileTypeFilter вектор из строк, который описывает желаемые расширения типов файлов, такие, как ".mp3". Значение по умолчанию – пустой список (фильтрация не применяется).
  • folderDepth принимает либо значение Windows.Storage.Search.FolderDepth.shallow (по умолчанию, неглубокое представление содержимого ), либо deep (глубокое рекурсивное представление всех вложенных папок и файлов.
  • indexerOption значение из Windows.Storage.Search.IndexerOption, оно может быть одним из следующих: useIndexerWhenAvailable, onlyUseIndexer (ограничивает поиск индексированным содержимым), и doNotUseIndexer (запрос направлен напрямую на файловую систему, без использования индекса). Последний вариант по умолчанию, обычно данное свойство явно устанавливают в значение useIndexerWhenAvailable.
  • sortOrder вектор из структур Windows.Storage.Search.SortEntry, каждая из которых содержит булево значение с именем ascendingOrder (значение false для убывающего порядка) и строку propertyName. Каждая запись в векторе определяет критерий сортировки. Эти критерии применяются в том порядке, в котором они расположены в векторе. Пример этого будет дан немного позже.
  • Три свойства QueryOptions затем примняются к поиску с AQS-строками:

  • applicationSearchFilter – AQS-строка.
  • userSearchFilter – другая AQS-строка.
  • language строка, содержащая идентификатор языка BCP-47, связанный с AQS-строками.
  • Когда запрос построен с помощью метода, наподобие createFileQueryWithOptions, строки пользовательского фильтра и фильтра приложения комбинируются. Это означает, что вы можете раздельно управлять любым фильтром, который вы хотите применять везде в вашем приложении (applicationSearchFilter) с помощью условий поиска, заданных пользователем (userSearchFilter). Таким образом, вы можете применить некоторые поисковые фильтры без необходимости ввода их пользователем, и без того, чтобы всегда выполнять объединение их со строками, заданными вами.

    Как упоминалось выше, запрос CommonFileQuery.orderBySearchRank имеет смысл лишь тогда, когда он скомбинирован с AQS-строкой, что говорит о том, что поиск, основанный на ключевых словах, возвращает ранжированный результат, к которому может быть применен обычный файловый запрос. Возвращаясь к Сценарию 1 примера о программном поиске файлов, мы можем увидеть, как здесь используется такое упорядочение вместе со свойством userSearchFilter:

    var musicLibrary = Windows.Storage.KnownFolders.musicLibrary;	
    var options = new Windows.Storage.Search.QueryOptions(	
    Windows.Storage.Search.CommonFileQuery.orderBySearchRank, ["*"]);
    options.userSearchFilter = searchFilter;	
    var fileQuery = musicLibrary.createFileQueryWithOptions(options);	
     

    На моем компьютере, где у меня есть несколько музыкальных композиций со словом "Nightingale" в заголовке, где есть и альбом, названный "Nightingale Lullaby", поиск с использованием строки "Nightingale" System.ItemType: "mp3" в вышеприведенном коде, дает мне следующий результат:

    Здесь можно видеть, что при поисковом ранжировании отобраны предпочитаемые композиции с "Nightingale" в заголовке, но так же в поиск включены композиции из альбома, который имеет это слово в имени.

    Моя поисковая строка, кстати, показывает, как вы можете использовать свойства applicationSearchFilter и userSearchFilter вместе. Если мое приложение может работать только с mp3 или с некоторыми другими форматами, я могу сохранить "System.Item.Type: 'mp3'" в applicationSearchFilter, а условия, которые задает пользователь, в userSearchFilter. Тем самым я избегаю самостоятельного объединения этих условий в коде.

    Помимо свойств, которые устанавливают в объекте QueryOptions существуют некоторые данные и возможности этого объекта. Так, groupPropertyName, это строковое свойство, которое показывает тип свойства, по которому будет сгруппирован запрос. Так же вы можете получить параметры запроса в виде строки, используя метод saveToString и создать объект на основе строки, используя loadFromString (это – аналог JSON.stringify и JSON.parse).

    Метод Посмотрите материал "Изменения, представляющие интерес для разработчиков приложений, внесенные после выхода Consumer Preview" (http://blogs.msdn.com/b/windowsappdev_ru/archive/2012/06/07/consumer-preview.aspx) в блоге для разработчиков приложений для Windows 8 для того, чтобы узнать некоторые подробности об этом. .

    В лекции 5 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", мы уже видели пример похожего использования свойств, связанных с эскизами, когда пользовались коротким именем библиотеки изображений с WinJS.UI.StorageDataSource и могли задавать параметр, указывающий размер эскиза:

    myFlipView.itemDataSource = new WinJS.UI.StorageDataSource("Pictures",
    { requestedThumbnailSize: 480 });
     

    Более общий пример, который так же включает вектор QueryOptions.sortOrder, можно найти в примере "Использование StorageDataSource и GetVirtualizedFilesVector" (http://code.msdn.microsoft.com/windowsapps/Data-source-adapter-sample-3d32e535), который упомянут в лекции 5 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". В примере, в js/scenario2.js, мы можем видеть создание QueryOptions с нуля, установку двух критериев sortOrder, и задание параметров эскизов в источнике данных:

    function loadListViewControl() {
    // Создаем источник данных из библиотеки изображений
    var library = Windows.Storage.KnownFolders.picturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions;
    // Неглубокий запрос для получения иерархии файлов
    queryOptions.folderDepth = Windows.Storage.Search.FolderDepth.shallow;
    queryOptions.sortOrder.clear();
    // Упорядочиваем элементы по типу, таким образом, первыми идут папки 
    queryOptions.sortOrder.append({ascendingOrder: false, propertyName: "System.IsFolder"}); 
    queryOptions.sortOrder.append({ascendingOrder: true, propertyName: "System.ItemName"}); 
    queryOptions.indexerOption =
    Windows.Storage.Search.IndexerOption.useIndexerWhenAvailable;
    
    var fileQuery = library.createItemQueryWithOptions(queryOptions);	
    var dataSourceOptions = {	
    mode: Windows.Storage.FileProperties.ThumbnailMode.picturesView,	
    requestedThumbnailSize: 190,	
    thumbnailOptions: Windows.Storage.FileProperties.ThumbnailOptions.none
    };	
    
    var dataSource = new WinJS.UI.StorageDataSource(fileQuery, dataSourceOptions);
    
    // Создаем ListView...
    };
     

    Если вам хочется разобраться с этим глубже, вы можете посмотреть, как заданы файловые запросы в StorageDataFolder. Просто найдите этот класс в файле ui.js в WinJS. По пути вы столкнетесь с другим набором API WinRT – возможно, это – дно кроличьей норы. Я хочу упомянуть о них, прежде чем рассматривать эту тему: Windows.Storage.BulkAccess. Они действительно существуют исключительно для использования в StorageDataSource и не предназначены для прямого использования в приложениях. Даже если вы создадите собственный источник данных или элемент управления коллекцией, лучше всего – использовать средства перечисления и API для упреждающей выборки данных, о которых мы уже говорили, так как они дают такой же уровень производительности.

    Обновление "Here My Am!"

    Для того, чтобы собрать воедино некоторые темы, изученные в этой лекции, дополнительные материалы включают в себя новую версию приложения "Here My Am!", в которую внесены следующие изменения и дополнения (в основном, в страницу pages/home/home.js, если не указано иное):

  • Теперь программа включает в себя Bing Maps SDK (http://msdn.microsoft.com/library/hh846481.aspx), таким образом, соответствующий элемент управления является частью пакета приложения, а не загружается с удаленного ресурса. Это устраняет необходимость в iframe, который мы использовали для поддержки карты, теперь весь код из html/map.html можно переместить в js/default.js. Обратите внимание на то, что для того, чтобы запустить этот пример в Visual Studio, вам нужно самостоятельно загрузить и установить этот SDK.
  • Вместо копирования изображения, полученного с камеры, в область данных приложения, теперь оно копируется в папку HereMyAm в библиотеке изображений. Объявлена возможность Библиотека изображений (Pictures Library).
  • Вместо сохранения пути к последнему полученному изображению, который используется, когда приложение было остановлено и перезапущено, StorageFile сохраняется в Windows.Storage.AccessCache для того, чтобы гарантировать возможность программного доступа к изображению в будущем.
  • На панель приложения добавлена команда, которая позволяет вам использовать средство выбора файлов для выбора изображения, вместо того, чтобы полностью полагаться на возможности камеры. Это так же позволяет вам использовать приложение для работы с камерой, если хотите. Обратите внимание, что в этом случае мы используем собственный settingsIdentifier со средством выбора файлов, что отличает его от обычного средства выбора файлов для существующих изображений.
  • Другая команда панели приложения позволяет вам выбирать из последних снимков, полученных с камеры. По умолчанию команда направлена на нашу папку в библиотеке изображений, она использует другой settingdIdentifier.
  • Дополнительные команды – О программе (About), Помощь (Help) и Заявление о конфиденциальности (Privacy Stating) включены в панель параметров с использованием события WinJS.Application.onsettings (смотрите js/default.js). Первые две отображают содержимое из приложения, в то время, как третья команда загружает веб-содержимое в iframe. Все страницы параметров можно найти в папке проекта html.
  • Что мы только что изучили

  • Преемственность или сохранение состояния важны в приложениях для Магазина Windows для поддержания состояния непрерывности работы приложения между сеансами работы, даже если приложение приостановлено или остановлено.
  • Данные приложения – это данные состояния сеанса, локальные, временные и перемещаемые состояния, которые привязаны к существованию приложения. Доступ к ним может получить только приложение.
  • Пользовательские данных хранятся в местах, отличных от мест хранения данных приложения (таких, как библиотеки музыки, изображений, видео, документов, вместе со съемными носителями информации) и существуют независимо от любого отдельно взятого приложения. Открывать пользовательские файлы и манипулировать ими могут различные приложения.
  • Доступ к данным приложения можно получить посредством API Windows.Storage.ApplicationData, что включает в себя и доступ к структурированным контейнерам параметров, и к данных, основанных на файлах. Так же доступны дополнительные API, наподобие IndexedDB и HTML5 localStorage.
  • Важно задавать версии состоянию приложения, особенно если используется перемещаемое состояние, от управления версиями зависит то, как служба перемещения данных будет направлять данные на устройства, на которых установлены определенные версии приложений.
  • Размер перемещаемого состояния ограничен квотой (она предоставляется API), при превышении которой Windows не будет перемещать данные. Для перемещения больших объемов данных, в том числе – пользовательских, можно использовать сервисы наподобие SkyDrive.
  • Обычный период перемещения данных – 30 минут или менее. Отдельный или составной параметр, имеющий имя "HighPriority", до тех пор, пока его размер не будет превышать 8 Кб, может перемещаться в течение минуты.
  • Классы WinRT StorageFolder и StorageFile – это основные объекты для работы с папками и файлами. Все виды программного доступа к файловой системе, начинаются, на самом деле, со StorageFolder. В противном случае, пользователь может указать на файл или папку с использованием API средства выбора файлов, который, на самом деле, является первым вариантом выбора для доступа к файлов.
  • Большие двоичные объекты (blob) – это удобные средства для работы с файлами, как и WinRT API в WindowsStorage.FileIO и PathIO. WinJS предлагает некоторые упрощенные методы для чтения и записи текстовых файлов (особенно они полезны при работе с состоянием приложения), так же поддерживается FileReader из HTML5.
  • WinRT предлагает средства шифрования с помощью Windows.Security.Cruptography, а так же встроенный механизм сжатия данных в Windows.Storage.Compression.
  • Для использования панели параметров, приложение заполняет панель верхнего уровня, которая предоставлена Windows, собственными командами. Эти команды связаны с обработчиками, которые либо открывают гиперссылки (в браузере), либо отображают всплывающие элементы настроек с использованием элемента управления WinJS.UI.SettingsFlyout. Эти всплывающие элементы могут включать в себя любой необходимый HTML-код, в том числе – элементы iframe для загрузки удаленного содержимого.
  • Доступ к папкам пользовательских данных, таким, как медиа-библиотеки, библиотека документов, съемные носители, контролируется возможностями, объявленными в манифесте. Подобные возможности нужно объявлять лишь тогда, если приложению нужен доступ к файловой системе таким способом, для которого не подходит применение средства выбора файлов.
  • Средство выбора файлов – это инструмент, с помощью которого пользователи могут выбирать файлы из любого безопасного расположения в файловой системе, а так же – файлы, предоставляемые другими приложениями (это могут быть удаленные файлы, файлы, хранящиеся в базах данных, даже те, которые не существуют в виде файловых записей в локальной файловой системе). Одна из наиболее удобных и мощных функций приложений для Магазина Windows – это возможность выбора файлов непосредственно из других приложений, в том числе – файлов, которые приложения могут генерировать по запросу.
  • Объекты типа StorageFolder обеспечивают обширные возможности по поиску в их содержимом и по доступу к нему с помощью файловых запросов. Запросы могут быть простыми и сложными и могут задействовать строки поиска Advanced Query Syntax (AQS).
  • Вернуться к учебному плану