[Visual Studio] タイルを使ってみたい

せっかく Windows 8 アプリなので、ホーム画面でいろいろ表示したいですよね。天気予報とかみたいに。ライブタイルって言うらしいです。

ここを参考にして、やってみましょう。

クイック スタート: タイルの更新の送信 (C#/VB/C++ と XAML を使った Windows ストア アプリ)
http://msdn.microsoft.com/ja-jp/library/windows/apps/hh868253.aspx

ライブタイル設定の前に、既定のタイルを設定します。

クイック スタート: Microsoft Visual Studio マニフェスト エディターを使用した既定のタイルの作成 (Windows ストア アプリ)
http://msdn.microsoft.com/ja-jp/library/windows/apps/hh868247.aspx

ソリューションエクスプローラからpackage.appxmanifestをダブルクリック。マニフェストエディタが開く。
マニフェストエディタの[アプリケーション UI] ウィンドウでタイルの詳細を指定する。

20140104_tile_1

まずここまでやります。

150×150、310×150、310×310のロゴが必要なようです。(最低でも150×150は必要)

hello150 hello310150

適当にロゴを用意します。

20140104_tile_3

設定。150×150、310×150、310×310のスケール100のところに設定します。

スタート画面にアイコンをピン止めします。

ロゴ設定前のスタート画面

20140104_tile_4

ロゴ設定後のスタート画面

20140104_tile_5

サイズも変更できます。

20140104_tile_6 20140104_tile_7 20140104_tile_8


それでは、ライブタイル行ってみましょう。

クイック スタート: タイルの更新の送信 (C#/VB/C++ と XAML を使った Windows ストア アプリ)
http://msdn.microsoft.com/ja-jp/library/windows/apps/hh868253.aspx

どのようにタイルの中身を表示するかは、テンプレートから選択します。テキストだけとか、画像+テキストとか、何行表示とか選択します。

タイル テンプレート カタログ (Windows ストア アプリ)
http://msdn.microsoft.com/ja-jp/library/windows/apps/hh761491.aspx

今回は、表示するところまでが目的なので、テキストのみの「TileSquare150x150Text01」で行ってみます。

テンプレートを取得

XmlDocument tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text01);

 

取得されるテンプレートはこんな感じ。

<tile>
  <visual version="2">
    <binding template="TileSquare150x150Text01" fallback="TileSquareText01">
      <text id="1">Text Field 1 (larger text)</text>
      <text id="2">Text Field 2</text>
      <text id="3">Text Field 3</text>
      <text id="4">Text Field 4</text>
    </binding>  
  </visual>
</tile>

 

これの、textエリアを設定すればいいということですね。こんな感じです。

XmlNodeList tileTextAttributes = tileXml.GetElementsByTagName("text");
tileTextAttributes[0].InnerText = "Hello Pokemon!";//タイトル。このテンプレートではサイズ大きめで表示
tileTextAttributes[1].InnerText = "~~";//1行目
tileTextAttributes[2].InnerText = "~~";//2行目
tileTextAttributes[3].InnerText = "";//3行目

 

あとは、指定した XML コンテンツに基づいて通知を作成する

TileNotification tileNotification = new TileNotification(tileXml);

 

通知の有効期限を設定する

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

 

通知をアプリのタイルに送信する

TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);

です。実際にコードに入れてみます。

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Net; //Http系クラス使用のため
using Windows.Data.Json;//Json使用のため
using Windows.UI.Notifications;//ホーム画面通知のため
using Windows.Data.Xml.Dom;//ホーム画面通知のため

// 空白ページのアイテム テンプレートについては、http://go.microsoft.com/fwlink/?LinkId=234238 を参照してください

namespace HelloWorldModernApp
{
    /// <summary>
    /// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            getHelloAsync();
        }

        private async void getHelloAsync()
        {
            try
            {
                string url = "http://localhost/";

                WebRequest request = (WebRequest)WebRequest.Create(url);
                WebResponse response = (WebResponse)await request.GetResponseAsync();

                Stream stream = response.GetResponseStream();
                StreamReader reader = new StreamReader(stream, System.Text.Encoding.UTF8);
                string result = reader.ReadToEnd();

                JsonValue root;
                JsonObject jsonObject;
                string resultString = "";
                string [] tileText = new string[2];
                if (JsonValue.TryParse(result, out root))
                {
                    jsonObject = root.GetObject();

                    if (jsonObject.ContainsKey("result"))
                    {

                        JsonArray resultArray;
                        resultArray = jsonObject.GetNamedArray("result", null);
                        int count = 0;
                        foreach(JsonValue jsonValue in resultArray)
                        {
                            JsonObject resultJsonObject = jsonValue.GetObject();
                            string nameString = resultJsonObject.GetNamedString("name");
                            string voiceString = resultJsonObject.GetNamedString("voice");
                            resultString += nameString +"「" + voiceString + "」\n";
                            if(count < tileText.Length)
                            {
                                tileText[count] = nameString +"「" + voiceString + "」";
                            }
                            count++;
                        }
                    }
                }

                formText.Text = resultString;

                //ライブタイル設定
                //テンプレートを取得
                XmlDocument tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text01);

                //通知のテキストコンテンツを指定
                XmlNodeList tileTextAttributes = tileXml.GetElementsByTagName("text");
                tileTextAttributes[0].InnerText = "Hello Pokemon!";
                tileTextAttributes[1].InnerText = tileText[0];
                tileTextAttributes[2].InnerText = tileText[1];
                tileTextAttributes[3].InnerText = "";

                //指定した XML コンテンツに基づいて通知を作成する
                TileNotification tileNotification = new TileNotification(tileXml);
                //通知の有効期限を設定する
                tileNotification.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(100);
                //通知をアプリのタイルに送信する
                TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);
            }
            catch (Exception ex)
            {
                formText.Text = ex.Message;
            }
        }
    }
}

