Xamarin.Forms Stepper

Use un Stepper para seleccionar un valor numérico de un intervalo de valores.

Xamarin.FormsStepper consta de dos botones etiquetados con signos menos y más. El usuario puede manipular estos botones para seleccionar incrementalmente un valor double de un rango de valores.

Stepper define dos propiedades de tipo double:

  • Increment es la cantidad por la que se cambia el valor seleccionado, con un valor predeterminado de 1.
  • Minimum es el valor mínimo del rango, con un valor predeterminado de 0.
  • Maximum es el valor máximo del rango, con un valor predeterminado de 100.
  • Value es el valor del control de incremento, que puede oscilar entre Minimum y Maximum, y tiene un valor predeterminado de 0.

Todos estos objetos están respaldados por objetos BindableProperty. La propiedad Value tiene un modo de enlace predeterminado de BindingMode.TwoWay, lo que significa que es adecuado como origen de enlace en una aplicación que usa la arquitectura Model-View-ViewModel (MVVM).

Advertencia

Internamente, Stepper garantiza que Maximum sea menor que Minimum. Si Minimum o Maximum se establecen alguna vez para que Maximum no sea menor que Minimum, se genera una excepción. Para obtener más información sobre cómo establecer las propiedades Minimum y Maximum, consulte la sección Precauciones.

El Stepper reprime la propiedad Value para que esté entre Minimum y Maximum, ambos inclusive. Si la propiedad Minimum se establece en un valor mayor que la propiedad Value, Stepper establece la propiedad Value en Minimum. Del mismo modo, si Maximum se establece en un valor menor que Value, Stepper establece la propiedad Value en Maximum.

Stepper define un evento ValueChanged que se desencadena cuando cambia Value, ya sea mediante la manipulación del usuario Stepper o cuando la aplicación establece la propiedad Value directamente. También se desencadena un evento ValueChanged cuando la propiedad Value se coacciona como se describe en el párrafo anterior.

El objeto ValueChangedEventArgs que acompaña al evento ValueChanged tiene dos propiedades, de tipo double: OldValue y NewValue. En el momento en que se desencadena el evento, el valor NewValue es el mismo que la propiedad Value del objetoStepper.

Código y marcado básicos de Stepper

El ejemplo contiene tres páginas que son funcionalmente idénticas, pero se implementan de maneras diferentes. La primera página usa solo código de C#, el segundo usa XAML con un controlador de eventos en el código y, en tercer lugar, puede evitar el controlador de eventos mediante el enlace de datos en el archivo XAML.

Creación de un Stepper en el código

En la página Código de Stepper básico en el ejemplo se muestra cómo crear un objeto Stepper y dos objetos en el código 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 se inicializa para tener una propiedad Maximum de 360, y una propiedad Increment de 30. Si se manipula Stepper, el valor seleccionado cambia incrementalmente entre Minimum y Maximum en función del valor de la propiedad Increment. El controlador ValueChanged del Stepper usa la propiedad Value del objeto stepper para establecer la propiedad Rotation del primero Label y usa el método string.Format con la propiedad NewValue de los argumentos del evento para establecer la propiedad Text del segundo Label. Estos dos enfoques para obtener el valor actual de Stepper son intercambiables.

En las capturas de pantalla siguientes se muestra la página Código de Stepper básico:

Código y marcado básicos

El segundo Label muestra el texto "(sin inicializar)" hasta que Stepper se manipula, lo que hace que se desencadene el primer evento ValueChanged.

Creación de un Stepper en XAML

La página Basic Stepper XAML es funcionalmente la misma que Basic Stepper Code pero implementada principalmente en 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>

El archivo de código subyacente contiene el controlador para el evento 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);
    }
}

También es posible que el controlador de eventos obtenga el Stepper que desencadena el evento a través del argumento sender. La propiedad Value contiene el valor actual:

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

Si el objeto Stepper recibiera un nombre en el archivo XAML con un atributo x:Name (por ejemplo, "stepper"), el controlador de eventos podría hacer referencia directamente a ese objeto:

double value = stepper.Value;

Enlace de datos del Stepper

En la página Enlaces de paso básico se muestra cómo escribir una aplicación casi equivalente que elimina el controlador de eventos Value mediante el Enlace de datos:

<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>

La propiedad Rotation del primer Label está enlazada a la propiedad Value de Stepper, tal como es la propiedad Text del segundo Label con una especificación StringFormat. La página Basic Stepper Bindings funciona de manera un poco diferente a las dos páginas anteriores: cuando aparece la página por primera vez, la segunda Label muestra la cadena de texto con el valor. Esta es una ventaja de usar el enlace de datos. Para mostrar texto sin enlace de datos, tendrías que inicializar específicamente la propiedad Text de Label o simular una activación del evento ValueChanged mediante una llamada al controlador de eventos desde el constructor de clase.

Precauciones

El valor de la propiedad Minimum debe ser siempre inferior que el valor de la propiedad Maximum. El siguiente fragmento de código hace que Stepper genere una excepción:

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

El compilador de C# genera código que establece estas dos propiedades en secuencia y, cuando la propiedad Minimum se establece en 180, es mayor que el valor Maximum predeterminado de 100. Puedes evitar la excepción en este caso estableciendo primero la propiedad Maximum:

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

Establecer Maximum en 360 no es un problema porque es mayor que el valor predeterminado Minimum de 0. Cuando Minimum está establecido, el valor es menor que el valor Maximum de 360.

El mismo problema existe en XAML. Establece las propiedades en un orden que garantice que Maximum siempre sea mayor que Minimum:

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

Luego, puedes establecer los valores Minimum y Maximum en números negativos, pero solo en un orden donde Minimum siempre sea menor que Maximum:

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

La propiedad Value siempre es mayor o igual que el valor Minimum y menor o igual que Maximum. Si Value se establece en un valor fuera de ese intervalo, el valor se reprimirá para que se encuentre dentro del intervalo, pero no se genera ninguna excepción. Por ejemplo, este código no generará una excepción:

Stepper stepper = new Stepper
{
    Value = 180
};

En su lugar, la propiedad Value se convierte al valor Maximum de 100.

Este es un fragmento de código que se muestra anteriormente:

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

Cuando Minimum se establece en 180, Value también se establece en 180.

Si un controlador de eventos ValueChanged se ha adjuntado en el momento en que la propiedadValue está coaccionada a algo distinto de su valor predeterminado de 0, se desencadena un evento ValueChanged. Este es un fragmento de código XAML:

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

Cuando Minimum se establece en 180, Value también se establece en 180 y el evento ValueChanged se desencadena. Esto puede ocurrir antes de que se haya construido el resto de la página y el controlador podría intentar hacer referencia a otros elementos de la página que aún no se han creado. Es posible que desees agregar código al controlador ValueChanged que comprueba si hay valores null de otros elementos en la página. O bien, puedes establecer el controlador de eventos ValueChanged después de inicializar los valores Stepper.