かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ReactivePropertyでXAMLで.Valueのつけ忘れを教えてくれるReSharperプラグイン

ガチでありがたいことに、よく頂く要望に対するプラグインを作っていただけました。 残念ながら私は、R#先生を使ってないので試せないですがR#を使ってる方はぜひ試してみてください。

resharper-plugins.jetbrains.com

WPFでWindowが閉じられたときにViewModelの後始末メソッドを呼ぶ

そういう動きをするビヘイビアを作ればOKです。こんな感じで。

public class ViewModelCleanupBehavior : Behavior<Window>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.Closed += this.WindowClosed;
    }

    private void WindowClosed(object sender, EventArgs e)
    {
        (this.AssociatedObject.DataContext as IDisposable)?.Dispose();
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.Closed -= this.WindowClosed;
    }
}

使い方はこんな感じ。

<Window x:Class="CloseAndDisposeSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CloseAndDisposeSample"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <i:Interaction.Behaviors>
        <local:ViewModelCleanupBehavior />
    </i:Interaction.Behaviors>
    <Grid>
    </Grid>
</Window>

これでMainWindowViewModelがIDpsopsableを実装していれば、Windowが閉じられたときにDisposeメソッドが呼び出されます。

めでたしめでたし。

Xamrin.FormsでBLEのアドバタイズパケットを拾おう(要はビーコン)

ということで、Xamarin.FormsでBLEやってみようと思います。 スキャンして、近くのパケット拾って来るのがゴールくらいにしておきましょう。

BLEを使おうとすると、ネイティブのコードを書かないといけないのですが、幸いにもプラグインのリストにBluetooth LEの文字があります。

github.com

こいつですね。

github.com

www.nuget.org

ということで、Acr.BleパッケージをXamarin.Formsのプロジェクトに追加します。

このAcr.BleですがReactive Extensionsに依存しています。なんてこったいいじゃないですか。 対応Rxのバージョンは2.5なので、Xamarin.Formsでも安心して使えます(最新のRxは.NET Standardじゃないと入らない雰囲気)

Androidのプロジェクトで以下のパーミッションを追加します。

  • Bluetooth
  • BluetoothAdmin
  • AccessCoarseLocation

iOSはplistにこれを追加しておけばいいみたいです。

<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
</array>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>なんかメッセージ</string>

今回は手抜きで画面には出さずにDebug.WriteLineで表示させるだけにします。Pageに以下のようなコードを追加します。

using System;
using System.Diagnostics;
using System.Reactive.Linq;
using Acr.Ble;
using Xamarin.Forms;

namespace BleDemo
{
    public partial class BleDemoPage : ContentPage
    {
        public BleDemoPage()
        {
            InitializeComponent();

            BleAdapter.Current.Scan().Subscribe(result =>
            {
                Debug.WriteLine($"{result.Device.Name}:{result.Device.Uuid}:{result.Rssi}");
            });
        }
    }
}

これだけ。

これで実行すると以下のような結果が得られます。ちなみにBluetoothをOFFにしてるとScanメソッドがnullを返すみたいなので要注意。

SensorTag:00000000-0000-0000-0000-b4994c6430c4:-59
SensorTag:00000000-0000-0000-0000-b4994c6430c4:-60
SensorTag:00000000-0000-0000-0000-b4994c6430c4:-59
SensorTag:00000000-0000-0000-0000-b4994c6430c4:-58
SensorTag:00000000-0000-0000-0000-b4994c6430c4:-57
SensorTag:00000000-0000-0000-0000-b4994c6430c4:-58
SensorTag:00000000-0000-0000-0000-b4994c6430c4:-60
SensorTag:00000000-0000-0000-0000-b4994c6430c4:-61
SensorTag:00000000-0000-0000-0000-b4994c6430c4:-59

いい感じなのかな。

Xamarin.Formsでグラフを描こう(OxyPlot)

WPFでグラフを描けるライブラリを探してたらOxyPlotというのを見つけました。 見つけたと思ったら、こいつXamarin.Formsでもできるぞ!?ということで試して見ました。

NuGetの追加

