かずきのBlog@hatena

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

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