Windowsストアアプリにおける グリッドアプリケーションについて(7)

Windowsストアアプリにおける グリッドアプリケーションについて(7)

  • Comments 0

少し時間があきましたが、今回はグリッドアプリケーションを使った場合にどのようにカスタマイズするかということを説明します。最初に、開発体験テンプレートをご存じな方も多いことと思います。このテンプレート集のNewReaderのReadme.txtにカスタマイズのポイントが記載されているので、その中から抜粋したものを以下に示します。

  • (0) アプリの名前
  • (2) ブランディング
  • (3) プライバシーポリシー
  • (4) package.appxmanifest

最初にブランディングを説明します。ブランディングに関係する事項として、以下のようなことを考慮する必要があります。

  • バックグラウンド
    背景色や画像など
  • アイコン デザイン
    ロゴ(150x150)、ワイドロゴ(310x150)、小さいロゴ(30x30)、バッジロゴ(24x24)、スプラッシュスクリーン(620x300)、ストアロゴ(50x50)

特にブランディングは重要で、作成したアプリが容易に識別できるようにするためにも必須となります。また、アプリ内の各種のページ設計などを含めて統一感を持ってデザインすることが重要となり、これらの統一がアプリの印象を利用者に認識してもらうのに役立ちます。
このブランディングを考える上で、最初に取り組むのが背景色の変更だと思います。Windows ストア アプリのテンプレートでは、テーマという機能が含まれておりデフォルトのテーマは「Dark」となっています。これをSDKサンプルのように白を基調としたテーマにするには、App.xamlに「RequestedTheme」属性を記述します。

<Application
	・・・・・
	RequestedTheme = "Light"
	・・・・・   >

 
アプリの名前を変更するのも忘れないようにしましょう。アプリの名前は、App.xamlに「AppName」というキーを持つリソースとして定義されています。

プライバシーポリシーは、ネットワーク通信を行うアプリでは必須となります。Windows 8 アプリの認定の要件 (Windows)の要件4.1.1に「ユーザーの IP アドレスなどの個人情報をアプリで収集または送信する場合は、」とあり、収集するかしないは別として通信を行う場合は通信インフラストラクチャーがIPアドレスを送信します。この理由から、プライバシーポリシーを用意することが必須となります。特に、Visual Studioで作成した新規プロジェクトではデフォルトで「インターネット」が有効になっているので、注意しましょう。用意するプライバシーポリシーは、以下の2ヶ所への明示が必須となります。

  • アプリ内でプライバシーポリシーを表示できるようにする。
    アプリで表示するページでも良いですし、Webサイトへのリンクでも構いません。
  • ストアのアプリ紹介ページからプライバシーポリシーを表示できるようにする。
    プライバシーポリシーを掲示しているWebサイトのリンクを用意する必要があります。

Package.appmanifestは、特に以下の点を正しく設定します。

  • アプリケーション UI タブ
    表示名:必ずデフォルトの名前から変更します。アプリケーションの名前で、タイルなどに表示されます。長い場合は、短い名前も適切に設定します。
    説明
    各種ロゴと背景色。特にスプラッシュスクリーンの背景色は、アプリ全体の背景色と統一感を持って設定します。
  • パッケージ化 タブ
    パッケージ表示名:必ずデフォルトの名前から変更します。
    パッケージ名:変更しても良いでしょうし、デフォルトのGUIDにしておいても構いません。

パッケージ名やパッケージ表示名は、意図的にデフォルトの値にしておくこともあります。これは、セキュリティ上の理由です。Windows ストアアプリは、インストール自体がパッケージ名単位で行われます。逆を言えば、パッケージ名が理解しやすいと、カジュアルハックがし易いとも言えます。カジュアルハックと言っても、パッケージのローカルストア(ユーザー プロファイルの中にあります)をWindows エクスプローラーなどで覗いたりという意味です。パッケージ名を変更することは、一見しただけでアプリとの関連付けを連想させないためだけに、アプリと関係の無いパッケージ名やパッケージ表示名にしておくという程度の効果しかありません。この理由は、タスクマネージャーなどを使うことで、パッケージ名を利用者が知ることができるからです。

