[win8.1]スタート画面のタイルを動的に作成する(実践編)

[win8] スタート画面のタイルを動的に作成する(前哨戦) – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3443

なところで、C++/CX(DirectX)を使って、スタート画面のタイルを動的に生成する方法を試していたのですが、8.1 になると、RenderTargetBitmap を使って、もっと簡単にできます。

TileTemplateType
http://msdn.microsoft.com/en-us/library/windows.ui.notifications.tiletemplatetype.aspx

を参照すると、タイルには色々と設定ができるのですが、いわゆる「フルカスタマイズ」という方法は用意されていません。画像の配置とシステムフォントを組み合わせた、Microsoft の推奨の方法に従うパターンになります。8 の頃から見ると、TileTemplateType の種類も増えており、色々とできるような気もするのですが、やっぱり「自由なタイル」というのを作ってみたいわけです。

こんな風に、フォントには「MV Boli」を使い、色も変えてしまいます。XAML としては以下のように Grid 要素内に好きなように画像やテキストを配置していきます。

<Grid Grid.Row="2"
    x:Name="panel"
    HorizontalAlignment="Left" Height="310" Margin="219,132,0,0" 
	VerticalAlignment="Top" Width="310">
    <Image 
        x:Name="imageTile"
        HorizontalAlignment="Left" Height="310" VerticalAlignment="Top" Width="310" 
		Source="Assets/hidamari.png"/>
    <TextBlock 
        x:Name="textTitle"
        HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" 
		Text="Hidamari Sketch" VerticalAlignment="Top" FontSize="32" 
		FontFamily="MV Boli" Foreground="#FFE0567C"/>
    <TextBlock 
        x:Name="textNum"
        HorizontalAlignment="Right" Margin="0,248,56,0" TextWrapping="Wrap" 
		Text="{Binding Item.TextNum}" VerticalAlignment="Top" FontSize="32" 
		FontFamily="MV Boli" Width="171" TextAlignment="Right" Foreground="#FFF0E0E4"/>
</Grid>

前回の C++/CX 版の場合は、DirectX を使ってがりがりと書いていかないと駄目だったのですが、8.1 の場合は RenderTargetBitmap クラスを使って、Grid 要素の中身を PNG 形式に保存ができます。

■PNG形式で保存する

保存先はアプリケーションのローカルフォルダにします。こうすることで、タイルに画像を指定することができます。他にも Image 要素の Source にしてすることもできるし、かなり便利です。

/// <summary>
/// ローカルフォルダにタイルを作成
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void ClickMakeTile(object sender, RoutedEventArgs e)
{
    _filename = string.Format("hidamariTile-{0}.png", _model.TextNum);

    RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
    await renderTargetBitmap.RenderAsync(this.panel);
    var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
    var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(
        this._filename, CreationCollisionOption.ReplaceExisting);

    using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream);
        encoder.SetPixelData(
            BitmapPixelFormat.Bgra8,
            BitmapAlphaMode.Ignore,
            (uint)renderTargetBitmap.PixelWidth,
            (uint)renderTargetBitmap.PixelHeight,
            DisplayInformation.GetForCurrentView().LogicalDpi,
            DisplayInformation.GetForCurrentView().LogicalDpi,
            pixelBuffer.ToArray());

        await encoder.FlushAsync();
    }
    Debug.WriteLine("パス:{0}", file.Path);
}

ファイル名を hidamariTile-{0}.png のようにしているのは、タイルに指定するときの画像ファイルをユニークにするためです。どうやら、同じファイル名にするとスタート画面は前のタイルを利用するらしく画像がうまく更新されません。これが、TileSquare310x310Image だけの現象なのかは分かりません。ひょっとすると、前回のファイル名と違っていればいいのかも、なので、2つのファイル名を交互に使うというハックでもいいと思います。

■保存したPNGファイルをタイルに設定する

今回、更新するタイルは 310×310 のサイズの大きなタイルにしました。TileTemplateType の enum 値は 8 の時とがらりと変わっているので、8.1 に移行させるときは注意が必要です。まあ enum 値を適当に直すだけですけどね。

/// <summary>
/// 作成したタイルを設定
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ClickSetTile(object sender, RoutedEventArgs e)
{
    // タイルをアップデート
    var tileTemplate = TileTemplateType.TileSquare310x310Image;
    var doc = TileUpdateManager.GetTemplateContent(tileTemplate);
    var xml = doc.GetXml();
    var images = doc.GetElementsByTagName("image");
    var img = (XmlElement)images.Item(0);
    img.SetAttribute("src", "ms-appdata:///local/" + this._filename);
    // 通知
    var notify = new TileNotification(doc);
    TileUpdateManager.CreateTileUpdaterForApplication().Update(notify);
}

タイルは Xml 形式なので、自前で設定してさほど難しくはありません。適当な関数でくるんでしまえばよいかと。ここでは、XmlDocument を使っていますが、XDocument を使ったほうが楽です。C++/CX のコードが XmlDocument だったので、面倒なのでそのまま引き写しました。

ここの例では、MyModel の TextNum プロパティしか変更していませんが、自分のアプリに合わせて適当なクラスを作ればよいでしょう。あまり汎用的にはせずに、自前のアプリに沿わせるのがベターです。

■実行してみる

「make tile」して画像に保存してから「set tile」すると、スタート画面のタイルが切り替わります。

定期的に変えれば、スタート画面に表示できる時計も作れるし(しかも画像やテキストなどの配置は自由)、サブタイルを利用すれば手持ちの動画ファイルや youtube の画像へのリンクをスタート画面に置くことが可能です。mpg 形式や youtube のプレビュー画面は API を使えば簡単に取得できるので、これは後ほど紹介します。手元の「VS100連発」で使っている方法です…公開はしてなかったかも。これは後で作る予定です。
そんな訳で、8.1 を使って、ちょっと変わったタイルを作って、ストアアプリの目立ち度で差をつけましょう、とかとか。

サンプルコードは、SkyDrive に置いておきます。
http://sdrv.ms/13rcsOk

カテゴリー: C#, WinRT パーマリンク