ぴーさんログ

だいたいXamarin.Formsのブログ

【Xamarin.Forms】TypeConverterの使い方

この記事は「Xamarin Advent Calendar 2015 - Qiita」の9日目です。

TypeConverterはXAMLでプロパティの値を指定する際、文字列から実際の方への変換を手助けしてくれます。(Binding時に登場するIValueConverterとは別物) Xamarin AC 5日目の記事で紹介したXFXamlAnimationsでもEasingプロパティなどで使われています。

例えば、XAML内で Padding="0,20,0,0"TextColor="Red" と書くと、それぞれ ThicnessColor に変換されます。これはビルトインされたTypeConverterのおかげです。

ビルトインTypeConverterが対応していない方への変換は独自に設定する必要があります。この記事ではその方法を解説します。

余談ですが、enum型はTypeConverterを使わなくても変換してくれるようです。(メンバ名、数値から変換可能)

サンプル

モデルケースとして、Labelコントロールを継承してColorThemeという独自プロパティを備えたMyLabelコントロールを作成します。

public class MyLabel : Label
{
   #region ColorTheme BindableProperty
    public static readonly BindableProperty ColorThemeProperty =
        BindableProperty.Create<MyLabel, ColorTheme>(p => p.ColorTheme, default(ColorTheme),
         propertyChanged: (bindable, oldValue, newValue) =>
            ((MyLabel)bindable).ColorTheme = newValue);

    public ColorTheme ColorTheme
    {
        get { return (ColorTheme)GetValue(ColorThemeProperty); }
        set
        {
            SetValue(ColorThemeProperty, value);
            ChangeColor(value);
        } 
    }
   #endregion

    private void ChangeColor(ColorTheme theme)
    {
        if(theme == null)
            return;

        BackgroundColor = theme.BaseColor;
        TextColor = theme.AccentColor;
    }
}

public class ColorTheme
{
    public Color AccentColor
    {
        get;
        set;
    }

    public Color BaseColor
    {
        get;
        set;
    }

    public static ColorTheme Dark
    {
        get
        {
            return new ColorTheme
            {
                AccentColor = Color.White,
                BaseColor = Color.Gray,
            };
        }
    }

    public static ColorTheme Light
    {
        get
        {
            return new ColorTheme
            {
                AccentColor = Color.Black,
                BaseColor = Color.White,
            };
        }
    }
}

Viewです、ColorThemeは名前(Dark、Light)で指定したいのでとりあえず書いてみましょう。

<ContentPage.Content>
    <StackLayout VerticalOptions="Center">
        <local:MyLabel Text="Dark" ColorTheme="Dark" />
        <local:MyLabel Text="Light" ColorTheme="Light" />
    </StackLayout>
</ContentPage.Content>

このまま実行すると...

Xamarin.Forms.Xaml.XamlParseException Position 10:31. Cannot assign property "ColorTheme": type mismatch between "System.String" and "XFApp4.ColorTheme"

XAML解析時に「string型からColorTheme型へ変換できません」と怒られてしまいました。まぁ、そうなるな。

独自のTypeConverterを作る

ColorThemeのためのTypeConverterを用意しましょう。

public class ColorThemeTypeConverter : TypeConverter
{
   #region implemented abstract members of TypeConverter
    public override bool CanConvertFrom(Type sourceType)
    {
        return sourceType == typeof(string);
    }

    public override object ConvertFrom(System.Globalization.CultureInfo culture, object value)
    {
        if(value == null)
            return null;

        if("Dark".Equals(value))
        {
            return ColorTheme.Dark;
        }
        if("Light".Equals(value))
        {
            return ColorTheme.Light;
        }

        throw new InvalidOperationException(
            string.Format("Conversion failed: {0} into {1}", value, typeof(ColorTheme)));
    }
   #endregion
}

overrideすべきメソッドは2つ

  • bool CanConvertFrom(Type sourceType)
    • XAMLからの変換に使う場合、string型であるかどうかを確認すればOKです。
  • object ConvertFrom(System.Globalization.CultureInfo culture, object value)

次に、MyLabelに修正を加えましょう。ColorThemeプロパティにTypeConverterAttirbuteを付加してColorThemeTypeConverterが呼ばれるようにします。

public class MyLabel : Label
{
    // 省略

    // TypeConverterAttribureを付加
    [TypeConverter(typeof(ColorThemeTypeConverter))]
    public ColorTheme ColorTheme
    {
        get { return (ColorTheme)GetValue(ColorThemeProperty); }
        set
        {
            SetValue(ColorThemeProperty, value);
            ChangeColor(value);
        } 
    }

    // 省略
}

再度実行してみると...

f:id:ticktack623:20151129230156p:plain

無事、XAMLから指定したColorThemeが反映されました。やったね。