Stepper
The .NET Multi-platform App UI (.NET MAUI) Stepper enables a numeric value to be selected from a range of values. It consists of two buttons labeled with minus and plus signs. These buttons can be manipulated by the user to incrementally select a double
value from a range of values.
The Stepper defines four properties of type double
:
Increment
is the amount to change the selected value by, with a default value of 1.Minimum
is the minimum of the range, with a default value of 0.Maximum
is the maximum of the range, with a default value of 100.Value
is the stepper's value, which can range betweenMinimum
andMaximum
and has a default value of 0.
All of these properties are backed by BindableProperty objects. The Value
property has a default binding mode of BindingMode.TwoWay
, which means that it's suitable as a binding source in an application that uses the Model-View-ViewModel (MVVM) pattern.
The Stepper coerces the Value
property so that it is between Minimum
and Maximum
, inclusive. If the Minimum
property is set to a value greater than the Value
property, the Stepper sets the Value
property to Minimum
. Similarly, if Maximum
is set to a value less than Value
, then Stepper sets the Value
property to Maximum
. Internally, the Stepper ensures that Minimum
is less than Maximum
. If Minimum
or Maximum
are ever set so that Minimum
is not less than Maximum
, an exception is raised. For more information on setting the Minimum
and Maximum
properties, see Precautions.
Stepper defines a ValueChanged
event that's raised when the Value
changes, either through user manipulation of the Stepper or when the application sets the Value
property directly. A ValueChanged
event is also raised when the Value
property is coerced as previously described. The ValueChangedEventArgs
object that accompanies the ValueChanged
event has OldValue
and NewValue
, of type double
. At the time the event is raised, the value of NewValue
is the same as the Value
property of the Stepper object.
Create a Stepper
The following example shows how to create a Stepper, with two Label objects:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
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="18"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Stepper Maximum="360"
Increment="30"
HorizontalOptions="Center"
ValueChanged="OnStepperValueChanged" />
<Label x:Name="_displayLabel"
Text="(uninitialized)"
HorizontalOptions="Center"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
In this example, the Stepper is initialized to have a Maximum
property of 360, and an Increment
property of 30. Manipulating the Stepper changes the selected value incrementally between Minimum
to Maximum
based on the value of the Increment
property. The second Label displays the text "(uninitialized)" until the Stepper is manipulated, which causes the first ValueChanged
event to be raised.
The code-behind file contains the handler for the ValueChanged
event:
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);
}
}
The ValueChanged
handler of the Stepper uses the Value
property of the stepper
object to set the Rotation
property of the first Label and uses the string.Format
method with the NewValue
property of the event arguments to set the Text
property of the second Label:
It's also possible for the event handler to obtain the Stepper that is firing the event through the sender
argument. The Value
property contains the current value:
double value = ((Stepper)sender).Value;
If the Stepper object were given a name in the XAML file with an x:Name
attribute (for example, "stepper"), then the event handler could reference that object directly:
double value = stepper.Value;
The equivalent C# code for creating a Stepper is:
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);
};
Data bind a Stepper
The ValueChanged
event handler can be eliminated by using data binding to respond to the Stepper value changing:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
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="18"
HorizontalOptions="Center"
VerticalOptions="Center" />
<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="Center" />
</StackLayout>
</ContentPage>
In this example, the Rotation
property of the first Label is bound to the Value
property of the Stepper, as is the Text
property of the second Label with a StringFormat
specification. When the page first appears, the second Label displays the text string with the value. To display text without data binding, you'd need to specifically initialize the Text
property of the Label or simulate a firing of the ValueChanged
event by calling the event handler from the class constructor.
Precautions
The value of the Minimum
property must always be less than the value of the Maximum
property. The following code example causes the Stepper to raise an exception:
// Throws an exception!
Stepper stepper = new Stepper
{
Minimum = 180,
Maximum = 360
};
The C# compiler generates code that sets these two properties in sequence, and when the Minimum
property is set to 180, it is greater than the default Maximum
value of 100. You can avoid the exception in this case by setting the Maximum
property first:
Stepper stepper = new Stepper
{
Maximum = 360,
Minimum = 180
};
In this example, setting Maximum
to 360 is not a problem because it is greater than the default Minimum
value of 0. When Minimum
is set, the value is less than the Maximum
value of 360.
The same problem exists in XAML. Set the properties in an order that ensures that Maximum
is always greater than Minimum
:
<Stepper Maximum="360"
Minimum="180" ... />
You can set the Minimum
and Maximum
values to negative numbers, but only in an order where Minimum
is always less than Maximum
:
<Stepper Minimum="-360"
Maximum="-180" ... />
The Value
property is always greater than or equal to the Minimum
value and less than or equal to Maximum
. If Value
is set to a value outside that range, the value will be coerced to lie within the range, but no exception is raised. For example, this code won't raise an exception:
Stepper stepper = new Stepper
{
Value = 180
};
Instead, the Value
property is coerced to the Maximum
value of 100.
A previous example set Maximum
to 360 and Minimum
to 180:
Stepper stepper = new Stepper
{
Maximum = 360,
Minimum = 180
};
When Minimum
is set to 180, then Value
is also set to 180.
If a ValueChanged
event handler has been attached at the time that the Value
property is coerced to something other than its default value of 0, then a ValueChanged
event is raised:
<Stepper ValueChanged="OnStepperValueChanged"
Maximum="360"
Minimum="180" />
When Minimum
is set to 180, Value
is also set to 180, and the ValueChanged
event is raised. This might occur before the rest of the page has been constructed, and the handler might attempt to reference other elements on the page that have not yet been created. You might want to add some code to the ValueChanged
handler that checks for null
values of other elements on the page. Or, you can set the ValueChanged
event handler after the Stepper values have been initialized.