かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

MADOSMAも出たしWindows Phone 8.1のアプリを作ろうぞ #wpjp

MADOSMAも出ました。ついでにおでコンも開催されています。これを機にWindows Phone 8.1のアプリを作ろうと考えている人も多いのではないかと思います。そこで個人的にお勧めするPrism.StoreAppsとReactivePropertyの組み合わせのとっかかりを書いてみようと思います。

なぜおすすめするのか

MVVMパターンちっくにアプリを作るための土台が提供されているので最初から自分で色々用意しなくて済みます。PrismのWindows Phone 8.1版(ストアアプリ版)は、割とバランスのいいところに落ち着いていると思います。

ReactivePropertyをPrismに追加するとコードが冗長になりがちな部分を簡単に書けるようになるのでお勧めです。

Prism.StoreAppの導入

Windows Phone 8.1のプロジェクトは空のものから始めます。空のプロジェクトを作ったらPrism.StoreAppsをNuGetから参照に追加しましょう。

Appクラスの変更

Prism用のAppクラスの基本クラスを継承するように書き換えます。PrismのAppクラスを継承すると、新規作成で作られるなが~~~~いAppクラスとおさらばできます。これだけでも個人的に気に入ってます。

using Microsoft.Practices.Prism.Mvvm;
using System.Threading.Tasks;
using Windows.ApplicationModel.Activation;

namespace App16
{
    /// <summary>
    /// 既定の Application クラスに対してアプリケーション独自の動作を実装します。
    /// </summary>
    public sealed partial class App : MvvmAppBase
    {
        protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
        {
            this.NavigationService.Navigate("Main", args.Arguments);
            return Task.FromResult(default(object));
        }
    }
}

基本クラスの変更に伴ってApp.xamlも書き換えます。

<mvvm:MvvmAppBase
    x:Class="App16.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App16"
    xmlns:mvvm="using:Microsoft.Practices.Prism.Mvvm">

</mvvm:MvvmAppBase>

これで起動したらViews.MainPageへ遷移するようになります。

ページの作成

MainPageを作成します。デフォルトのMainPageは削除してViews名前空間を定義してそこにMainPageを作成します。

MainPageもPrismの基本クラスに置き換えます。VisualStateAwarePageです。C#は以下のような感じで。

using Microsoft.Practices.Prism.StoreApps;

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

    }
}

XAMLは以下のような感じになります。

<prism:VisualStateAwarePage
    x:Class="App16.Views.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App16.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="using:Microsoft.Practices.Prism.StoreApps"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>

    </Grid>
</prism:VisualStateAwarePage>

動作確認

これで空のテンプレートと同じ状態です。コード全体が非常にすっきりしてます。実行すると空のアプリが立ち上がります。

f:id:okazuki:20150620235413p:plain

ViewModelを紐づける

次にViewModelをMainPageに紐づけます。ViewModelはViewModels名前空間にページ名ViewModelという感じでつけます。MainPageのViewModelの場合はMainPageViewModelです。ReactivePropertyをここで使うといいでしょう。基本クラスはViewModelです。

ReactivePropertyをNuGetで追加して以下のような簡単なViewModelを作りました

using Microsoft.Practices.Prism.Mvvm;
using Reactive.Bindings;
using System.Collections.Generic;
using Windows.UI.Xaml.Navigation;

namespace App16.ViewModels
{
    public class MainPageViewModel : ViewModel
    {
        public ReactiveProperty<string> Message { get; private set; }

        public override void OnNavigatedTo(object navigationParameter, NavigationMode navigationMode, Dictionary<string, object> viewModelState)
        {
            // 画面遷移してきたときに呼ばれる
            base.OnNavigatedTo(navigationParameter, navigationMode, viewModelState);
            // RPの初期化
            this.Message = new ReactiveProperty<string>("Hello world");
        }

        public override void OnNavigatedFrom(Dictionary<string, object> viewModelState, bool suspending)
        {
            // 画面遷移する前に呼ばれる
            base.OnNavigatedFrom(viewModelState, suspending);

            // Rpの後始末
            this.Message.Dispose();
        }
    }
}

OnNavigatedToとOnNavigatedFromでそれぞれ初期化と後始末をします。このハンドリングがViewModelで出来るのはPrismのいいところだと個人的に思っています。

最後にMainPage.xamlでViewModelの紐づけ機能を有効にします。mvvm:ViewModelLocator.AutoWireViewModel="True"を追加します。

<prism:VisualStateAwarePage
    x:Class="App16.Views.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App16.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="using:Microsoft.Practices.Prism.StoreApps"
    xmlns:mvvm="using:Microsoft.Practices.Prism.Mvvm"
    mc:Ignorable="d"
    mvvm:ViewModelLocator.AutoWireViewModel="True"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <TextBlock Text="{Binding Message.Value}"
                   Style="{ThemeResource HeaderTextBlockStyle}" />
    </Grid>
</prism:VisualStateAwarePage>

実行するとHello worldと表示されます。

f:id:okazuki:20150621000437p:plain

戻るボタンへの対応

Windows Phone 8.1のアプリは通常戻るボタンのハンドリングを自前でしないといけないのですがPrismではMvvmAppBaseクラスで処理してくれてるので、戻るボタンが押されたら1ページ戻るだけでいい場合は何もする必要はありません。

もし、それで不都合がある場合はAppクラスでOnHardwareButtonsBackPressedをオーバーライドして処理することが出来ます。

さて、これで土台はできました。

中華フォント対策

土台ができたので日本のアプリには欠かせない中華フォント対策を入れます。これにはFrameのLanguageプロパティを適切に設定することでできます。

App.xaml.csのOnLanuchApplicationAsyncで定番のコードを入れましょう。

参考:http://blogs.msdn.com/b/shintak/archive/2014/08/15/10550264.aspx

PrismのMvvmAppBaseではWindow.Current.ContentにFrameを突っ込んでいるので、そのままキャストしてLanguageを設定すればOKです。

using Microsoft.Practices.Prism.Mvvm;
using System.Threading.Tasks;
using Windows.ApplicationModel.Activation;
using Windows.Globalization;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace App16
{
    /// <summary>
    /// 既定の Application クラスに対してアプリケーション独自の動作を実装します。
    /// </summary>
    public sealed partial class App : MvvmAppBase
    {
        protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
        {
            var rootFrame = (Frame)Window.Current.Content;
            rootFrame.Language = ApplicationLanguages.Languages[0];

            this.NavigationService.Navigate("Main", args.Arguments);
            return Task.FromResult(default(object));
        }
    }
}

後は、Prism.StoreAppsの使い方の勉強のみです。

リソース

勉強するためのリソースはたくさんあります?

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com

code.msdn.microsoft.com