ここまで説明してきたのは、NewReaderテンプレートのReadme.txtに基づいています。新規のグリッドアプリケーションを自分で作成した場合は、データソースの変更が最初に行うステップとなります。以下に記載するのは、必ずではありませんが、このような考え方でNewsReaderはデータソースをカスタマイズしたと理解して頂ければ結構です。

  • Sampleで始まる名前をNewsにリネーム
  • NewsDataComon、NewsDataItemクラスへプロパティを追加
  • NewsDataGroupクラスへ、TopHighlitedItemsプロパティとNumberOfToken、ArticleCountプロパティを追加
    グリッドアプリケーションのHubページは、TopItemsプロパティをデータバインドしています。TopItemsとは、Itemsプロパティのコレクションに対する操作に連動して最初の12件を保持するコレクションです。
    NewsDataGroupでは、NumberOfToken(デフォルト4)を設定することで、設定した件数のNewsDataItemを返すTopHighlitedItemsプロパティを用意しています。このプロパティが、Hubページにデータバインドしています。
    セマンティックズームのズームアウトビューにデータバインドするために、件数を返すArticleCountプロパティを用意しています。
  • NewsDataSourceクラスへ以下を追加
    GetGroupメソッドとGetItemsメソッドのバグへの対処( == 1 を >= 1)。
    IsNetworkAvailable(オフライン判定)、IsInitialized(データの読み込み済みかどうか)プロパティを追加。
    コンストラクターで、DesignMode.DesignModeEnabledの場合にサンプルデータの作成。
    LoadRemoteDataAsyncメソッドを追加して、このメソッドで実際のデータを読み込んでいます。
    TwitterやRSSフィードや、ローカルへの保存や読み込みなどを行うメソッドを追加。

簡単に言えば、自分が作成するアプリが必要とするデータに応じてデータモデルを変更するということです。また、ズームアウトビューに対応させるために、必要なプロパティの実装を行ったり、オフラインサポートに応じて必要な機能を実装したりする必要があるということです。もちろん、オフラインサポートが必須というわけではありません。が、アプリを使用するユーザーにとってモバイルシーンでは必須とも言えるでしょう。

データソースを変更すれば、そのデータの表示方法も変更させる必要があります。具体的には、データテンプレートを自分のデータ用にカスタマイズする作業となります。この目的で、NewsReaderテンプレートは以下のようにApp.xamlでデータテンプレートを定義しています。

  • DefaultGridItemTemplate
    GroupedItemPageのGridViewのItemTemplateです。グリッドアプリケーションのデフォルトは、Standard250x250ItemTemplateになっています。
  • ItemGridTemplate
    GrpupDetailPageのGridViewのItemTemplateです。グリッドアプリケーションのデフォルトは、Standard500x130ItemTemplateになっています。
  • ZoomedOutItem
    NewsReaderテンプレートのセマンティックズーム サポートで使用しているズームアウトビュー用のデータテンプレートです。

NewsReaderテンプレートでは、アプリバーなどを導入しており、そのために必要となるスタイルをApp.xamlにリソースとして定義しています。これ以外に、行うカスタマイズとしては、次に説明するようなものがあります。

設定コントラクト

Visual Sudioではテンプレートの用意がありませんので、NewsReaderテンプレートなどのApp.xaml.csから必要なコードを引用してください。特に、プライバシーポリシーの明示を行うには必須となる作業です。

検索コントラクトや共有ターゲットコントラクト

Visual Studioを使ってプロジェクトへ[追加]-[新しい項目]で表示されるウィザードを使って、検索コントラクト、あるいは共有ターゲットコントラクトを追加して雛形を作成します。追加した後に、以下の作業を行います。

  • 追加されたページが、LayoutAwarePageを継承していない場合は継承するように変更します。
  • ロジックを作成します。ロジックの参考例としては、開発体験テンプレートを参照してください。
  • 検索コントラクトや共有ターゲットコントラクトを追加すると、ウィザードは以下の作業を行っています。
    App.xaml.csにコントラクト用のアクティベーション コードを追加。
    該当ページ.xamlを追加。

