Pull to refresh

Живые тайлы (Live tiles) в Windows 8 (WinRT)

Reading time 21 min
Views 24K
UI Windows 8 был существенно переработан и появился стартовый экран с тайлами (tiles – далее в скобках буду указывать используемые английские терминологии). Одним из основных преимуществ тайлов перед иконками – это возможность «оживления» (live tile) и предоставления важной для пользователя информации непосредственно на тайле. Кроме того, есть возможность создать вторичные тайлы (secondary tiles), которая позволяет переходить в приложение с определенными параметрами или на страницу вглубь приложения. В качестве примера можно привести погодное приложение отображающее погоду на основном тайле и погоду в выбранных городах на вторичных тайлах.

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

В этой статье рассмотрим следующие пункты.

1. Тайлы по умолчанию.
2. Живые тайлы
    2.1. Шаблоны
    2.2. Способы реализации тайлов
    2.3. Живые тайлы. Полная реализация.
    2.4. Ссылка на изображения в тайлах.
3. Управление временем жизни живого тайла.
    3.1. Отключение тайла
    3.2. Установка лимита времени тайла.
    3.3. Установка отображения тайла по расписанию.
    3.4. Управление списком тайлов по расписанию (получение списка, удаление)
4. Очередь тайлов.
5.Индикатор событий (Badges) в тайлах
6. Периодическое обновление тайлов (с удаленных ресурсов)
7. Вторичные тайлы (Secondary Tiles)
    7.1. Закрепление вторичного тайла
    7.2. Активация приложения со вторичного тайла
    7.3. Удаление закрепленного тайла
    7.4. «Оживление» вторичного тайла
8. Управление живым тайлом через Background Task и Push Notification

1. Тайлы по умолчанию.


В Win8 можно установить тайлы двух основных размеров – квадратные 150х150 (square) и широкие 310х150 (wide).

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

image

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


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

2.Живые тайлы


2.1. Шаблоны

В Windows 8 есть поддержка «живых» тайлов, похожих на живые тайлы в Windows Phone. «Живые тайлы» получили свое название из-за возможности «оживления» тайла приоритетной для пользователя информацией.

В API WinRT предусмотрены 46 шаблонов для тайлов. Подробное описание каждого из шаблона можно прочитать на странице MSDN

Существует 10 шаблонов для квадратных тайлов и 36 для широких, если не планируется использование в приложении широких тайлов, то 10 шаблонов квадратных тайлов вполне достаточно…

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

Шаблоны квадратных тайлов
Текстовые Графические Графика и текст (двусторонние)
TileSquareBlock,
TileSquareText01,
TileSquareText02,
TileSquareText03,
TileSquareText04,
TileSquareImage TileSquarePeekImageAndText01
TileSquarePeekImageAndText02
TileSquarePeekImageAndText03
TileSquarePeekImageAndText04

Выбор широких тайлов гораздо больше.
При этом графических в «чистом» виде всего два, и также есть односторонние тайлы с графикой и текстом на одном тайле.

Шаблоны широких тайлов
Текстовые Графические Текстовые и графические
TileWideBlockAndText01
TileWideBlockAndText02
TileWideText01
TileWideText02
TileWideText03
TileWideText04
TileWideText05
TileWideText06
TileWideText07
TileWideText08
TileWideText09
TileWideText10
TileWideText11
TileWideImage
TileWideImageCollection
Односторонние
TileWideImageAndText01
TileWideImageAndText02
TileWideSmallImageAndText01
TileWideSmallImageAndText02
TileWideSmallImageAndText03
TileWideSmallImageAndText04
TileWideSmallImageAndText05

Двусторонние (анимированныйпереход)
TileWidePeekImageCollection01
TileWidePeekImageCollection02
TileWidePeekImageCollection03
TileWidePeekImageCollection04
TileWidePeekImageCollection05
TileWidePeekImageCollection06
TileWidePeekImageAndText01
TileWidePeekImageAndText02
TileWidePeekImage01
TileWidePeekImage02
TileWidePeekImage03
TileWidePeekImage04
TileWidePeekImage05
TileWidePeekImage06

2.2. Способы реализации тайлов

