Metro-приложения - новый класс Windows-приложений, что работают под управлением платформы Metro, входящей в состав Windows 8, - предназначены, в первую очередь, для мобильных устройств с большим сенсорным экраном, например, планшетов. К подобным устройствам предъявляются весьма специфические требования; так, они, в первую очередь, должны быть постоянно подключены к сети, работать от одной зарядки аккумулятора как можно дольше и отнимать как можно меньше системных ресурсов.
Что касается поддержки печати, то она не входит в первоочередной набор "умений" таких устройств. Тем не менее, иногда возникает необходимость распечатать полученный по электронной почте документ или найденную в Интернете картинку. Возможно ли это?
С появлением платформы Metro - не только возможно, но и чрезвычайно просто. И данная статья будет посвящена как раз этому.
Внимание! Перед чтением следует ознакомиться с предыдущими статьями из цикла "Начала Metro-программирования", опубликованными на сайте TheVista.ru ранее. Описанные в них приёмы программирования будут активно здесь использоваться.
1. Введение
Платформа Metro предоставляет встроенные средства для выполнения печати. В них входят стандартная панель Печать, аналогичная по назначению соответствующему диалоговому окну традиционных Windows-приложений, специализированный интерфейс программирования, программный диспетчер печати и драйверы печатающих устройств.
Нас интересуют только панель Печать и интерфейсы программирования, обеспечивающие поддержку печати. Именно с ними мы будем иметь дело.
В статье, посвящённой реализации поиска, говорилось о волшебных кнопках, появляющихся при наведении курсора мыши на правый нижний угол экрана или вытягиваемых пальцем из-за его правой границы. Среди них есть кнопка Устройства (Devices), выводящая на экран одноимённую панель (см. рис. 1). Эта панель содержит список всех подключенных к компьютеру периферийных устройств, в том числе и принтеров. Если нужное нам устройство отсутствует в этом списке, мы нажмём гиперссылку Дополнительно (More).
Рис. 1. Панель Устройства
Чтобы выполнить печать на каком-либо принтере, мы нажмём на представляющем его пункте данного списка. После чего на экране появится панель Печать (Print), показанная на рис. 2.
Рис. 2. Панель Печать (выполняется печать из Metro-версии Internet Explorer)
Эта панель обычно содержит:
область предварительного просмотра, где представляется печатаемый документ;
элементы управления, предназначенные для вывода остальных страниц многостраничного документа;
элементы управления для задания параметров печати (обычно размера и ориентации бумаги);
кнопку Печать, запускающую процесс печати.
Всё это нам знакомо по обычным Windows-приложениям.
2. Поддержка печати в Metro-приложениях
Теперь давайте выясним, что именно и каким образом мы можем печатать из Metro-приложений, разработанных с применением технологий HTML, CSS и JavaScript.
Мы можем печатать только то, что в данный момент выводится на экран, то есть сам интерфейс приложения. Распечатать что-либо иное, к сожалению, не получится.
Однако существует возможность переформатировать интерфейс приложения для вывода на печать: изменить местоположение и размеры элементов интерфейса, задать для них иные параметры и даже скрыть отдельные элементы, которые не должны быть распечатаны. Для этого мы используем медиазапросы, о которых обязательно поговорим позднее в этой статье.
На заметку Metro-приложения, написанные с применением технологий XAML и DirectX, могут формировать произвольные документы для вывода на печать без всяких ухищрений. Разговор об этих платформах выходит за рамки данной статьи.
Мы можем запускать печать как из панели Печать, так и из интерфейса самого приложения.
Мы можем программно задавать параметры печати.
Мы можем указывать, какие элементы управления должны присутствовать на панели Печать.
Ещё мы можем задавать собственное представление для панели Печать, в том числе специфические элементы управления, предназанченные для указания каких-либо особых параметров печати. Однако это довольно сложный процесс, описание которого выходит за рамки этой статьи.
3. Реализация базовой поддержки печати
Реализовать в приложении поддержку печати очень просто. Сейчас мы в этом убедимся.
3.1. Получение диспетчера печати Metro
Сначала нам нужно получить экземпляр объекта Windows.Graphics.Printing.PrintManager. Этот объект представляет программный диспетчер печати платформы Metro.
Для получения экземпляра объекта Windows.Graphics.Printing.PrintManager нам следует вызвать метод getForCurrentView этого же объекта. Данный метод не принимает параметров и возвращает то, что нам нужно, - диспетчер печати.
var oPM = Windows.Graphics.Printing.PrintManager.getForCurrentView();
Обычно это выражение помещается в код инициализации - в обработчик события DOMContentLoader.
3.2. Собственно обеспечение поддержки печати
Следующий наш шаг - привязка к событию printtaskrequested, поддерживаемому объектом Windows.Graphics.Printing.PrintManager, обработчика. Наличие обработчика у этого события говорит о том, что приложение поддерживает печать.
Событие printtaskrequested возникает в диспетчере печати, когда пользователь выводит на экран панель Печать. В этом случае платформе Metro требуется отобразить в области предварительного просмотра данной панели (см. рис. 2) представление печатаемого документа, который приложение должно сформировать и предоставить.
Здесь мы объявили функцию-обработчик oPMPrintTaskRequested, которую потом и привязали к событию printtaskrequested диспетчера печати.
Данное выражение также можно поместить в код инициализации. Но часто приложение должно в одних случаях поддерживать печать, а в других - не поддерживать. Пример: приложение просмотровщика графики, которое должно поддерживать печать только если пользователь выберет в списке какой-либо файл. Поэтому в таких случаях лучше всего привязывать обработчик к событию только тогда, когда приложение будет готово инициировать печать. В остальных случаях поддержку печати следует блокировать.
Но как это сделать? Очень просто - "отвязав" обработчик от события printtaskrequested. Для этого мы вызовем метод removeEventListener, поддерживаемый всеми объектами, порождающими события.
<экземпляр объекта>.removeEventListener(
<имя события>,
<функция-обработчик, которую требуется "отвязать">
)
требуется "отвязать">
)[/code]
Как видим, он принимает те же параметры, что и давно знакомый нам метод addEventListener. А именно, имя события в виде строки и функцию-обработчик, которую требуется от него "отвязать".
[code]oPM.removeEventListener("printtaskrequested", oPMPrintTaskRequested);[/code]
"Отвязываем" от события printtaskrequested привязанную ранее функцию-обработчик oPMPrintTaskRequested.
3.3. Создание задания на печать
И, наконец, мы создадим так называемое задание на печать, включающее собственно документ, который должен быть напечатан.
Задание на печать формируется в обработчике события printtaskrequested. Мы уже знаем, что это событие возникает, когда на экране появляется панель Печать, и платформе Metro требуется вывести в её области предварительного просмотра представление печатаемого документа. Этот самый печатаемый документ как раз берётся из задания на печать.
Функция-обработчик данного события принимает в качестве единственного параметра экземпляр объекта Windows.Graphics.Printing.PrintTaskRequestedEventArgs, хранящий дополнительные сведения о событии. Объект этот поддерживает свойство request, чьим значением является экземпляр объекта Windows.Graphics.Printing.PrintTaskRequest, который представляет своего рода системный запрос на создание задания на печать...
...которое создаётся и заносится во внутренний список диспетчера печати вызовом метода createPrintTask этого запроса.
[code]<запрос на создание задания на печать>.createPrintTask(
<название>,
<функция, формирующая печатаемый документ>
)[/code]
Первым параметром этому методу передаётся название создаваемого задания на печать в виде строки. Это название будет выводиться в списке заданий на печать, отображаемых в окне состояния принтера.
Вторым параметром указывается функция, которая сформирует печатаемый документ, относящийся к этому заданию. Данная функция требует более подробного разбора.
Прежде всего, она принимает единственный параметр - экземпляр объекта Windows.Graphics.Printing.PrintTaskSourceRequestedArgs, который предоставляет несколько методов, позволяющих сформировать печатаемое содержимое.
Самый полезный в нашем случае метод - setSource. Он не возвращает результата, а в качестве единственного параметра принимает экземпляр объекта, представляющий печатаемый документ. Объект, на основе которого создаётся этот экземпляр, должен реализовывать интерфейс Windows.Graphics.Printing.IPrintDocumentSource.
Но как нам превратить интерфейс приложения в экземпляр такого объекта? С помощью вызова метода getHtmlPrintDocumentSource объекта MSApp. (Этот объект предоставляет ряд методов для работы с данными; единственный его экземпляр создаётся платформой Metro и доступен из одноимённой переменной.)
В качестве единственного параметра метод getHtmlPrintDocumentSource принимает экземпляр объекта HTMLDocument, представляющий весь интерфейс приложения. Данный объект создаётся самой платформой Metro и доступен в любом месте кода логики через переменную document.
А возвращает метод getHtmlPrintDocumentSource экземпляр объекта, представляющего интерфейс приложения и реализующего интерфейс Windows.Graphics.Printing.IPrintDocumentSource.
Осталось только сказать, что метод createPrintTask возвращает экземпляр объекта Windows.Graphics.Printing.PrintTask, представляющий только что созданное задание на печать. Если мы собираемся указывать для этого задания параметры печати (как это сделать, будет описано позже), мы сохраним его в какой-либо переменной. В противном случае сохранять его нет нужды - всё равно оно будет занесено в список диспетчера печати автоматически.
[code]function oPMPrintTaskRequested(evt) {
evt.request.createPrintTask("Задание", function(args) {
args.setSource(MSApp.getHtmlPrintDocumentSource(document));
});
}[/code]
Здесь мы написали обработчик события printtaskrequested, который создаст задание на печать, содержащее весь интерфейс приложения.
На этом реализация основных функций печати закончена.
3.4. Выполнение печати из интерфейса приложения
Мы только что рассмотрели, как запустить печать с помощью волшебной кнопки Устройства. Но часто бывает полезнее дать пользователю возможность выполнить печать прямо из интерфейса приложения, скажем, нажатием специальной кнопки. Можно ли такое сделать? Конечно можно!
Диспетчер печати поддерживает метод showPrintUIAsync. Он выводит на экран панель Печать и позволяет выполнить печать на принтере, установленном как принтер по умолчанию. Параметров он не принимает и результата не возвращает.
[code]<input type="button" id="btnPrint" value="Печать" />
. . .
var btnPrint = document.getElementById("btnPrint");
btnPrint.addEventListener("click", function() {
oPM.showPrintUIAsync();
});[/code]
Создаём кнопку Печать и привязываем к её событию click обработчик, который выведет на экран соответствующую панель. (Тег <input>, для атрибута type которого задано значение button, создаёт кнопку; атрибут тега value в данном случае задаёт надпись для кнопки.)
4. Задание параметров печати
Мы уже знаем, что платформа Metro позволяет задавать параметры печати - формат и ориентацию бумаги, количество копий и пр. - программно. Сейчас мы узнаем, как это делается.
Следует сразу уяснить, что параметры печати устанавливаются для задания на печать. Это значит, что мы можем напечатать один документ с одним набором параметров, а другой - с другим. Однако мы не можем изменить значения параметров печати по умолчанию, указанные в настройках принтера, из обычного Metro-приложения.
На заметку Имеется возможность создать Metro-приложение, предназначенное для управления принтером и, соответственно, позволяющее устанавливать для него параметры по умолчанию. Такие приложения должны иметь особые права, позволяющие им это сделать. Впрочем, данная статья посвящена не им.
Задание на печать, то есть представляющий его объект Windows.Graphics.Printing.PrintTask, поддерживает свойство options. Это свойство хранит экземпляр объекта Windows.Graphics.Printing.PrintTaskOptions, представляющий набор доступных параметров печати, значения которых мы можем задать.
Значениями почти всех этих свойств являются элементы соответствующих им перечислений. Все эти перечисления имет одно сходство - они содержат три элемента, являющихся для них общими. Давайте их рассмотрим.
default - соответствующий параметр выставлен в значение по умолчанию. Значение по умолчанию для данного параметра устанавливается в настройках принтера.
notAvailable - обозначает, что соответствующий параметр неприменим к данному принтеру. Например, если принтер не поддерживает двустороннюю печать, то параметр, устанавливающий настройки двусторонней печати, не имеет для него смысла. Попытка присвоить свойству, имеющему значение notAvailable и, соответственно, неприменимому для данного принтера, какое-либо другое значение не будет иметь успеха - значение этого свойства так и останется равным notAvailable, - но и не вызовет возникновения ошибки.
printerCustom - обозначает, что для соответствующего параметра указано значение, либо введённое пользователем вручную, либо являющееся уникальным для данной модели принтера. В качестве примера можно указать ситуацию, когда для принтера задан пользовательский размер бумаги.
Теперь рассмотрим наиболее интересные для нас и поддерживаемые большинством принтеров параметры печати и соответствующие им свойства объекта Windows.Graphics.Printing.PrintTaskOptions.
Свойство mediaSize задаёт размер бумаги. Его значением должен являться один из элементов перечисления Windows.Graphics.Printing.PrintMediaSize. Это перечисление включает в себя очень много элементов, полный список которых приведён на этой Web-странице.
[code]function oPMPrintTaskRequested(evt) {
var oPT = evt.request.createPrintTask("Задание", function(args) {
args.setSource(MSApp.getHtmlPrintDocumentSource(document));
});
oPT.options.mediaSize = Windows.Graphics.Printing.PrintMediaSize.isoA4;
}[/code]
Создаём задание на печать и устанавливаем для него размер бумаги А4.
[code]oPT.options.mediaSize = Windows.Graphics.Printing.PrintMediaSize.default;[/code]
А здесь мы указываем размер бумаги по умолчанию.
[code]if (oPT.options.mediaSize != Windows.Graphics.Printing.PrintMediaSize.notAvailable) then {
oPT.options.mediaSize = Windows.Graphics.Printing.PrintMediaSize.isoA4;
}[/code]
Проверяем, применим ли параметр размера бумаги для данного принтера, и, если это так, устанавливаем размер бумаги А4. Впрочем, эту проверку выполнять необязательно, поскольку, как говорилось ранее, даже если принтер не поддерживает данный параметр, успеха операция присваивания данному свойству другого значения иметь не будет, но и не вызовет возникновения ошибки.
Свойство orientation задаёт ориентацию бумаги - портретную или ландшафтную. Его значением должен быть один из элементов перечисления Windows.Graphics.Printing.PrintOrientation: portrait (портретная ориентация) или landscape (ландшафтная ориентация).
[code]oPT.options.orientation = Windows.Graphics.Printing.PrintOrientation.landscape;[/code]
Устанавливаем для задания на печать ландшафтную ориентацию бумаги.
Свойство numberOfCopies указывает количество копий печатаемого документа. Его значением должно быть целое число.
[code]oPT.options.numberOfCopies = 3;[/code]
Печатаем три копии документа.
Свойство printQuality устанавливает качество печати. Его значением должен являться один из элементов перечисления Windows.Graphics.Printing.PrintQuality:
automatic - качество печати выбирается автоматически;
draft - черновик;
fax - факс;
high - высокое качество;
normal - обычное качество;
photographic - фотографическое качество, самое высокое;
text - текст.
[code]oPT.options.printQuality = Windows.Graphics.Printing.PrintQuality.text;[/code]
Печатаем документ с качеством, подходящим для вывода текста.
5. Настройка панели Печать
Теперь рассмотрим способ настроить панель Печать под наши нужды, а именно, указать, какие элементы управления для настройки печати должны на ней присутствовать.
Объект Windows.Graphics.Printing.PrintTaskOptions, представляющий параметры печати, поддерживает свойство displayedOptions. Его значением является экземпляр объекта-коллекции, содержащий список всех отображаемых на панели параметров печати. Этот объект-коллекция реализует интерфейс Windows.Foundation.Collections.IVector и типизирован для хранения списка строк, собственно, представляющих отображаемые параметры.
[code]var oDO = oPT.options.displayedOptions;[/code]
Перед тем как задавать список отображаемых в панели параметров печати, нам следует очистить этот список. Сделать это можно вызовом не принимающего параметров и не возвращающего результата метода clear объекта-коллекции параметров печати.
[code]oDO.clear();[/code]
Для добавления в список очередного параметра печати, который должен отображаться на панели, следует вызвать метод append объекта-коллекции. Этот метод принимает в качестве единственного параметра строку с обозначением нужного параметра и не возвращает результата.
Мы можем передавать методу append непосредственно строки с обозначениями нужных параметров печати. Но куда удобнее пользоваться для этого перечислением Windows.Graphics.Printing.StandardPrintTaskOptions. Элементы этого перечисления, соответствующие рассмотренным нами в параграфе 4 параметрам печати, перечислены далее.
mediaSize - размер бумаги;
orientation - ориентация бумаги;
copies - количество копий;
printQuality - качество печати.
[code]oDO.append(Windows.Graphics.Printing.StandardPrintTaskOptions.mediaSize);
oDO.append(Windows.Graphics.Printing.StandardPrintTaskOptions.orientation);[/code]
Выводим в панели Печать только элементы управления, задающие размер и ориентацию бумаги.
6. Настройка печатаемого документа
А теперь рассмотрим очень важный вопрос, касающийся самого печатаемого документа. А именно, его внешнего вида.
Ранее говорилось, что из Metro-приложения, разработанного с применением технологий HTML, CSS и JavaScript, можно распечатать только интерфейс этого приложения, выводящийся на экране. Задать произвольное печатаемое содержимое мы в этом случае не сможем - для этого придётся использовать другие технологии разработки Metro-приложений.
Но что если нам надо вывести на печать не то, что присутствует на экране? Скажем, если мы разрабатываем приложение клиента электронной почты, у нас на экране будут присутствовать список почтовых сообщений и содержимое сообщения, выбранного в этом списке. Тогда нам будет нужно вывести на печать только текст выбранного сообщения; список сообщений будет там явно лишним. Возможно ли вообще такое сделать?
Конечно! Мы можем скрыть на печатаемом документе определённые элементы интерфейса, оставив только те, что должны быть напечатаны. Мы можем также указать для печатемого документа другие параметры, скажем, увеличить размер шрифта, убрать рамки и фон и пр. Мы даже можем выводить печатаемый документ в отдельном элементе интерфейса, не выводящимся на экран, в при печати выводить его, одновременно скрывая остальные элементы интерфейса.
Для таких случаев платформа Metro поддерживает так называемые медиазапросы. Их можно рассматривать как наборы стилей CSS, действующие только в определённые моменты работы приложения. Например, один медиазапрос может содержать стили, действующие при выводе на экран, а другой - стили, действующие при выводе на печать. Как раз наш случай!
Уже понятно, что медиазапросы создаются в описании оформления приложения - в файлах таблиц стилей. Основная таблица стилей, описывающая оформление основного интерфейса приложения, хранится в файле default.css.
Синтаксис описания медиазапросов таков:
[code]@media <тип вывода> {
<набор стилей, действующих при указанном типе вывода>
}[/code]
Тип вывода указывается в виде одного из следующих значений:
screen - вывод на экран;
print - вывод на печать;
all - вывод и на экран, и на печать.
[code]@media screen {
.content {
border: 1px solid black;
}
}
@media print {
.content {
border: none;
}
}[/code]
Здесь мы создали два медиазапроса. Первый будет действовать при выводе на экран и задаст у элементов интерфейса с привязанным стилевым классом content чёрную сплошную рамку толщиной в один пиксел (параметры рамки задаёт атрибут стиля border). Второй будет действовать при выводе на печать и уберёт рамку у этих же элементов интерфейса.
Стили, не входящие в состав медиазапроса, имеют меньший приоритет, чем указанные в составе медиазапросов. Это значит, что, если, например, нам следует скрыть рамку у какого-либо элемента интерфейса при его печати, нам достаточно создать медиазапрос с соответствующим стилем, для которого указать лишь отсутствие рамки. Вот так:
[code]@media print {
#divButtons {
display: none;
}
}[/code]
А этот небольшой медиазапрос скроет при печати элемент управления с именем divButtons. (Атрибут стиля display управляет отображением элемента интерфейса; значение none этого атрибута стиля скрывает элемент.)
7. Дополнительные возможности печати
Осталось рассмотреть некоторые дополнительные возможности подсистемы печати Metro, которые могут нам пригодиться.
Объект Windows.Graphics.Printing.PrintTask, представляющий задание на печать, поддерживает четыре события, перечисленные далее.
submitting - возникает, когда задание на печать начинает формироваться.
previewing - возникает при выводе в области предварительного просмотра в панели Печать представления печатаемого документа.
progressing - периодически возникает в процессе печати документа.
Обработчик этого события в качестве единственного параметра принимает экземпляр объекта Windows.Graphics.Printing.PrintTaskProgressingEventArgs, хранящий дополнительные сведения о событии. Эти дополнительные сведения невелики - всего лишь количество страниц в печатаемом документе; оно хранится в свойстве documentPageCount этого объекта в виде целого числа.
completed - возникает после завершения, удачного или неудачного, процесса печати.
Обработчик этого события в качестве единственного параметра принимает экземпляр объекта Windows.Graphics.Printing.PrintTaskCompletedEventArgs, хранящий дополнительные сведения о событии. Они включают состояние завершения печати, хранящееся в свойстве completion этого объекта.
Значением данного свойства является один из элементов перечисления Windows.Graphics.Printing.PrintTaskCompletion: abandoned (документ почему-то не был напечатан, и хранящее его задание на печать так и осталось в списке диспетчера печати), canceled (печать была прервана пользователем), failed (печать не была выполнена в результате аппаратной или программной ошибки) или submitted (печать была успешно выполнена).
[code]oPT.addEventListener("progressing", function(args) {
var nPages = args.documentPageCount;
//Выводим количество страниц в печатаемом документе на экран
});
oPT.addEventListener("completed", function(args) {
if (args.completion == Windows.Graphics.Printing.PrintTaskCompletion.submitted) {
//Печать прошла удачно
} else {
//Возникли проблемы...
}
});[/code]
Как мы уже знаем, весь интерфейс приложения представляется экземпляром объекта HTMLDocument, доступным из переменной document. Этот объект поддерживает свойство body, значением которого является экземпляр объекта HTMLBodyDocument, представляющий видимый интерфейс приложения (содержимое тега <body>). Объект HTMLBodyDocument поддерживает два события, связанные с печатью, которые также могут нам пригодиться.
beforeprint - возникает непосредственно перед печатью документа.
afterprint - возникает после выполнения печати документа.
8. Реализация печати в приложении просмотровщика графики
В качестве примера мы реализуем поддержку печати в приложении просмотровщика графических файлов ImageViewer, написанном нами ранее.
Откроем в Visual Studio проект ImageViewer. Сразу же откроем файл default.css, в котором хранится CSS-код, описывающий оформление приложения. Вставим в его конец такой фрагмент:
[code]@media print {
body {
display: -ms-grid;
-ms-grid-columns: 1fr;
-ms-grid-rows: 1fr 40px;
}
#divFolderPath, #divList { display: none; }
#divViewer { -ms-grid-row: 1; }
#divFileName { -ms-grid-row: 2; }
}[/code]
Здесь мы создали медиазапрос со стилями, действующими при печати. Мы создали сеточную разметку из одного столбца и двух строк; блок, в котором выводится выбранное пользователем изображение, мы поместили в первую ячейку сетки, а блок с именем выбранного файла - во вторую. Блок, в котором выводится путь к выбранной папке, и блок - список графических файлов мы скрыли.
В результате напечатаны будут лишь само выбранное изображение и имя файла, в котором оно хранится.
Откроем файл default.js, в котором пишется код логики. Отыщем код инициализации и вставим в его конец такие выражения:
[code]document.addEventListener("DOMContentLoaded", function() {
WinJS.UI.processAll().then(function() {
. . .
var oPM = Windows.Graphics.Printing.PrintManager.getForCurrentView();
oPM.addEventListener("printtaskrequested", oPMPrintTaskRequested);
});
});[/code]
Эти выражения получат диспетчер печати и привяжут к его событию printtaskrequested обработчик.
Объявим этот обработчик:
[code]function oPMPrintTaskRequested(evt) {
var oPT = evt.request.createPrintTask("Изображение", function(args) {
args.setSource(MSApp.getHtmlPrintDocumentSource(document));
});
oPT.options.orientation = Windows.Graphics.Printing.PrintOrientation.landscape;
oPT.options.mediaSize = Windows.Graphics.Printing.PrintMediaSize.isoA4;
oPT.options.printQuality = Windows.Graphics.Printing.PrintQuality.photographic;
}[/code]
Он создаст задание на печать и задаст для печатаемого документа размер бумаги А4, ландшафтную ориентацию и фотографическое качество печати.
Сохраним все исправленные файлы и запустим приложение на выполнение. Выберем в списке какой-либо файл и выполним печать. Если мы всё сделали правильно, выбранное нами изображение будет успешно распечатано.
9. Заключение
В этой статье мы изучили инструменты платформы Metro, призванные обеспечить в приложениях поддержку печати. И для практики реализовали поддержку печати в приложении просмотровщика графики ImageViewer.
С одной стороны, дать приложению возможность печатать документы оказалось очень просто. С другой стороны, возможности по формированию печатаемого документа в Metro-приложениях, написанных на HTML, CSS и JavaScript, заметно ограничены. Что ж, сама Microsoft рекомендует использовать "связку" HTML+CSS+JavaScript для написания лишь самых простых приложений...
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.04 секунд (Общее время SQL: 0.014 секунд - SQL запросов: 51 - Среднее время SQL: 0.00028 секунд))