タイルとバッジのライフサイクル実装(クライアント)編

タイルとバッジのライフサイクル設計編での設計に従って、アプリケーションにセカンダリ・タイルやバッジが必要と判断された場合は、それらのガイドラインに則って「ロゴとアプリケーション名のタイルへの配置」を実装していきます。バッジの実装についてはタイルとバッジのライフサイクル運用(タグの管理)編で解説しています。

サンプル・ソリューション

・タイルとバッジのガイドライン

バッジが必要なアプリケーションは、ライブタイルが必要なアプリケーションである可能性があります。バッジのみで更新情報を伝えられる場合はライブタイルを使用する必要はありませんが、情報の更新頻度が高くユーザーがひとつひとつの通知を確認する可能性よりも、一定の間隔の複数の通知を確認する可能性が高いような場合などは、MSDNのタイルとバッジのガイドラインに則って、ライブタイルの使用を検討します。

◆ライブ・タイルのアンチパターン

×コンテンツ提供が目的でない機能提供中心のアプリ(電卓など)
×最新の状態以外の通知が無いアプリ
×広告やスパムを通知する
×ブランド名やロゴをアニメーションのアイテムのひとつに指定する

ライブ・タイルは、複数の通知を連続して表示します。たとえば、ユーザーがYoutubeの複数のチャンネルの更新情報に関心がある場合は、それぞれのチャンネルの更新情報を連続して表示します。このケースで、特定のチャンネルを別途スタートメニューに表示したい場合はセカンダリ・タイルを使います。前述のタイルとバッジのライフサイクル設計編での設計がしっかりなされている場合、ライブ・タイルのサイズ設計は、セカンダリ・タイルのサイズ設計と同じになります。セカンダリ・タイルのガイドラインのサイズ設計をチェックしてください。

◆ワイドまたは大サイズのタイルやロゴを使う場合の目安

✔通知を使う ✔要約通知のみではない ✔詳細情報をタイルに表示する
✔週に1回以上の通知が見込まれる ✔タイルの通知表示が複数ある
✔タイルに一覧や大きな画像を表示 ✔タイルの既定イメージとしてロゴを使用する

セカンダリ・タイル、ライブ・タイル、バッジの使用やサイズの検討が終わったらサイズを指定して実装していきます。ここでは、ユーザーがセカンダリタイルを設定する際に、複数のサイズ選択を提示するシナリオの実装例を記載します。必要でないサイズは省略してください。アプリケーションの具体例は後述しますが、まずはセカンダリ・タイルの実装の手順を解説します。この中で既定のタイルの設定やロゴの画像の準備なども行います。
ライブ・タイル、バッジはMicrosoft Azure Notification Hubsを経由して更新しますので、タイルとバッジのライフサイクル実装(Azure)編にて解説します。

◆セカンダリ・タイルの実装の手順

1.コンテンツがピン止めされているかどうかを判別するプロパティを用意する アプリバー操作を実装
2.システムグリフ(57665/57750)を使う※1 AppBarButton Icon=”Pin/UnPin”を操作する
3.コンテンツは静的に決定づけられている※2 ×次のコンテンツ
〇特定アーティストの情報画面

※1:Windows.UI.Xaml.Controls.Symbol列挙型のEnumeration値
※2:親アプリとの対話によって決定づけられるコンテンツであってはいけない

ここでは、音楽を再生するアプリ内である特定のアーティストのYoutubeチャンネルなどのアーティストの情報画面のピン止め機能をアプリバーに設置する例を解説します。このアプリ例は、セカンダリ・タイルを利用する際の指針となる「異なるコンテンツ・スコープのコンテンツ提供・更新をウリにしている」を満たすように「アーティストごとの情報画面」というコンテンツ・スコープや「ユーザーのプレイリストの曲を再生する」というコンテンツ・スコープを持つアプリケーションを想定しています。

ピン止めをする画面は、”特定のアーティスト”の情報を表示するという「静的に決定づけられているコンテンツ」を提供することに注意が必要です。セカンダリ・タイルのアンチパターン「親アプリとの対話によって決定づけられるコンテンツ」とは、この例では「情報画面がアプリケーションの何かの属性によって対象のアーティストが変わってしまうこと」です(ユーザーのプレイリストの3番目のアーティストの情報画面をピン止めするなど)。

画面をピン止めをする操作は、下部のアプリケーションバーを表示し、ピン止めボタンをクリックするという操作が一般的です。セカンダリ・タイルはユーザーの操作によってのみ作成できます。この画面のアプリケーションバーに[ピン止め]や[ピン止めを外す]ボタンを設置します。この機能をシステムグリフによってアプリケーションバーに設置する例は以下の通りです。

    <Page.BottomAppBar>
        <CommandBar>
            <AppBarButton x:Name="PinUnPinButton" Icon="{Binding PinUnPinButtonIcon}"
                Label="{Binding PinUnPinButtonLabel}" Click="PinUnPinButton_Click" />
            <CommandBar.SecondaryCommands>
          ...
            </CommandBar.SecondaryCommands>
        </CommandBar>
    </Page.BottomAppBar>

これがクリックされたときに実行する処理は

1.アイコンとラベルをPinからUnPinに変更する

2.スタート画面にPin止めする

3.Pin止めを外す場合は、「1.」「2.」の逆を行う

となります。「1.」はView Modelにバインディングされている値として実装します。またテキストはリソースから取得するようにしておきます。View Modelの初期処理では

1.セカンダリ・タイルを表すApp Singletonを使って、スタート画面にPin止めされているかどうか判別する