以下のパッケージを追加します。

  • OxyPlot.Xamarin.Forms

初期化

以下のコードをXamarin.Forms.Forms.Init()の後に追加します。

PlotViewRenderer.Init();

画面構築

画面にPlotView部品を置きます。そしてModelプロパティをバインドします。

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:OxyApp"
    xmlns:oxy="clr-namespace:OxyPlot.Xamarin.Forms;assembly=OxyPlot.Xamarin.Forms"
    x:Class="OxyApp.OxyAppPage">
    <ContentPage.BindingContext>
        <local:OxyAppPageViewModel />
    </ContentPage.BindingContext>
    <oxy:PlotView Model="{Binding Model}" />
</ContentPage>

ViewModelの構築

ViewModelでグラフのモデルを構築します。

using System;
using OxyPlot;
using OxyPlot.Series;

namespace OxyApp
{
    public class OxyAppPageViewModel
    {
        public PlotModel Model { get; }

        public OxyAppPageViewModel()
        {
            this.Model = new PlotModel { Title = "Hello OxyPlot" };
            this.Model.Series.Add(new LineSeries
            {
                Points =
                {
                    new DataPoint(0, 10),
                    new DataPoint(1, 20),
                    new DataPoint(2, 15),
                    new DataPoint(3, 40),
                }
            });
        }
    }
}

Seriesにグラフの種類を表すSeries(今回の場合は折れ線グラフ)を追加していく形になります。DataPointをPointsに追加することで折れ線のデータを指定できます。

実行して動作確認

こんな感じで表示されます。

f:id:okazuki:20170116083107p:plain

感想

パッと触った感じ、なかなかいいんじゃないんでしょうか?? ライセンスもMITで扱いやすそう。

2016年に最も読まれた記事 TOP10 世間はDataTableと戦っている

2017年も始まってしばらく経ったので2016年の振り返りをして見たいと思います。 ということで、2016年に最も読まれた記事TOP10でも見て見たいと思います。

1位

blog.okazuki.jp

あっはい。

世間は、まだDataTable全盛期なんでしょうか。2009年に書いてる記事がNo1でした。

2位

blog.okazuki.jp

WPF!!

DataTableと比べて大分進化した気がします。2014年の記事ですね。 コレクションをデータバインドするのは、基本ですので是非抑えたいところ。

3位

blog.okazuki.jp

スマホでListView的な表記が流行ってるとはいえDataGridの人気も根強いみたいです。 そういえば、エクセルソフトさんでDataGridのセッションしたりしたなぁ

4位

blog.okazuki.jp

小ネタですね。 まぁヒープに無慈悲にインスタンス作りまくるので、あまり大きなサイズのデータではやりたくないところですが、知りたいことって多いですよね。

5位

blog.okazuki.jp

Excelを出力したいというネタも根強いのでしょう。 何故かNPOIの公式サイトから、Japanese Documentationとしてリンクが貼られてるこのブログ記事が5位にランクインしました。

6位

blog.okazuki.jp

これは何ででしょうね? スクロールが上手くいかないことが多いんでしょうか。

7位

blog.okazuki.jp

WPFで複雑なレイアウトを組むならこのGridですよね。 ということで、こいつが7位にランクインしました。

8位

blog.okazuki.jp

ComboBoxも地味に使うコントロール。WPFではテンプレート使えばかなりリッチな見た目できますよね。

9位

blog.okazuki.jp

多分、Windows Formsから来た人がつまづくであろうポイントの1つですね。 これは重要なので抑えておきましょう!!

10位

blog.okazuki.jp

WPFもルーティングイベントとかあって特殊な感じですよね。 この挙動を知ってるか知らないかで細かな動きの制御ができるかどうかとかが関わって来たりします。

まとめ

来年はDataTableの記事を超えるものを書きたいな。

Microsoft Azure ServiceFabricで複数のサービスで設定値を共通化したい

同じDBに繋ぐときとか一か所で設定を終えたいですよね。 ということで手順を備忘録的に残しておこうと思います。基本的には以下に書いてあることです。

Service Fabric での複数の環境の管理 | Microsoft Docs

Step1

