Xamarin.Forms ステッパー

Download Sampleサンプルのダウンロード

"値の範囲から数値を選ぶには、ステッパーを使います。"

Xamarin.FormsStepper は、マイナス記号とプラス記号の付いた 2 つのボタンで構成されます。 ユーザーはこれらのボタンを操作して、値の範囲から double 値を段階的に選択できます。

Stepper では、double 型の 4 つのプロパティが定義されています。

  • Increment は選択した値を変更する量で、既定値は 1 です。
  • Minimum は範囲の最小値で、既定値は 0 です。
  • Maximum は範囲の最大値で、既定値は 100 です。
  • Value はステッパーの値です。この値は Minimum から Maximum までの範囲で指定でき、既定値は 0 です。

これらのプロパティはすべて、BindableProperty オブジェクトによってサポートされます。 Value プロパティの既定のバインド モードは BindingMode.TwoWay で、Model-View-ViewModel (MVVM) アーキテクチャを使うアプリケーションのバインディング ソースとして適していることを意味します。

警告

内部的には、StepperMinimumMaximum より小さくなるようにします。 MinimumMaximum より小さくならないように MinimumMaximum が設定された場合、例外が発生します。 Minimum および Maximum プロパティの設定の詳細については、「注意事項」セクションを参照してください。

Stepper は、Value プロパティを MinimumMaximum の間になるように強制します(両端の値を含む)。 Minimum プロパティが Value プロパティより大きい値に設定されている場合、StepperValue プロパティを Minimum に設定します。 同様に、MaximumValue より小さい値に設定されている場合は、StepperValue プロパティを Maximum に設定します。

Stepper は、Stepper がユーザーによって操作されるか、アプリケーションで Value プロパティが直接設定されることで、Value が変化したときに発生する ValueChanged イベントを定義します。 前の段落で説明したように、Value プロパティが強制された場合にも ValueChanged イベントが発生します。

ValueChanged イベントに付随する ValueChangedEventArgs オブジェクトには、double 型の 2 つのプロパティ (OldValueNewValue) があります。 イベントが発生した時点では、NewValue の値は Stepper オブジェクトの Value プロパティと同じです。

基本的なステッパー コードとマークアップ

StepperDemos サンプルは、機能的には同じですが、異なる方法で実装された 3 つのページが含まれます。 最初のページでは C# コードのみを使い、2 番目のページではコード内のイベント ハンドラーで XAML を使い、3 番目のページでは XAML ファイル内のデータ バインディングを使ってイベント ハンドラーを回避できます。

コードでのステッパーの作成

StepperDemos サンプルの [基本的なステッパー コード] ページには、コード内に Stepper と 2 つの Label オブジェクトを作成する方法が示されています。