起動した後に、ホーム画面を表示すると…

20140104_tile_9

出た!

ここまでのコーディングだと、中サイズアイコンの場合のみ、表示されます。複数のサイズで設定するには、それぞれの表示内容を送る必要があります。

クイック スタート: タイルの更新の送信 (C#/VB/C++ と XAML を使った Windows ストア アプリ)
http://msdn.microsoft.com/ja-jp/library/windows/apps/hh868253.aspx

「正方形とワイドの両方の通知をペイロードに含める」やりかたで、一括で設定できます。

ワイド用テンプレートはTileWide310x150ImageAndText02を使ってみます。

<tile>
  <visual version="2">
    <binding template="TileWide310x150ImageAndText02" fallback="TileWideImageAndText02">
      <image id="1" src="image1.png" alt="alt text"/>
      <text id="1">Text Field 1</text>
      <text id="2">Text Field 2</text>
    </binding>  
  </visual>
</tile>

 

ワイド用のテンプレートに、同じように設定してから、 binding 要素を取得

IXmlNode node = tileXml.ImportNode(squareTileXml.GetElementsByTagName("binding").Item(0), true);

 

テンプレート取得・設定してbinding要素に追加

tileXml.GetElementsByTagName("visual").Item(0).AppendChild(node);

これでOK。

実際のソースはこんな感じ。

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Net; //Http系クラス使用のため
using Windows.Data.Json;//Json使用のため
using Windows.UI.Notifications;//ホーム画面通知のため
using Windows.Data.Xml.Dom;//ホーム画面通知のため

// 空白ページのアイテム テンプレートについては、http://go.microsoft.com/fwlink/?LinkId=234238 を参照してください
namespace HelloWorldModernApp
{
    /// <summary>
    /// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            TileUpdateManager.CreateTileUpdaterForApplication().EnableNotificationQueue(true);
            getHelloAsync();
        }

        private async void getHelloAsync()
        {
            try
            {
                string url = "http://localhost/";

                WebRequest request = (WebRequest)WebRequest.Create(url);
                WebResponse response = (WebResponse)await request.GetResponseAsync();

                Stream stream = response.GetResponseStream();
                StreamReader reader = new StreamReader(stream, System.Text.Encoding.UTF8);
                string result = reader.ReadToEnd();

                JsonValue root;
                JsonObject jsonObject;
                string resultString = "";
                string [] tileText = new string[2];
                if (JsonValue.TryParse(result, out root))
                {
                    jsonObject = root.GetObject();

                    if (jsonObject.ContainsKey("result"))
                    {                    
                        JsonArray resultArray;
                        resultArray = jsonObject.GetNamedArray("result", null);
                        int count = 0;
                        foreach(JsonValue jsonValue in resultArray)
                        {
                            JsonObject resultJsonObject = jsonValue.GetObject();
                            string nameString = resultJsonObject.GetNamedString("name");
                            string voiceString = resultJsonObject.GetNamedString("voice");
                            resultString += nameString +"「" + voiceString + "」\n";
                            if(count < tileText.Length)
                            {
                                tileText[count] = nameString +"「" + voiceString + "」";
                            }
                            count++;
                        }
                    }
                }

                formText.Text = resultString;

                //ライブタイル設定
                //テンプレートを取得
                XmlDocument tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text01);

                //通知のテキストコンテンツを指定
                XmlNodeList tileTextAttributes = tileXml.GetElementsByTagName("text");
                tileTextAttributes[0].InnerText = "Hello Pokemon!";
                tileTextAttributes[1].InnerText = tileText[0];
                tileTextAttributes[2].InnerText = tileText[1];
                tileTextAttributes[3].InnerText = "";

                //ワイド用テンプレートを取得
                XmlDocument wideTileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150ImageAndText02);
                //通知のテキストコンテンツを指定
                XmlNodeList wideTileImageAttributes = wideTileXml.GetElementsByTagName("image");
                ((XmlElement)wideTileImageAttributes[0]).SetAttribute("src", "ms-appx:///Assets/Wide310x150Logo.scale-100.png");
                ((XmlElement)wideTileImageAttributes[0]).SetAttribute("alt", "Hello,Pokemon!");

                XmlNodeList wideTileTextAttributes = wideTileXml.GetElementsByTagName("text");
                wideTileTextAttributes[0].InnerText = tileText[0];
                wideTileTextAttributes[1].InnerText = tileText[1];

                //ワイドタイル情報を追加
                IXmlNode node = tileXml.ImportNode(wideTileXml.GetElementsByTagName("binding").Item(0), true);
                tileXml.GetElementsByTagName("visual").Item(0).AppendChild(node);

                //指定した XML コンテンツに基づいて通知を作成する
                TileNotification tileNotification = new TileNotification(tileXml);

                //通知の有効期限を設定する
                tileNotification.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(100);

                //通知をアプリのタイルに送信する
                TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);
            }
            catch (Exception ex)
            {
                formText.Text = ex.Message;
            }
        }
    }
}

実行。

20140104_tile_10

出た。

画像は”ms-appx:///Assets/Wide310x150Logo.scale-100.png”で、アイコンを参照しました。

アプリアイコン→通知→アプリアイコン→通知みたいに繰り返して出したい時はどうすればいいのかがまだわかりませんでした。

スケジュールされた通知、定期的な通知、プッシュ通知の送信 (C#/VB/C++ と XAML を使った Windows ストア アプリ)
http://msdn.microsoft.com/ja-jp/library/windows/apps/hh868242.aspx

このあたりかな。スケジュール実行ができるなら、WebAPIから情報を取得して定期的にパネル更新とか簡単にできそうです。