サービスのプロジェクト/PackageRoot/COnfig/Settings.xmlに設定値を書く。これは設定を共通化したいプロジェクトが2個あったら2個ともにやります。

<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <!-- これは StateManager のレプリケーターにより使用されます。-->
  <Section Name="ReplicatorConfig">
    <Parameter Name="ReplicatorEndpoint" Value="ReplicatorEndpoint" />
  </Section>
  <!-- これは StateManager のレプリケーション トラフィックをセキュリティで保護するために使用されます。-->
  <Section Name="ReplicatorSecurityConfig" />

  <!-- ここで、カスタム構成セクションとパラメーターを追加します。-->
  <!--
  <Section Name="MyConfigSection">
    <Parameter Name="MyParameter" Value="Value1" />
  </Section>
  -->

  <!-- これを追加 -->
  <Section Name="UserDatabase">
    <Parameter Name="ConnectionString" Value="" />
  </Section>
</Settings>

Valueにはなんか書いてもかまいませんが、どうせ後で上書きされるので適当な値を突っ込んでおきましょう。

Step2

アプリケーションのプロジェクトのApplicationPackageRoot/ApplicationManifest.xmlのServiceManifestImportのConfigOverridesで先ほどの設定をオーバーライドする定義を追加します。これも2サービスあったら2つぶんやります。

Valueのところでかっこで囲っているのがパラメータ名になります。

<ServiceManifestImport>
  <ServiceManifestRef ServiceManifestName="Stateful1Pkg" ServiceManifestVersion="1.0.0" />
  <ConfigOverrides>
    <!-- こんな感じ -->
    <ConfigOverride Name="Config">
      <Settings>
        <Section Name="UserDatabase">
          <Parameter Name="ConnectionString" Value="[ConnectionString]" />
        </Section>
      </Settings>
    </ConfigOverride>
  </ConfigOverrides>
  <!-- ServicePackage から ServiceManifest をインポートします。ServiceManifestName と ServiceManifestVersion は、
     ServiceManifest.xml ファイルで定義されている ServiceManifest 要素の [Name] 属性と [Version] 属性と 
     一致しなければなりません。-->
</ServiceManifestImport>

そして、同じファイルのParametersタグに先ほど追加したかっこで囲ったパラメータ名のパラメータを追加します。

<Parameters>
  <Parameter Name="Stateful1_MinReplicaSetSize" DefaultValue="3" />
  <Parameter Name="Stateful1_PartitionCount" DefaultValue="1" />
  <Parameter Name="Stateful1_TargetReplicaSetSize" DefaultValue="3" />
  <Parameter Name="Stateless1_InstanceCount" DefaultValue="-1" />
  <!-- これを追加 -->
  <Parameter Name="ConnectionString" DefaultValue="DefaultConnectionString" />
</Parameters>

Step3

アプリケーションのプロジェクトのAplicationParametersフォルダの下にある構成単位のxmlファイルの中身を構成に合わせて設定します。 Local.Node1.xmlやLocal.Node5.xmlの場合はローカルDBの接続文字列とか、Cloud.xmlはSQL Databaseとかいった感じです。

こんな風になります。

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="fabric:/Application1" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="Stateful1_PartitionCount" Value="1" />
    <Parameter Name="Stateful1_MinReplicaSetSize" Value="1" />
    <Parameter Name="Stateful1_TargetReplicaSetSize" Value="1" />
    <Parameter Name="Stateless1_InstanceCount" Value="1" />
    <!-- これを追加 -->
    <Parameter Name="ConnectionString" Value="Node1ConnectionString" />
  </Parameters>
</Application>

Step4

定義は完了です。あとはコードからの参照方法ですが以下のようなコードで出来ます。

this.Context
  .CodePackageActivationContext
  .GetConfigurationPackageObject("Config")
  .Settings
  .Sections["UserDatabase"]
  .Parameters["ConnectionString"]
  .Value

長いですね。記述場所はStatefulやStatelesの中になります。Contextにアクセスできれば何処で書いてもOKです。

かずきのXamarin.Forms入門を更新しました