15秒以内にアクティブ化を完了する

Windows ストアアプリでは、タイルをタップしてから起動が完了するまでに15秒を超えるとシステムがアプリを強制終了する仕組みを備えています。たとえばNewsReaderテンプレートなどは、BlogやTwitterをネットワークを使って読み込んでデータソースを作成しますから、容易に15秒という時間を超えてしまいます。仮に、15秒を超えていればシステムに強制終了させられるため、アプリが起動することはなくなってしまいます。この症状を避けるためにNewsReaderテンプレートが行っている方法は、以下のようなものです。

  • LoadStateメソッドを非同期とする

この対策を行っても複数のフィードを行うとビューが表示されるまでに、時間がかかることになってしまいます。この理由から、NewsReaderテンプレートでは、1)1画面に収まるデータの取得、2)残りのデータを取得の2段階に分類しており、後者を非同期に処理しています。つまり、ビューが表示された後も、データの読み込みを続けるので徐々にデータが増えていくという動作を行うことで、ユーザーがビューを操作できるようになる時間の短縮を行っています。
このような手法には、画一的なアプローチはなく、取り扱うアプリのコンセプトやデータによって最適と思われる方法を使っていく必要があります。そのためには、作成されたアプリのボトルネックが何処に存在するかを調査して、その結果をもとに解決策を考えていきます。ちなみに要件3.8では、「5秒以内に起動すること」とあり、起動時にかけられる制限は厳しくなっています。つまり、データの初期化を同期的に行うのではなく、非同期処理を適切に組み合わせる必要があるということになります。

5秒以内に一時停止を完了する

Windows ストアアプリでは、アプリがバックグラウンドに移行するとシステム側がシステムリソースとの関係で一時停止させたり、強制終了させたりする場合があります。この時の状態遷移は、「一時停止」-[復帰]、[一時停止]-[強制終了]の2種類となります。一時停止に伴い、Suspendイベントがアプリに通知されるため、Suspendイベントの処理は「5秒以内に完了」する必要があります。仮に、5秒を超えるとシステムがアプリを強制終了させます。
一般的に一時停止イベントで行う処理は、以下のようなものです。

  • アプリのセッションデータを保存します。
    セッションデータとは、動作している間の一時的なデータであり、強制終了後の起動で元の状態に戻すために必要とするデータです。

この動作は、強制終了された後にアプリを起動した時に、強制終了させられた状態にアプリを復帰させる場合は実装する必要があります。既に説明したようにグリッドアプリケーションは、SuspensionManagerによってFramのナビゲーション履歴を保存するようになっています。従って、この機能を有効にしている限りは、セッションデータの保存と復帰は必須となります。問題は、セッションデータの保存と復帰の実装コードを何処に記述するかという点になります。

  • App.xaml.cs
    SusupensionManagerが、保存や復帰を行っているので統一性が取れて簡単です。が、扱うデータが大きい場合は、アクティブ化や一時停止の時間制限が問題にならないかと検討しましょう。
  • LoadStateメソッド
    NewsReaderテンプレートで採用した方法です。LoadStateを非同期メソッドにすることで、アクティブ化の時間制限を回避することができます。
    問題になるのは、どのタイミングで保存するかということです。

NewsReaderテンプレートでは、RSSなどのフィードの読み込みが完了した時にデータを保存するようにしています。この手法の根底にある考え方は、データモデルに変化があったタイミングで保存するというものです。この当たりの考え方も統一的なものはありませんので、作成されるアプリに応じて考えるものとなります。ちなみに要件3.8では、「2秒以内に中断を実行できること」とあり、かなり厳しくなっています。要件3.8が厳しくなっている理由は、非力なPCのサポートを前提に置いていると考えると良いでしょう。つまり、サポートCPUを限定すれば問題がなくなることも少なくないということになります。

ユーザーコントロールを作成するには

C#やVB、そしてC++でxamlを使って開発される場合は、ユーザーコントロールを作成したい場合もあることでしょう。ユーザーコントロールを作成する場合に、注意するのはデータバインドとVisualStateManagerによるビューをどのように切り替えるかという点になります。最初に、簡単なXAMLの定義を以下に示します。