Добавить поддержку живых тайлов очень просто. По ссылке в MSDN можно найти описание xml шаблона.

Рассмотрим пример добавление квадратного тайла TileSquareBlock с описанием xml:

<tile>
  <visual>
    <binding template="TileSquareBlock">
      <text id="1">Text Field 1</text>
      <text id="2">Text Field 2</text>
    </binding>  
  </visual>
</tile>


Шаблон лучше всего подходит для отображения числовой информации. Теги в элементе служат для установки нужных нам значений.
Укажем значение 25 для первого поля и degrees для второго:

<tile>
  <visual>
    <binding template="TileSquareBlock">
      <text id="1">25</text>
      <text id="2">degrees</text>
    </binding>  
  </visual>
</tile>

После того как определились с шаблоном, приступим к написанию кода.
У нас есть три разных идентичных способа реализации тайла:

2.2.1. «Ручная» реализация

Суть этого способа заключается в том, что мы вручную формируем необходимый Xml документ и создаем на его основе тайл:
var xml = @"<tile>
  <visual>
    <binding template=""TileSquareBlock"">
      <text id=""1"">25</text>
      <text id=""2"">Degrees</text>
    </binding>  
  </visual>
</tile>";
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
var notification=new TileNotification(xmlDocument);
TileUpdateManager.CreateTileUpdaterForApplication().Update(notification);


2.2.2. По предустановленному шаблону

В WinRT заложены готовые шаблоны. Используя API WinRT “TileUpdateManager.GetTemplateContent” мы можем загрузить XmlDocument любого шаблона и менять значения пользуясь API XmlDocument.

var xmlDocument = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquareBlock);
 
var nodes = xmlDocument.GetElementsByTagName("binding").First().ChildNodes;
nodes[0].InnerText = "25";
nodes[1].InnerText = "Degrees";
 
var notification = new TileNotification(xmlDocument);
TileUpdateManager.CreateTileUpdaterForApplication().Update(notification);


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

2.2.3. С помощью библиотеки NotificationsExtensions

В официальных примерах поставляется библиотека NotificationsExtensions, созданная для упрощения работы с тайлами. Библиотека является оберткой над API WinRT и собирает необходимый xml документ. Давайте рассмотрим как будет выглядеть реализация нашего тайла с помощью этой библиотеки.

ITileSquareBlock tileContent = TileContentFactory.CreateTileSquareBlock();
tileContent.TextBlock.Text = "25";
tileContent.TextSubBlock.Text = "Degrees";
TileUpdateManager.CreateTileUpdaterForApplication().Update(tileContent.CreateNotification());


Как мы видим, библиотека несколько упрощает работу с тайлами. Далее в статье мы будем рассматривать в основном первый способ, так как это дает большее понимание происходящих процессов и дает необходимые знания для правильного использования второго и третьего способа.
После того как определились со способом реализации добавим следующее незамысловатое small logo в манифест. (Small logo является опциональным и его указание не обязательно).
image
Теперь после запуска нашего приложения основной тайл «оживет», и сменит свою картинку на тайл с нашим контентом (при условии, что сейчас режим тайла «квадратный»):

image

Для «широкого» тайла у нас не будет изменений, рассмотрим далее как правильно реализовывать тайлы.

2.3. Живые тайлы. Полная реализация.

Возможно вы захотите поддерживать не только квадратный тайл но и широкий тайл.
Для того чтобы добавить одновременно поддержку широкого и квадратного тайла мы должны объединить их в один xml элемент.
Объединие осуществляется достаточно просто – необходимо объединить теги в один xml.
Т.е. если выбрали шаблон для квадратного тайла:

<tile>
  <visual>
    <binding template="TileSquareBlock">
      <text id="1">25</text>
      <text id="2">degrees</text>
    </binding>  
  </visual>
</tile>


и шаблон для широкого тайла:

<tile>
  <visual>
    <binding template="TileWideText03">
      <text id="1">25 degrees</text>
    </binding>  
  </visual>
</tile>


то объединенный вариант будет выглядеть так:

<tile>
  <visual>
    <binding template="TileSquareBlock">
      <text id="1">25</text>
      <text id="2">degrees</text>
    </binding>  
    <binding template="TileWideText03">
      <text id="1">25 degrees</text>
    </binding>  
  </visual>