すっかりDataTemplateSelectorについて書くのを忘れてたのでSlideShareのPDFとKindleを差し替えました。 Kindleは反映までに1日くらいかかるのと、おそらく既に購入された方には変更は届けないとAmazonが判断すると思います…(よっぽどインパクトの大きな変更でない限り更新は配らないらしいです。しおりとかのデータが全部飛んじゃうらしいので)

申し訳ありませんが、既にKindle版を購入されてる方はSlideShareから更新内容をご確認ください。

www.slideshare.net

www.amazon.co.jp

MacBook Pro (Late 2016) 15インチをXamarin開発用に買ったので感想

使い方

私のMacBook Pro(Late 2016)の使い方は以下のような感じです。

Xamarin開発環境として

Xamarin StudioとVisual Studio for Macを入れてXamarinの開発環境とするために購入しました。 なので、この使い方がメインになります。

MacBook Proのメモリ16GBでSSD512GBモデルなので開発環境として申し分ない感じです。

Windowsとして

Windowsメインで使ってたのでParallelsを購入してWindows 10を入れました。 Parallelsって細かいところで色々気が利いてるので便利ですね。

個人的には、アプリ仮想化ができる点(Coherence)が好きです。 バックグラウンドでWindowsが動いていて、アプリをまるでMac上で動かしてるみたいなことができます。 私は、これでVisual Studio 2015をマック上で使っています。

管理者権限で起動したいとか言った特別な要件がない限りは割と満足できる使い勝手です。

入れたもの

インストールしたソフトウェアは以下のようなものになります。

  • Xamarin Studio
  • Visual Studio for Mac
  • Visual Studio Code
  • TweetDeck
  • Office
  • Slack
  • LINE
  • Kindle
  • Remote Desktop
  • SourceTree
  • Minecraft

ParallelsのWindowsには以下のようなものを入れています。

  • Visual Studio 2015 Update3
  • SourceTree
  • Office

本当にWindowsが使いたいときは、Surface Bookを持ってるのでそっちを使うので、Parallels上のWindowsは、あくまで開発環境といった感じです。

不満なところ

現時点使っていて不満に感じるところをつらつらとまず書いていこうと思います。

英語キーボードなので…

私は、1年前にSurface Bookをアメリカで買った時から英字配列のキーボードを使うようになりました。 そのためMacBook Proも英字配列で購入しました。 オプションとして英字配列を選ぶことのできるMacBook Pro素晴らしいと思いました。

まぁそんなわけで英字配列使ってると不便なことがあります。