public class BasicStepperCodePage : ContentPage
{
    public BasicStepperCodePage()
    {
        Label rotationLabel = new Label
        {
            Text = "ROTATING TEXT",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        Label displayLabel = new Label
        {
            Text = "(uninitialized)",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        Stepper stepper = new Stepper
        {
            Maximum = 360,
            Increment = 30,
            HorizontalOptions = LayoutOptions.Center
        };
        stepper.ValueChanged += (sender, e) =>
        {
            rotationLabel.Rotation = stepper.Value;
            displayLabel.Text = string.Format("The Stepper value is {0}", e.NewValue);
        };

        Title = "Basic Stepper Code";
        Content = new StackLayout
        {
            Margin = new Thickness(20),
            Children = { rotationLabel, stepper, displayLabel }
        };
    }
}

Stepper は、Maximum プロパティが 360、Increment プロパティが 30 になるように初期化されます。 Stepper を操作すると、Increment プロパティの値に基づいて、選択した値が Minimum から Maximum まで段階的に変更されます。 StepperValueChanged ハンドラーは、stepper オブジェクトの Value プロパティを使って最初の LabelRotation プロパティを設定し、string.Format メソッドをイベント引数の NewValue プロパティと共に使って 2 番目の LabelText プロパティを設定します。 Stepper の現在の値を取得するこれらの 2 つの方法は、相互に置き換え可能です。

次のスクリーンショットは、[基本的なステッパー コード] ページを示しています。

Basic Stepper Code

2 番目の Label には、Stepper が操作されるまで "(初期化されていません)" というテキストが表示されます。これにより、最初の ValueChanged イベントが発生します。

XAML でのステッパーの作成

[基本的なステッパー XAML] ページは、基本的なステッパー コードと機能的には同じですが、主に XAML で実装されています。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="StepperDemo.BasicStepperXAMLPage"
             Title="Basic Stepper XAML">
    <StackLayout Margin="20">
        <Label x:Name="_rotatingLabel"
               Text="ROTATING TEXT"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
        <Stepper Maximum="360"
                 Increment="30"
                 HorizontalOptions="Center"
                 ValueChanged="OnStepperValueChanged" />
        <Label x:Name="_displayLabel"
               Text="(uninitialized)"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />        
    </StackLayout>
</ContentPage>

分離コード ファイルには、ValueChanged イベントのハンドラーが含まれます。

public partial class BasicStepperXAMLPage : ContentPage
{
    public BasicStepperXAMLPage()
    {
        InitializeComponent();
    }

    void OnStepperValueChanged(object sender, ValueChangedEventArgs e)
    {
        double value = e.NewValue;
        _rotatingLabel.Rotation = value;
        _displayLabel.Text = string.Format("The Stepper value is {0}", value);
    }
}

イベント ハンドラーは、sender 引数でイベントを発生させる Stepper を取得することもできます。 Value プロパティは現在値を含みます。

double value = ((Stepper)sender).Value;

XAML ファイル内で Stepper オブジェクトに x:Name 属性 ("stepper" など) を持つ名前が指定されている場合、イベント ハンドラーはそのオブジェクトを直接参照できます。

double value = stepper.Value;

ステッパーのデータ バインディング

[基本的なステッパー バインディング] ページでは、データ バインディングを使って Value イベント ハンドラーを除去する、ほぼ同等のアプリケーションを作成する方法を示します。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="StepperDemo.BasicStepperBindingsPage"
             Title="Basic Stepper Bindings">
    <StackLayout Margin="20">
        <Label Text="ROTATING TEXT"
               Rotation="{Binding Source={x:Reference _stepper}, Path=Value}"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
        <Stepper x:Name="_stepper"
                 Maximum="360"
                 Increment="30"
                 HorizontalOptions="Center" />
        <Label Text="{Binding Source={x:Reference _stepper}, Path=Value, StringFormat='The Stepper value is {0:F0}'}"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

最初の LabelRotation プロパティは StepperValue プロパティにバインドされ、2 番目の LabelText プロパティは StringFormat の仕様でバインドされています。 [基本的なステッパー バインディング] ページは、前の 2 つのページとは少し異なる形で機能します。ページが最初に表示されると、2 番目の Label に値を含むテキスト文字列が表示されます。 これは、データ バインディングを使う利点です。 データ バインディングなしでテキストを表示するには、LabelText プロパティを具体的に初期化するか、クラス コンストラクターからイベント ハンドラーを呼び出して ValueChanged イベントの発生をシミュレートする必要があります。

注意事項

Minimum プロパティの値は常に、Maximum プロパティの値より小さくする必要があります。 次のコード スニペットを使うと、Stepper で例外が発生します。

// Throws an exception!
Stepper stepper = new Stepper
{
    Minimum = 180,
    Maximum = 360
};

C# コンパイラは、これら 2 つのプロパティを順番に設定するコードを生成します。Minimum プロパティが 180 に設定されている場合、この値は Maximum の 既定値である 100 よりも大きくなります。 この場合、最初に Maximum プロパティを設定することで例外を回避できます。

Stepper stepper = new Stepper
{
    Maximum = 360,
    Minimum = 180
};

Maximum を 360 に設定しても、既定の Minimum 値の 0 より大きいため、問題ありません。 Minimum が設定されている場合、値は Maximum の値の 360 より小さくなります。

XAML でも同じ問題が存在します。 Maximum が常に Minimum より大きくなる順序でプロパティを設定します。

<Stepper Maximum="360"
         Minimum="180" ... />

MinimumMaximum の値を負の数に設定できますが、Minimum が常に Maximum より小さくなるような順序でのみ設定できます。

<Stepper Minimum="-360"
         Maximum="-180" ... />

Value プロパティは常に Minimum 値以上、Maximum 値以下です。 Value がその範囲外の値に設定された場合、値は強制的に範囲内に設定されますが、例外は発生しません。 たとえば、次のコードを使っても、例外は発生 "しません"。

Stepper stepper = new Stepper
{
    Value = 180
};

その代わりに、Value プロパティは Maximum の値が 100 に強制的に設定されます。

上記のコード スニペットを次に示します。

Stepper stepper = new Stepper
{
    Maximum = 360,
    Minimum = 180
};

Minimum を 180 に設定すると、Value も 180 に設定されます。

ValueChanged イベント ハンドラーが、Value プロパティが既定値 0 以外の値に強制された時点ですでにアタッチされていた場合、ValueChanged イベントが発生します。 XAML のスニペットを次に示します。

<Stepper ValueChanged="OnStepperValueChanged"
         Maximum="360"
         Minimum="180" />

Minimum を 180 に設定すると、Value も 180 に設定され、ValueChanged イベントが発生します。 これは、ページの残りの部分が作成される前に発生する可能性があり、ハンドラーは、まだ作成されていないページ上の他の要素を参照しようとする可能性があります。 ページ上の他の要素の null 値をチェックするコードを、ValueChanged ハンドラーに追加できます。 または、Stepper の値が初期化された後に ValueChanged イベント ハンドラーを設定することもできます。