滅入るんるん

何か書きます

Xamarin.AndroidにBindingとCode-Behindが追加されてたので試してみた

Xamarin.Android 9.0 - Xamarin

Xamarin.Androidのリリースノートを見ていたらいつのまにかにBindingとCode-Behindが追加されていたので試してみました。

xamarin-android/LayoutCodeBehind.md at master · xamarin/xamarin-android · GitHub

スペックなどはドキュメントとしてまとめられているようです。ざっくり言うとXAMLでもなくAndroidのDataBindingでもないBindingとCode-Behindになります。

サンプルコードはGithubに公開しています。

github.com

機能の有効化

デフォルトでは有効になっていないので有効化する必要があります。

csprojを編集することで有効化できます。

<PropertyGroup>
    <AndroidGenerateLayoutBindings>true</AndroidGenerateLayoutBindings>
</PropertyGroup>

しかし、私はcsprojの編集がめんどくさいので、axml単位での有効化をしました。

f:id:meilcli:20181108100754p:plain

axml単位で有効化するにはaxmlのプロパティを開き、ビルドアクションをAndroidBoundLayoutにします。

Binding

Bindingといっても今のところはFindViewByIdを省けるぐらいの機能しかないようです(?)

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

// 略

axmlのルート要素にxmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools"を記述するだけでBindingのクラスが自動生成されます。

namespace XamarinAndroidCodeBehindSample
{
    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true)]
    public class MainActivity : AppCompatActivity
    {
        public MainActivity() { }

        public MainActivity(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { }

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.ActivityMain);

            var binding = new Binding.ActivityMain(this);

            SetSupportActionBar(binding.Toolbar);

            binding.FloatingActionButton.Click += fabClicked;
        }

        private void fabClicked(object sender, EventArgs eventArgs)
        {
            StartActivity(new Intent(this, typeof(SubActivity)));
        }
    }
}

あとは自動生成されたBindingのクラスをホルダー感覚で参照するだけです。

自動生成されるコードはこんな感じになっています↓

XamarinAndroidCodeBehindSample/Binding.ActivityMain.g.cs at master · MeilCli/XamarinAndroidCodeBehindSample · GitHub

Code-Behind

Code-BehindはBindingを利用した機能で、Bindingのクラスを用意しなくてよくするような感じの機能です。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools"
    xamarin:classes="XamarinAndroidCodeBehindSample.SubActivity"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView 
        android:id="@+id/Message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

axmlでCode-Behind対象のクラスをxamarin:classes="XamarinAndroidCodeBehindSample.SubActivity"のように名前空間ごと指定してあげるとpartialクラスが自動生成されます。

namespace XamarinAndroidCodeBehindSample
{
    [Activity]
    public partial class SubActivity : AppCompatActivity
    {
        public SubActivity() { }

        public SubActivity(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { }

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            SetContentView(Resource.Layout.ActivitySub);

            Message.Text = "Hello World";
        }
    }
}

partialクラスが自動生成されるので、ユーザーが作成するActivityのコードもpartialにしてあげることで、ViewをFindViewByIdやBindingせずともアクセスできます。

XamarinAndroidCodeBehindSample/XamarinAndroidCodeBehindSample.SubActivity.ActivitySub.g.cs at master · MeilCli/XamarinAndroidCodeBehindSample · GitHub

生成されるコードはこちらなのですが、どうもActivity専用なコード生成されてるように見えますが、Fragmentなどにも使えるのかなどは未確認です(すいません)

自動生成直後は自動生成ファイルが反映されない?

AndroidBoundLayoutでBindingやCode-Behindをしてるせいなのかもしれませんが、自動生成してほしいaxmlを用意し、コードが自動生成されていることを確認してもVisualStudio側のC#エディターで参照が取れませんでした。
プロジェクトのリロードをすると反映されるようです。

f:id:meilcli:20181108102716p:plain

一番手っ取り早い方法はソリューションエクスプローラーのツールのぐるぐるアイコンでのリロードですかね。

なお、参照さえ取れればIdの変更などの自動再生成には瞬時に反映されるようです。

この機能使えるのか…?

個人的にはありよりのありです。

AndroidのDataBindingやXamlのようにデータまでのBindingはできないですが、MVVMなアーキテクチャーでReactivePropertyを使っているとFindViewByIdがつらいだけで、Bindingはコードで書いちゃいますので……