WindowsはAlt + `が半角・全角の切り替えなのですがMacはCtrl + Spaceが切り替えに割り当たってます。 そのため、Parallels上のWindowsとMacで同じハードで同じデスクトップ上でアプリを使ってるのに半角・全角の切り替えが統一されてない!という状況になってます。 まぁ、これは誰が悪いわけでもないんですが不便ですね。

Minecraft

マウスホイールでのアイテムの切り替えがWindowsと逆なんですよ…。 マウスの設定でスクロールを逆にすると全体に効いてくるので変えるわけにもいかない。 まぁそんなところですね。

その他

まぁ郷に入れば郷に従えなので、他に不満点はないですね。MacっていいOSなんだなと思います。

便利なところ

ということで便利だと感じてるところを書いてみたいと思います。

仮想デスクトップ

アプリを全画面にして気持ちよく別デスクトップに割当たるという動きは気持ちいいです。

タッチバー

思ったほど悪くないです。

個人に依存するとは思うのですが私はF1〜F12は、もともと割と目を落として目視で押してたみたいなのでFnキーを押してから目視で選んで押すので割と間に合ってます。 まぁ押す機会自体少ないですしね。

Visual StudioやXamarin Studioでデバッグ実行するときくらいしか押してない感じ。

Safariを使ってると割とよくできていて、検索バーへのフォーカスの移動やタブ増やしたりとか、お気に入りへのアクセスとか簡単にできるのがいいです。 まぁショートカットの方が早いですが、検索バーへの移動ショートカットを未だに発見できていないのでタッチバー使ってます。 (タッチバーでできるから調べようという気力も起きない)

あと、音量の調整や画面輝度の調整がタッチバーでやれるのもなかなかいい感じです。 トラックパッドでバーをちまちまやるよりタッチでささっとやるのが気持ちいいですね。

文字変換

デフォルトの文字変換って勝手に変換してくれるんですよね。 これが最初は気持ち悪かったけど、慣れたらWindowsで変換忘れてしまうようになってしまいました。 これは、気持ちいいですね。

思ったよりない

便利なところはそれくらいでしょうか。

思ったこと

WindowsもMacもOSとして割と歴史あるものなので、それぞれ使いやすくなってて作法を知れば便利なようにできてるんだなと思いました。 仮想デスクトップについては、Macの方が古くからできているのでこなれてるなぁという印象です。

まぁMacのVMをWindows機の上に立てていいようなライセンスになったらMacBookとはさようならしそうだけど、そんな未来はないよね。 ということでXamarinやるならMacいるんだよね。 それが最大の不満点かも(不満点に書けばよかったか)

まぁそんなことで、久しぶりにプログラミングネタじゃない記事でした。

Prism.FormsでAutofacを使ってみよう

Xamarin Studioベースで話を進めます。(Visual Studioでもだいたい同じになると思うけど)

まずForms Appを新規作成してPCLで作ります。

NuGetから以下のパッケージを追加します。

  • Prism.Autofac.Forms

Views名前空間を作って、そこにMainPage.xamlを作成します。XAMLはいつも通り、ViewModelLocatorを設定しておきます。 今回は、ViewModelにMessageプロパティがあることを前提に作って見ました。あとでViewModelも作ります。

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:mvvm="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
    mvvm:ViewModelLocator.AutowireViewModel="true"
    x:Class="PrismAutofac.Views.MainPage">
    <Label Text="{Binding Message}"
        HorizontalOptions="Center"
        VerticalOptions="Center" />
</ContentPage>

ViewModels名前空間を作って以下のようなViewModelも作ります。ここら辺は普通のPrismの世界ですね。

using System;
using Prism.Mvvm;

namespace PrismAutofac.ViewModels
{
    public class MainPageViewModel : BindableBase
    {
        public string Message => "Hello world powered by Prism.Autofac.Forms";
    }
}

そして、App.xaml.csを以下の内容に書き換えます。

AutofacはUnityと違って登録されてないクラスのインスタンスは作ってくれないので、Unityでは必要のなかったViewModelの登録を行っています。と言ってもAssemblyをスキャンしてViewModelを一括登録する感じなので楽チンですけどね。

using Prism.Autofac;
using Prism.Autofac.Forms;
using Autofac;
using Xamarin.Forms;
using PrismAutofac.Views;
using PrismAutofac.ViewModels;
using System.Reflection;

namespace PrismAutofac
{
    public partial class App : PrismApplication
    {
        protected override void OnInitialized()
        {
            InitializeComponent();

            this.NavigationService.NavigateAsync("MainPage");
        }

        protected override void RegisterTypes()
        {
            // ViewModelの登録
            var containerUpdater = new ContainerBuilder();
            containerUpdater
                .RegisterAssemblyTypes(typeof(App).GetTypeInfo().Assembly)
                .Where(x => x.IsInNamespace("PrismAutofac.ViewModels"))
                .Where(x => x.Name.EndsWith("ViewModel"))
                .AsSelf();
            containerUpdater.Update(this.Container);

            // Viewの登録
            this.Container.RegisterTypeForNavigation<MainPage>();
        }
    }
}

追記 2017/01/09

nuitsさんから指摘いただきました。

ということなので、こういう感じでOKな上に、将来的にはこの手間もいらなくなるとか。

using Prism.Autofac;
using Prism.Autofac.Forms;
using Autofac;
using Xamarin.Forms;
using PrismAutofac.Views;
using PrismAutofac.ViewModels;
using System.Reflection;

namespace PrismAutofac
{
    public partial class App : PrismApplication
    {
        protected override void OnInitialized()
        {
            InitializeComponent();

            this.NavigationService.NavigateAsync("MainPage");
        }

        protected override void RegisterTypes()
        {
            // Viewの登録
            this.Container.RegisterTypeForNavigation<MainPage>();

            var containerUpdater = new ContainerBuilder();
            // 登録されてない型もコンテナで作成する
            containerUpdater.RegisterSource(new Autofac.Features.ResolveAnything.AnyConcreteTypeNotAlreadyRegisteredSource());

            // Serviceの登録
            containerUpdater
                .RegisterAssemblyTypes(typeof(App).GetTypeInfo().Assembly)
                .Where(x => x.IsInNamespace("PrismAutofac.Services"))
                .Where(x => x.Name.EndsWith("Service"))
                .AsImplementedInterfaces()
                .SingleInstance();
            containerUpdater.Update(this.Container);
        }
    }
}

個人的に納得いかない挙動が1つあって、Viewの登録を最後に持ってくるとアプリが死ぬようになることですかね。

追記ここまで

あとは、PrismApplicationを継承するようにしてるのでApp.xamlの内容もそれに合わせて書き換えます。

<?xml version="1.0" encoding="utf-8"?>
<prism:PrismApplication xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:prism="clr-namespace:Prism.Autofac;assembly=Prism.Autofac.Forms"
    x:Class="PrismAutofac.App">
    <Application.Resources>
        <!-- Application resource dictionary -->
    </Application.Resources>
</prism:PrismApplication>

実行すると、以下のようにいい感じに表示されます。

f:id:okazuki:20170108220649p:plain

サービスとかの登録もしてみよう

サービスの登録もついでにして見ましょう。以下のようなIMessageServiceというインターフェースを定義します。

using System;
namespace PrismAutofac.Services
{
    public interface IMessageService
    {
        string GetMessage();
    }
}

実装も適当にやります。

using System;
namespace PrismAutofac.Services
{
    public class MessageService : IMessageService
    {
        public string GetMessage() => "Xamarin.Forms and Prism.Autofac.Forms.";
    }
}

App.xaml.csでサービスの登録をシングルトンで行います。これもサービスが増えて来たときのことを考えてAssemblyをスキャンしてやってしまいましょう。

using Prism.Autofac;
using Prism.Autofac.Forms;
using Autofac;
using Xamarin.Forms;
using PrismAutofac.Views;
using PrismAutofac.ViewModels;
using System.Reflection;

namespace PrismAutofac
{
    public partial class App : PrismApplication
    {
        protected override void OnInitialized()
        {
            InitializeComponent();

            this.NavigationService.NavigateAsync("MainPage");
        }

        protected override void RegisterTypes()
        {
            // ViewModelの登録
            var containerUpdater = new ContainerBuilder();
            containerUpdater
                .RegisterAssemblyTypes(typeof(App).GetTypeInfo().Assembly)
                .Where(x => x.IsInNamespace("PrismAutofac.ViewModels"))
                .Where(x => x.Name.EndsWith("ViewModel"))
                .AsSelf();

            // Serviceの登録
            containerUpdater
                .RegisterAssemblyTypes(typeof(App).GetTypeInfo().Assembly)
                .Where(x => x.IsInNamespace("PrismAutofac.Services"))
                .Where(x => x.Name.EndsWith("Service"))
                .AsImplementedInterfaces()
                .SingleInstance();
            containerUpdater.Update(this.Container);

            // Viewの登録
            this.Container.RegisterTypeForNavigation<MainPage>();
        }
    }
}

MainPageViewModelを、IMessageServiceを使うように書き換えます。

using System;
using Prism.Mvvm;
using PrismAutofac.Services;

namespace PrismAutofac.ViewModels
{
    public class MainPageViewModel : BindableBase
    {
        private IMessageService MessageService { get; }

        public MainPageViewModel(IMessageService messageService)
        {
            this.MessageService = messageService;
        }

        public string Message => this.MessageService.GetMessage();
    }
}

実行すると、ちゃんとViewModelにMessageServiceがインジェクションされていることが確認できます。

f:id:okazuki:20170108221600p:plain

まとめ

Unityがいなくなっても平気ではありそうだなぁと思った今日この頃でした。(Unityには頑張って欲しい)