<UserControl
    x:Class="App4.MyUserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App4"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="self"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">
    <Grid>
        <TextBox x:Name="txtInput" 
                 Width="{Binding Width, ElementName=self}"
                 Height="{Binding Height, ElementName=self}"
                 Text="{Binding Data, ElementName=self, Mode=TwoWay}"
                 />
    </Grid>
</UserControl>

 
ユーザーコントロールにTextBoxを置いただけのシンプルなxamlです。このxaml定義で、注意する必要があるのはUserControlのName属性とデータバインドの記述方法の2種類になります。

  • x:Name="self"
    UserControlにName属性を付与することは、次のデータバインドを要素内で完結させるために必須となります。名前は、理解しやすいように「self」としていますが、何でも構いません。
  • {Binding Data, ElementName=self, Mode=TwoWay} 
    最初の「Data」が要素名を表し、ElementNamaeが自分自身(作成しているユーザーコントロール)を指します。つまり、MyUserControl1.Dataプロパティを指していることになります。最後のModeがバインディングを双方向にしています。これは、TextBoxコントロールが入力を受け取る性格から設定しています。実際には、一方向でも問題はありません。要は、作成されるコントロールが双方向バインディングをサポートするかどうかで判断すれば良いということです。

次にユーザーコントロールに実装したコードを以下に示します。

// 依存プロパティの定義
public static DependencyProperty DataProperty =
       DependencyProperty.Register("Data",
         typeof(string), typeof(MyUserControl1),
         new PropertyMetadata(string.Empty, 
             new PropertyChangedCallback(MyUserControl1.OnDataChanged)));
// プロパティ変更のイベントハンドラー
private static void OnDataChanged(DependencyObject obj,
                            DependencyPropertyChangedEventArgs args)
{
    var myUserControl1 = (MyUserControl1)obj;
    myUserControl1.Data = (string)args.NewValue;
}
// 依存プロパティの実装
public string Data
{
    get
    {
        return this.GetValue(DataProperty) as string;
    }
    set
    {
        this.SetValue(DataProperty, value);
    }
}

   
コードを見れば理解できると思いますが、DependencyPropertyを定義する必要があります。この定義で注意すべきことは、PropertyMetadataの定義だと思います。双方向バインディングを行う場合は、PropertyMetadataの第2引数にPropertyChangedCallbackを指定します。一方向バインディングであれば、第2引数はnullで構いません。この点が、データバインド可能なプロパティを実装する上での注意点となります。次に、このコントロールを使用するXAMLの定義を以下に示します。

<local:MyUserControl1 x:Name="myControl1" Data="{Binding Data, Mode=TwoWay}" 
                      Margin="95,127,0,0" Width="430" Height="65"/>


後は、myControl1のDataContextにデータソースを設定することで、データバインドは完了となります。 上記で説明したことは、データバインド可能なユーザーコントロールを作成する上での最低限の知識となります。次に、VisualStateManagerを定義する上で注意する点を以下に示します。

  • ユーザーコントロール側のXAMLにVisualStateManagerを記述する。
    記述することで、Visual Studioのデバイスタブでビューを切り替えてデザインの確認を行うことができます。
  • 利用する側のXAMLで、LoadedとUnloadedにLayoutAwarePageのイベントハンドラーを設定する。
    グリッドアプリケーションのVisualStateManagerを使ったビューの切り替えで説明したように、LayoutAwarePageのStartLayoutUpdatesメソッドとStopLayoutUpdateメソッドを使うことでビューの切り替えが行われるようになるためです。

上記に説明したのは、基本的な方法となります。もちろん、LayoutAwarePageを使用しない場合ではビューの切り替えを自分で考える必要があります。たとえば、ウィンドウのSize変更イベントなどを使って、ユーザーコントロール内で適切なビューに合わせて配置を変更するなどの方法も考えられます。この方法の欠点は、デザイン時のビューの確認をどうするかということです。デザイン時に確認したいとなれば、XAML内にVisualStateManagerを定義せざるを得ません。

Leave a Comment
  • Please add 8 and 5 and type the answer here:
  • Post