ぴーさんログ

だいたいXamarin.Formsのブログ

【Xamarin.Forms 2.1.0(プレビュー)】ControlTemplate

Xamarin.Forms 2.1.0 で ControlTemplate が追加される予定です。

Xamarin.Forms 2.1.0-pre2 Released - Xamarin Forums

ControlTemplate は次のクラスで使用可能です。

  • ContentPage
  • ContentView
  • TemplatedPage
  • TemplatedView

TemplatedPage、TemplatedView が追加され、それに伴いContentPageの基底クラスがTemplatedPageへ、 ContentViewの基底クラスがTemplatedViewへ変更されます。

サンプル

TemplatedViewを継承してユーザーコントロールを作成します。ここにはUI定義が一切書かれていないことに注目してください。

using System;
using Xamarin.Forms;
using System.Windows.Input;

namespace XFApp10
{
    public class LoginView : TemplatedView
    {
        public static readonly BindableProperty UserNameProperty = 
            BindableProperty.Create("UserName", typeof(string), typeof(TemplateSamplePage), null, BindingMode.TwoWay);

        public string UserName
        {
            get { return (string)GetValue(UserNameProperty); }
            set { SetValue(UserNameProperty, value); }
        }

        public static readonly BindableProperty PasswordProperty = 
            BindableProperty.Create("Password", typeof(string), typeof(TemplateSamplePage), null, BindingMode.TwoWay);

        public string Password
        {
            get { return (string)GetValue(PasswordProperty); }
            set { SetValue(PasswordProperty, value); }
        }

        public static readonly BindableProperty CommandProperty = 
            BindableProperty.Create("Command", typeof(ICommand), typeof(TemplateSamplePage), null);

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }
    }
}

LoginViewにセットするControlTemplateはApp.xamlで定義します。App.xamlを追加する方法は@omanukeさんのXamarin.FormsでApp.xamlを追加する方法 - omanuke-ekunamoの日記を参照で。

<?xml version="1.0" encoding="UTF-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XFApp10.App">
    <Application.Resources>
        <ResourceDictionary>
            <!-- LoginViewの見た目 -->
            <ControlTemplate x:Key="LoginViewTemplate">
                <StackLayout VerticalOptions="CenterAndExpand" Spacing="20" Padding="20" >
                    <Entry Text="{TemplateBinding UserName, Mode=TwoWay}" Placeholder="UserName" />
                    <Entry Text="{TemplateBinding Password, Mode=TwoWay}" Placeholder="Password" />
                    <Button Command="{TemplateBinding Command}" Text="Click Here To Log In" />
                </StackLayout>
            </ControlTemplate>
        </ResourceDictionary>
    </Application.Resources>
</Application>

LoginViewのプロパティとテンプレートの紐付けには TemplateBinding を使用します。これも新しい構文です、通常のBinding構文とは別なので注意。 ViewModelのプロパティとバインドしたい場合(ControlTemplatesでするべきではないと思いますが) {TemplateBinding BindingContext.Hoge} のようにBindingContextを経由することでアクセス可能です。

LoginViewを利用するXAMLコード。

<?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:XFApp10;assembly=XFApp10"
             x:Class="XFApp10.MyPage" >
    <ContentPage.Content>
        <local:LoginView ControlTemplate="{StaticResource LoginViewTemplate}"
                         UserName="{Binding UserName}"
                         Password="{Binding Password}"
                         Command="{Binding Command}" />
    </ContentPage.Content>
</ContentPage>

こちらでViewModelとバインドすればControlTemplateとViewModelが繋がります。

結果はこのようになります。

f:id:ticktack623:20160124233451p:plain

WPFとの比較

WPFではButtonなど既存コントロールの見た目をカスタムする際にControlTemplateがよく使用されますが、Xamarin.Formsの場合はControlTemplateに対応したクラスは最初に説明した4つしかありません。 なので、基本的にユーザーコントロールを作成する際に使用する物という認識で良いでしょう。 縦向き用、横向き用のレイアウトをControlTemplateで用意して切り変えるという使い方はアリかも。

Xamarin.FormsはMerged Dictionaryに対応していません。(バージョン2.1.0プレビュー時点) そのためコントロール毎にテンプレートを定義したResourceDictionaryファイルを用意する、といった使い方ができません。

参考

Xamarin.Forms 2.1.0-pre2 Released - Xamarin Forums

Control Templates - Xamarin.Forms Complete