2.アイコンとラベルの状態をPinまたはUnPinに変更する

という処理で、以下のようになります。

    //Code behind
    public const string TileID = "MainPageTile";
    SecondaryTile _secondaryTile { get; set; }
    SecondaryTile secondaryTile
    {
        get
        {
            if (_secondaryTile == null)
            {
                //セカンダリ・タイルを生成
            }
            return _secondaryTile;
        }
    }
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = new MainPageVM();
            if (!SecondaryTile.Exists(TileID))
            {
                (DataContext as MainPageVM).SetPinUnPinButtonState(Symbol.Pin);
            }
            else
            {
                (DataContext as MainPageVM).SetPinUnPinButtonState(Symbol.UnPin);
            }
    }
    //View model (MainPageVM)
    public string PinUnPinButtonLabel { get; set; }
    public IconElement PinUnPinButtonIcon { get; set; }
    public void SetPinUnPinButtonState(Symbol state)
    {
        PinUnPinButtonIcon = state == Symbol.Pin ?
            new SymbolIcon(Symbol.Pin) : new SymbolIcon(Symbol.UnPin);
        PinUnPinButtonLabel
            = ResourceUtilities.GetResourceString(
                    Enum.GetName(typeof(Symbol), state) + "ButtonLabel");
        RaisePropertyChanged(string.Empty);
    }
    //ResourceUtilities
    public class ResourceUtilities
    {
        private static ResourceLoader resourceLoader
            = ResourceLoader.GetForCurrentView("Resources");
        public static string GetResourceString(string key)
        {
            return resourceLoader.GetString(key);
        }
    }

※IconElement、SymbolIconはWindows.UI.Xaml.Controls
※SecondaryTileはWindows.UI.StartScreen
※SymbolはWindows.UI.Xaml.Controls.Symbol
※ResourceLoaderはWindows.ApplicationModel.Resources

この例では、MainPageのTileIDが存在しているか?を確認しています。このように各画面(シーン)のIDを使ってセカンダリ・タイルを管理しますので、複数のコンテンツを提供するアーティストの情報画面のようなXAMLでピン止めを行う場合は、この例のようなXAML固有の名前(”MainPageTile”)ではなく、アーティストの名前などのコンテンツ名にします。

ボタンのタップ時のPin/UnPinの判別は、アプリケーションバーに表示しているアイコンをView Modelのプロパティで取得し、そのアイコンの種類によって「ピン止めする」処理を行うか、または「ピン止めを外す」処理を行うようにしています。セカンダリ・タイルのVisualElementsを設定することで、ボタンのタップ時にセカンダリ・タイルの候補を選べるフライアウトをボタンの上部に表示することができます。Code behindへのユースケースのシナリオ実装とView Modelへのビジネスモデルの実装を混同しないようにしてください。

    SecondaryTile secondaryTile
    {
        get
        {
            if (_secondaryTile == null)
            {
                Uri square150x150Logo = new Uri("ms-appx:///Assets/Logo.png");
                Uri wide310x150Logo = new Uri("ms-appx:///Assets/Wide310x150Logo.png");
                _secondaryTile = new SecondaryTile(
                    TileID, DateTime.Now.ToLocalTime().ToString(), TileID
                    , square150x150Logo, TileSize.Wide310x150);
                _secondaryTile.VisualElements.Square150x150Logo = square150x150Logo;
                _secondaryTile.VisualElements.Wide310x150Logo = wide310x150Logo;
                _secondaryTile.VisualElements.BackgroundColor = Colors.White;
                _secondaryTile.VisualElements.ForegroundText = ForegroundText.Dark;
                _secondaryTile.VisualElements.ShowNameOnSquare150x150Logo = true;
                _secondaryTile.VisualElements.ShowNameOnWide310x150Logo = true;
            }
            return _secondaryTile;
        }
    }
    private void PinUnPinButton_Click(object sender, RoutedEventArgs e)
    {
        SetPin(sender).GetAwaiter();
    }
    private async Task SetPin(object sender)
    {
        var symbol
            = ((DataContext as MainPageVM).PinUnPinButtonIcon as SymbolIcon).Symbol;
        if (symbol == Symbol.Pin)
        {
            bool isPinned = await secondaryTile.RequestCreateAsync();
            if (isPinned)
            {
                (this.DataContext as MainPageVM).SetPinUnPinButtonState(Symbol.Pin);
            }
        }
        else
        {
            bool unPinned = await secondaryTile.RequestDeleteAsync();
            if (unPinned)
            {
                (this.DataContext as MainPageVM).SetPinUnPinButtonState(Symbol.UnPin);
            }
        }
    }

ロゴとアプリケーション名を配置する際は、ロゴにアプリケーション名を入れるかどうかを計画してください。この例のようにロゴにアプリケーション名が入っている場合、MSDNのタイルとバッジのガイドラインに則って、ShowNameOnWide310x150Logoをtrueに設定したら、「ピン止めした日時を表示する」などの変更が必要です(または、falseに設定する)。

また、これらはすべてCode behindで定義されていることが重要です。特にユニバーサル・アプリでは、このようなプラットフォームの都合によるロジック(システム・ロジック)をCode behindに定義し、ユースケースのシナリオを完結させます。そのようにすることで、ビジネスを解決するロジックをSharedのView Modelに分離することが可能です。ユニバーサル・アプリでなくとも、MVVMデザイン・パターンにおいてはView Modelにプラットフォームのシステム・ロジックを混在させることで、MVCにおけるFat Controllerと同じような保守性の低下を招きます。

About takao

I'm Microsoft MVP since June 2010.