読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

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

Visual Studio上のXamarin.FormsでReactiveProperty v3.0を使う方法

Rx 3.0対応しているRP 3.0ですが、まだpreリリースです。何故なら、Xamarin.Androidで参照追加するとコンパイルエラーになるから…! ということで、とりあえず使い方を試行錯誤しながら書いていこうと思います。

まず、プロジェクトを作ります。作ったら以下のプロジェクトを消します。

  • XXX.Windows
  • XXX.WinPhone

Windowsのほうはサポートはしてるんだけど今更Xamarinで作らないよね?という感じです。WinPhoneのほうはReactiveProperty v3.0でサポート切る予定なのでそもそもあると使えません。

次に、PortableのプロジェクトのNuGetパッケージマネージャーを開いてXamarin.Formsを削除します。

そして、プロジェクトのプロパティを開いてライブラリのTarget .NET Platform Standardのリンクをクリックします。そうするとこんな感じになります。

f:id:okazuki:20160804204503p:plain

project.jsonが作られるので、frameworksのnetstandard1.1の下にimportsを追加します。

{
  "supports": {},
  "dependencies": {
    "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
    "NETStandard.Library": "1.6.0"
  },
  "frameworks": {
    "netstandard1.1": {
      "imports": "portable-uap+net45"
    }
  }
}

そしたら、ソリューションのNuGetパッケージマネージャーを開いて以下のパッケージを最新化します。

  • Microsoft.NETCore.UniversalWindowsPlatform (UWPのプロジェクトのやつ)
    • 5.2.2が執筆時点の最新です。
  • Xamarin.Forms
    • 先ほど削除したPortableのプロジェクトに追加するのとついでに最新にしましょう。

次にReactivePropertyの3.0-pre5を追加します。

この時点でビルドエラーが出るようになります。原因は不明ですがReactive Extensions 3.0を入れただけでも出るエラーなので謎です。 解決策は、Droidのプロジェクトから以下の参照を削除します。

  • System.Runtime.InteropServices.WindowsRuntime

動作確認

PortableのプロジェクトにMainPage.xamlを追加して以下のような感じでVMとViewを作ります。

using Reactive.Bindings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace App63
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            this.BindingContext = new MainPageViewModel();
        }
    }

    public class MainPageViewModel
    {
        public ReactiveProperty<string> Input { get; }
        public ReadOnlyReactiveProperty<string> Output { get; }

        public MainPageViewModel()
        {
            this.Input = new ReactiveProperty<string>("");
            this.Output = this.Input
                .Delay(TimeSpan.FromSeconds(1))
                .Select(x => x.ToUpper())
                .ToReadOnlyReactiveProperty();
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App63.MainPage">
  <StackLayout>
    <Entry Text="{Binding Input.Value, Mode=TwoWay}" />
    <Label Text="{Binding Output.Value}" />
  </StackLayout>
</ContentPage>

Appクラスを書き換えて表示されるページをMainPageに差し替えます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Xamarin.Forms;

namespace App63
{
    public class App : Application
    {
        public App()
        {
            // The root page of your application
            MainPage = new MainPage();
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

実行すると以下のような感じで動きます。

f:id:okazuki:20160804205819p:plain

f:id:okazuki:20160804210013p:plain