</tile>


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

private TileNotification CreateNotification(string xml)
{
      var xmlDocument = new XmlDocument();
      xmlDocument.LoadXml(xml);
      return new TileNotification(xmlDocument);
 }


Теперь реализация для широкого и квадратного тайла будет выглядеть следующим образом:

var tile = CreateNotification(@"<tile>
  <visual>
    <binding template=""TileSquareBlock"">
      <text id=""1"">25</text>
      <text id=""2"">Degrees</text>
    </binding> 
    <binding template=""TileWideText03"">
      <text id=""1"">25 degrees in Moscow</text>
    </binding>  
  </visual>
</tile>");
TileUpdateManager.CreateTileUpdaterForApplication().Update(tile);


Так как теперь у нас есть контент для широкого и квадратного тайла, при переключении в режим «широкого» тайла, увидим следующий текст:

image

Библиотека NotificationExtensions также поддерживает возможность указания широкого и квадратного тайла. Рассмотрим аналогичный пример с использованием этой библиотеки:

ITileSquareBlock squareTile = TileContentFactory.CreateTileSquareBlock();
squareTile.TextBlock.Text = "25";
squareTile.TextSubBlock.Text = "Degrees";
 
ITileWideText03 wideTile = TileContentFactory.CreateTileWideText03();
wideTile.TextHeadingWrap.Text = "25 degrees in Moscow";
wideTile.SquareContent = squareTile;
TileUpdateManager.CreateTileUpdaterForApplication().Update(squareTile.CreateNotification());


Здесь «связка» двух типов тайлов осуществляется указанием ссылки на квадратный тайл wideTile.SquareContent = squareTile;

2.4. Ссылка на изображения в тайлах.

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

Добавим небольшой вспомогательный метод для отображения этих изображений.

private void ImageLiveTile(string squareImageUri, string wideImageUri)
{
     var tile = CreateNotification(String.Format(@"<tile>
  <visual>
    <binding template=""TileSquareImage"">
      <image id=""1"" src=""{0}"" alt=""alt text""/>
    </binding>
    <binding template=""TileWideImage"">
      <image id=""1"" src=""{1}"" alt=""alt text""/>
    </binding>  
  </visual>
</tile>",squareImageUri,wideImageUri));
     TileUpdateManager.CreateTileUpdaterForApplication().Update(tile);
 }


В первую очередь рассмотрим как отобразить тайл находящийся у нас в приложении в папке Assets

ImageLiveTile(@"Assets\SquareTileLogo.png", @"Assets\WideTileLogo.png");


После которого можно увидеть следующие тайлы:

image
image


Вместо относительных путей также есть возможность получения доступа к ресурсам в проекте по абсолютному пути. Так мы получим аналогичный результат при следующих адресах:

ImageLiveTile(@"ms-appx:///Assets/SquareTileLogo.png", @"ms-appx:///Assets/WideTileLogo.png");


Также у нас есть возможность отображать изображения с веб-ресурсов. К примеру возьмем с flickr одну и ту же фотографию для квадратного тайла 150х150 и широкого тайла размером 320х159.

ImageLiveTile(@"http://farm5.staticflickr.com/4019/4529892979_23bcdc7b1e.jpg", @"http://farm5.staticflickr.com/4019/4529892979_23bcdc7b1e_n.jpg");


image
image


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

Также есть возможность ссылаться на тайлы в локальном хранилище. Для этого надо использовать префикс ms-appdata:///local/

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

private async Task SaveImage(string url, string fileName)
{
      var client = new HttpClient();
      var bytes = await client.GetByteArrayAsync(url);
 
      var file= await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName,CreationCollisionOption.ReplaceExisting);
     var writeStream = await file.OpenAsync(FileAccessMode.ReadWrite);
     var streamWriter = new BinaryWriter(writeStream.AsStreamForWrite());
     streamWriter.Write(bytes);
     streamWriter.Flush();
}


Теперь мы можем сохранить изображения в локальном хранилище

await SaveImage(@"http://farm5.staticflickr.com/4019/4529892979_23bcdc7b1e.jpg", "squareTile.jpg");
await SaveImage(@"http://farm5.staticflickr.com/4019/4529892979_23bcdc7b1e_n.jpg", "wideTile.jpg");


и обратиться к нему при создании живого тайла

ImageLiveTile(@"ms-appdata:///local/squareTile.jpg", @"ms-appdata:///local/wideTile.jpg");


3. Управление временем жизни живого тайла.


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

3.1. Отключение тайла

В первую очередь рассмотрим как можно отключить тайл:

TileUpdateManager.CreateTileUpdaterForApplication().Clear();


После выполнения этого метода тайлы заменяются на тайл по умолчанию.

3.2. Установка лимита времени тайла.

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

В качестве примера зададим отключение живого тайла через 10 секунд.
var tile = CreateNotification(@"<tile>
  <visual>
    <binding template=""TileSquareBlock"">
      <text id=""1"">40</text>
      <text id=""2"">Degrees</text>
    </binding>     
    <binding template=""TileWideText03"">
      <text id=""1"">40 degrees in Moscow</text>
    </binding>  
  </visual>
</tile>");
tile.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(10);
TileUpdateManager.CreateTileUpdaterForApplication().Update(tile);


После выполнения кода и сворачивания приложения мы можем увидеть как живой тайл появляется и исчезает через 10 секунд.

3.3. Установка отображения тайла по расписанию.

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

К примеру, если мы захотим установить тайл через 10 секунд, напишем следующий код.

var tile = CreateNotification(@"<tile>
  <visual>
    <binding template=""TileSquareBlock"">
      <text id=""1"">10</text>
      <text id=""2"">Degrees</text>
    </binding>     
    <binding template=""TileWideText03"">
      <text id=""1"">10 degrees in Moscow</text>
    </binding>  
  </visual>
</tile>");            
var scheduledTileNotification = new ScheduledTileNotification(tile.Content, DateTimeOffset.UtcNow.AddSeconds(10));
TileUpdateManager.CreateTileUpdaterForApplication().AddToSchedule(scheduledTileNotification);


Метод ScheduledTileNotification принимает XmlDocument. (В данном случае tile.Content содержит XmlDocument).

Точно так же мы можем комбинировать запуск по расписанию со временем жизни тайла.
К примеру код, который создает тайл через 10 секунд на 15 секунд выглядит так:

var scheduledTileNotification = new ScheduledTileNotification(tile.Content, DateTimeOffset.UtcNow.AddSeconds(10));
scheduledTileNotification.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(25);
TileUpdateManager.CreateTileUpdaterForApplication().AddToSchedule(scheduledTileNotification);


3.4. Управление списком тайлов по расписанию (получение списка, удаление)

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

scheduledTileNotification.Id = "1";


Мы можем получить список всех установленных тайлов по расписанию методом TileUpdateManager.CreateTileUpdaterForApplication()

var scheduledTiles = TileUpdateManager.CreateTileUpdaterForApplication();


Получить доступ к нашему тайлу, соответственно, можно по идентификатору

var tile = scheduledTiles.FirstOrDefault(i => i.Id == "1");


Теперь, к примеру, мы можем при необходимости удалить этот тайл.

if(tile!=null)
{
    TileUpdateManager.CreateTileUpdaterForApplication().RemoveFromSchedule(tile);
}


4. Очередь тайлов.


В API WinRT у нас есть возможность установить очередь до 5 тайлов, которые будут циклически отображаться.

Все, что нам надо сделать — это включить поддержку очереди методом:

TileUpdateManager.CreateTileUpdaterForApplication().EnableNotificationQueue(true);


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

private void SetTile(int value)
{
     var tile = CreateNotification(String.Format(@"<tile>
  <visual>
    <binding template=""TileSquareBlock"">
      <text id=""1"">{0}</text>
      <text id=""2"">Degrees</text>
    </binding>     
    <binding template=""TileWideText03"">
      <text id=""1"">{0} degrees in Moscow</text>
    </binding>  
  </visual>
</tile>",value));
     TileUpdateManager.CreateTileUpdaterForApplication().Update(tile);
}


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

TileUpdateManager.CreateTileUpdaterForApplication().Clear();
TileUpdateManager.CreateTileUpdaterForApplication().EnableNotificationQueue(true);
SetTile(15);
SetTile(25);
SetTile(35);


И мы сможем увидеть как у нас циклически 3 тайла сменяют друг друга. Метод Clear нужен для того чтобы очистить очередь, в противном случае при следующем выполнении кода у нас образуется стек из 5 тайлов с двумя одинаковыми тайлами, что приведет к тому, что периодически тайл будет сменяться на такой же тайл.
При использовании этого метода необходимо более осторожно проверять работу тайлов, устанавливаемых по расписанию, так как они точно так же попадают в стек и будут «крутиться» с предыдущим тайлом.

5.Индикатор событий (Badges) в тайлах


У нас есть возможность отобразить индикатор события на тайлах (независимо живые или тайлы по умолчанию). Индикатор событий отображается в правом нижнем углу и можно отобразить число (от 1 до 99 к примеру количество непрочитанных сообщений) или глиф (состояние приложения).

Более подробно можно прочитать об индикаторах событий на странице MSDN на русском языке. Здесь же рассмотрим реализацию индикатора событий.

Для работы с индикаторами у нас есть BadgeUpdateManager у которого API почти идентично API TileUpdateManager.

Рассмотрим как отобразить число 12 в индикаторе событий, для этого возьмем соответствующий шаблон со страницы MSDN/>

var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(@"<badge value=""12""/>"));
 
var badgeNotification = new BadgeNotification(xmlDocument);
BadgeUpdateManager.CreateBadgeUpdaterForApplication().Update(badgeNotification);


Теперь мы можем наблюдать индикатор со значением 12 как на тайле по умолчанию, так и на живом тайле:

image
image


Для того чтобы отобразить глиф мы должны заменить в xml значение 12 на один из идентифиаторов. К примеру на “attention”

xmlDocument.LoadXml(@"<badge value=""attention""/>"));

image
Точно так же как и для тайлов мы можем установить лимит времени жизни для индикатора событий:

badgeNotification.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(10);


И, аналогично, можем удалить индикатор
BadgeUpdateManager.CreateBadgeUpdaterForApplication().Clear();


6. Периодическое обновление тайлов (с удаленных ресурсов)


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

Для простоты создадим новое Web-приложение, которое отдает нам тайл с текущим временем. Если это будет ASP.NET приложение, добавим HttpHandler, которое возвращает нам xml тайла с текущим временем:

public class TileHandler : IHttpHandler
{
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/xml";
            context.Response.Write(String.Format(@"<tile>
  <visual>
    <binding template=""TileSquareText02"">
      <text id=""1"">{0}</text>
      <text id=""2"">current time</text>
    </binding> 
    <binding template=""TileWideText03"">
      <text id=""1"">Time: {0}</text>
    </binding>
  </visual>
</tile>
",DateTime.Now.ToShortTimeString()));
        }
        public bool IsReusable {get { return false; }}
 }


Теперь, если к примеру, обработчик находится по адресу localhost:28457/TileHandler.ashx мы можем использовать этот адрес для получения уведомлений.

Следующий код в приложении запускает проверку и обновление тайла через каждые полчаса:

TileUpdateManager.CreateTileUpdaterForApplication().StartPeriodicUpdate(new Uri("http://localhost:28457/TileHandler.ashx"),PeriodicUpdateRecurrence.HalfHour);


Мы можем запустить обновление тайла не сразу, а через указанное время. К примеру, следующий код запускает проверку и обновление тайлов через 3 часа:

TileUpdateManager.CreateTileUpdaterForApplication().StartPeriodicUpdate(new Uri("http://localhost:28457/TileHandler.ashx"), DateTimeOffset.UtcNow.AddHours(10), PeriodicUpdateRecurrence.HalfHour);


Теперь, если мы запустим приложение, мы увидим следующие тайлы для широкого и квадратного тайла:

image
image


Также есть возможность установления «очереди» тайлов (как описано в разделе «Очередь тайлов»). Синтаксис практически идентичен и вместо единичного Uri у нас есть возможность указать коллекцию Uri до 5 элементов.

В первую очередь нам необходимо включить поддержку очереди:

TileUpdateManager.CreateTileUpdaterForApplication().EnableNotificationQueue(true);
Uri[] uriCollection=new []
       {
           new Uri("http://localhost:28457/TileHandler1.ashx"), 
           new Uri("http://localhost:28457/TileHandler2.ashx"), 
           new Uri("http://localhost:28457/TileHandler3.ashx"), 
           new Uri("http://localhost:28457/TileHandler4.ashx"), 
           new Uri("http://localhost:28457/TileHandler5.ashx"), 
       };
TileUpdateManager.CreateTileUpdaterForApplication().StartPeriodicUpdateBatch(uriCollection,PeriodicUpdateRecurrence.HalfHour);


Обновление идентификаторов событий происходит идентичным способом.

К примеру, если у нас есть адрес localhost:28457/BadgeHandler.ashx который возвращает xml вида />

Следующий код будет раз в полчаса запрашивать и обновлять состояние индикатора.

BadgeUpdateManager.CreateBadgeUpdaterForApplication().StartPeriodicUpdate(new Uri("http://localhost:28457/TileBadgeHandler.ashx"),PeriodicUpdateRecurrence.HalfHour);


7. Вторичные тайлы (Secondary Tiles)


Вторичные тайлы дают возможность запуска приложения на определенных страницах с определенными параметрами. Достаточно подробный пример работы со вторичными тайлами можно скачать из примеров MSDN. Рассмотрим работу со вторичными тайлами.

7.1. Закрепление вторичного тайла

Закрепить вторичный тайл достаточно просто:

К примеру, если у нас есть кнопка закрепления тайла, мы напишем следующий обработчик к кнопке для закрепления тайла (для простоты используем те же логотипы, что и для тайла по умолчанию):

private async void PinToStart_Click(object sender, RoutedEventArgs e)
{
      SecondaryTile secondaryTile = new SecondaryTile()
      {
           TileId = "MyTileId",
           ShortName = "Tile short name",
           DisplayName = "Tile display name",
           Arguments = "MyTileArgument",
           TileOptions = TileOptions.ShowNameOnLogo | TileOptions.ShowNameOnWideLogo,
           Logo = new Uri("ms-appx:///assets/SquareTileLogo.png"),
           WideLogo = new Uri("ms-appx:///assets/WideTileLogo.png"),
       };
 
      bool isPinned = await secondaryTile.RequestCreateAsync();
}


TileId является уникальным идентификатором тайла и используется в дальнейшем для работы с конкретным тайлом (удаление, обновление, запуск и т.п.)

Для основного тайла используется уникальный идентификатор “App”. Этот идентификатор можно считать зарезервированным и закрепить тайл с таким идентификатором не получится (так как очевидно такой тайл уже существует). Попытка удаления тайла с таким идентификатором приводит к тому, что у нас теряются ссылки со стартового экрана и списка программ, и полностью «отваливается» возможность дальнейшей работы со вторичными тайлами.

Очевидно, этот баг, и скорее всего он будет исправлен, но, в любом случае, настоятельно не рекомендуется использовать в качестве идентификатора “App”.
После клика по кнопке у нас появится следующее диалоговое окно закрепления тайла:

image

7. 2. Активация приложения со вторичного тайла

После того как мы создали вторичный тайл, необходимо обработать активацию приложения по вторичному тайлу.
Для этого в методе AppXaml.cs мы можем обработать аргументы запуска args. Мы можем получить из этого параметра идентификатор тайла TileId и аргумент. Для простоты реализуем сценарий, когда открывается специальная страница в приложении при активации по тайлу.
Для этого в том же файле App.xaml.cs в методе OnLaunch допишем в начало метода код перехода на другую страницу, при условии активации со вторичного тайла

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
      var tileId= args.TileId;
      if (tileId == "MyTileId")
      {                 
          if(Window.Current.Content ==null)
          {
              Window.Current.Content=new Frame();
          }
 
          var secondaryTileArgument = args.Arguments;
          ((Frame)Window.Current.Content).Navigate(typeof(SecondaryTilePage), secondaryTileArgument);
          Window.Current.Activate();
          return;
     }
     …
 }


Теперь при активации приложения со вторичного тайла будет осуществлен переход на страницу с тайлом и в качестве аргумента будет передано значение использованное при закреплении тайла.

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

7. 3. Удаление закрепленного тайла

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

Добавим кнопку Unpin и обработчик к кнопке:

private async void UnPinFromStart_Click(object sender, RoutedEventArgs e)
{
       if(Windows.UI.StartScreen.SecondaryTile.Exists("MyTileId"))
       {
           SecondaryTile secondaryTile = new SecondaryTile("MyTileId");
           bool unpinned = await secondaryTile.RequestDeleteAsync();
       }
}


Метод SecondaryTile.Exists() позволяет проверить наличие закрепленного тайла на рабочем столе.
При выполнения этого кода, пользователь должен подтвердить, что хочет удалить вторичный Tile, после чего тайл будет удален

image

7. 4. «Оживление» вторичного тайла

Вторичные тайлы тоже можно сделать «живым». API для вторичного тайла идентично основному тайлу.

Для работы со вторичным тайлом используется метод TileUpdateManager.CreateTileUpdaterForSecondaryTile(tileId).

Аналогичный пример для вторичного тайла

var tile = CreateNotification(@"<tile>
  <visual>
    <binding template=""TileSquareBlock"">
      <text id=""1"">25</text>
      <text id=""2"">Degrees</text>
    </binding>     
    <binding template=""TileWideText03"">
      <text id=""1"">25 degrees in Moscow</text>
    </binding>  
  </visual>
</tile>");
TileUpdateManager.CreateTileUpdaterForSecondaryTile("MyTileId").Update(tile);


8.Управление живым тайлом через Background Task и Push Notification


Темы BackgroundTask и PushNotification заслуживают отдельной статьи каждый.
Здесь рассмотрим принцип работы с тайлами для обоих тем.

8.1. Background Task

Быстрое введение в создание background task можно прочитать в MSDN

В методе OnCompleted при срабатывании фоновой задачи мы можем установить LiveTile

void OnCompleted(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
{ 
      var tile = CreateNotification(String.Format(@"<tile>
  <visual>
    <binding template=""TileSquareText04"">
      <text id=""1"">{0}</text>
      <text id=""2""></text>
    </binding> 
    <binding template=""TileSquareText02"">
      <text id=""1"">{0}</text>
      <text id=""2""></text>
    </binding>  
  </visual>
</tile>", DateTime.Now.ToString("hh:mm:ss")));
     TileUpdateManager.CreateTileUpdaterForApplication().Update(tile);
  }


8. 2. Push Notification

В Windows 8 push notification-ы стали более безопасными и взамен стало чуть сложнее с ним работать.
О том как с сервера можно пройти авторизацию на WNS сервере и отправить push notification описано на странице MSDN. Там же в конце документа приведен готовый код. Здесь приведу только сигнатуру метода:

public string PostToWns(string secret, string sid, string uri, string xml, string type = «wns/toast») {}

В качестве type необходимо передать значение “wns/tile”
в качестве значения xml передается шаблон tile.

Пример:
string xml = @"<tile>
  <visual>
    <binding template=""TileSquareText04"">
      <text id=""1"">Tile text1</text>
      <text id=""2"">Tile text2</text>
    </binding> 
    <binding template=""TileSquareText02"">
      <text id=""1"">Tile text1</text>
      <text id=""2"">Tile text2</text>
    </binding>  
  </visual>
</tile>";


Единственное замечание — у меня метод указанный на странице msdn не сработал пока я не добавил Content-Type и ContentLength:

request.Headers.Add("X-WNS-Type", type);
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken));
request.ContentType = "text/xml";
request.ContentLength = xml.Length;


Там же в конце документа есть ссылки на создание и открытие канала и описание авторизации на WNS сервере.
В качестве параметров secret и sid используются значения вида:
sid: «ms-app://s-1-23-2-3112458577-1770873644-3250801218-3829720502-2556658560-167841413-2364691272»;
secret: «DcQWqb7eL7oIwVCr8yIOo-aQQRplPDL3»;

Фактически это все что предоставляет API тайлов.

P.S. Больше спасибо хабраюзеру Стасу Павлову stasus и Сергею Урусову petrishko за ценные советы, помощь и поддержку при написании статьи.
Tags:
Hubs:
+48
Comments 6
Comments Comments 6

Articles