Utilizing data binding in Xamarin.Forms applications can greatly simplify app development by automatically synchronizing an app’s data to its user interface with very little work. Previously, we took a look at setting up your project to begin data binding and then saw it in action in an app. We then explored more advanced data binding scenarios where values are formatted and converted as they are passed between source and target by the binding engine.
In this blog post, I’m going to explore a Xamarin.Forms feature called commanding, that allows data bindings to make method calls directly to a ViewModel.
Introduction to Commanding
The traditional approach for executing a method in response to an interaction with the UI is to call the method from a Clicked
event handler of a Button
or a Tapped
event handler of a TapGestureRecognizer
. However, with commanding, data bindings can make method calls directly to a ViewModel from the following classes:
Button
MenuItem
ToolbarItem
SearchBar
TextCell
ImageCell
ListView
TapGestureRecognizer
To support commanding, two public properties are defined on the majority of these classes:
Command
, of typeSystem.Windows.Input.ICommand
.CommandParameter
, of typeobject
.
Implementing a Command
In order to implement commanding, a ViewModel should define one or more properties of type ICommand
. The ICommand
interface defines two methods and one event:
public interface ICommand { void Execute(object arg); bool CanExecute(object arg) event EventHandler CanExecuteChanged; }
The Command
and Command<T>
classes provided by Xamarin.Forms implement the ICommand
interface, where T
is the type of the arguments to Execute
and CanExecute
. As well as implementing the ICommand
interface, these classes also include a ChangeCanExecute
method, which causes the Command
object to fire the CanExecuteChanged
event.
Within a ViewModel, there should be an object of type Command
or Command<T>
for each public property in the ViewModel of type ICommand
. The Command
or Command<T>
constructor requires an Action
callback object, that is called when the Button
calls the ICommand.Execute
method. The CanExecute
method is an optional constructor parameter, and takes the form of a Func
that returns a bool
.
The following code example shows a sample application command implementation that’s used to calculate a square root:
public class DemoViewModel : INotifyPropertyChanged { public int Number { get; set; } public double SquareRootResult { get; private set; } public ICommand SquareRootCommand { get; private set; } ... public DemoViewModel () { Number = 25; SquareRootCommand = new Command (CalculateSquareRoot); ... } void CalculateSquareRoot () { SquareRootResult = Math.Sqrt (Number); OnPropertyChanged ("SquareRootResult"); } ... }
The SquareRootCommand
is data bound to the Command
property of a Button
, as shown in the following code example from the sample application:
<Label Text="Demo 1 - Command" FontAttributes="Bold" /> <StackLayout Orientation="Horizontal"> <Label Text="Enter number:" /> <Entry Text="{Binding Number, Mode=TwoWay}" WidthRequest="50" /> </StackLayout> <Button Text="Calculate Square Root" Command="{Binding SquareRootCommand}" HorizontalOptions="Center" /> <StackLayout Orientation="Horizontal"> <Label Text="Square root =" /> <Label Text="{Binding SquareRootResult}" /> </StackLayout>
When the Button
is clicked, it calls the ICommand.Execute
method of the object bound to its Command
property. Therefore, the CalculateSquareRoot
method is called, with the value of the Number
property being used in the calculation. The square root of this value is calculated, and the Label
that binds to the SquareRootResult
property is updated with the result.
The following screenshots show the result of the SquareRootCommand
being executed:
Passing a Parameter to a Command
A parameter can be passed to an ICommand.Execute
method by using the Command<T>
class to instantiate the command. The following code example shows a sample application command implementation that’s used to calculate a square root of a value passed into the command as a parameter:
public class DemoViewModel : INotifyPropertyChanged { public double SquareRootWithParameterResult { get; private set; } public ICommand SquareRootWithParameterCommand { get; private set; } ... public DemoViewModel () { SquareRootWithParameterCommand = new Command<string> (CalculateSquareRoot); ... } void CalculateSquareRoot (string value) { double num = Convert.ToDouble (value); SquareRootWithParameterResult = Math.Sqrt (num); OnPropertyChanged ("SquareRootWithParameterResult"); } ... }
The SquareRootWithParameterCommand
is data bound to the Command
property of a Button
, as shown in the following code example from the sample application:
<Label Text="Demo 2 - Command with Parameter" FontAttributes="Bold" /> <StackLayout Orientation="Horizontal"> <Label Text="Enter number:" /> <Entry x:Name="entry" Text="100" WidthRequest="50" /> </StackLayout> <Button Text="Calculate Square Root" Command="{Binding SquareRootWithParameterCommand}" CommandParameter="{Binding Source={x:Reference entry}, Path=Text}" HorizontalOptions="Center" /> <StackLayout Orientation="Horizontal"> <Label Text="Square root =" /> <Label Text="{Binding SquareRootWithParameterResult}" /> </StackLayout>
As well as the Button
binding its Command
property to the SquareRootWithParameterCommand
, it also passes the Text
property value of the Entry
to the SquareRootWithParameterCommand
through its CommandParameter
property.
When the Button
is clicked, it calls the ICommand.Execute
method of the object bound to its Command
property. The argument to the Execute
method is the object set to the CommandParameter
property of the Button
. Therefore, when the Button
is clicked, the CalculateSquareRoot
method is called, with the value that the CommandParameter
of the Button
binds to being passed as a parameter to the method. The square root of this value is calculated, and the Label
that binds to the SquareRootWithParameterResult
property is updated with the result.
The following screenshots show the result of the SquareRootWithParameterCommand
being executed:
Calling an Asynchronous Method
An asynchronous method can be invoked by a command by using the async
and await
keywords when specifying the command’s Action
callback. This indicates that the callback is a Task
and should be awaited. The following code example shows a sample application command implementation that simulates a file downloading through an asynchronous method:
public class DemoViewModel : INotifyPropertyChanged { ... bool canDownload = true; string simulatedDownloadResult; public string SimulatedDownloadResult { get { return simulatedDownloadResult; } private set { if (simulatedDownloadResult != value) { simulatedDownloadResult = value; OnPropertyChanged ("SimulatedDownloadResult"); } } } public ICommand SimulateDownloadCommand { get; private set; } public DemoViewModel () { ... SimulateDownloadCommand = new Command (async () => await SimulateDownloadAsync (), () => canDownload); } async Task SimulateDownloadAsync () { CanInitiateNewDownload (false); SimulatedDownloadResult = string.Empty; await Task.Run (() => SimulateDownload ()); SimulatedDownloadResult = "Simulated download complete"; CanInitiateNewDownload (true); } void CanInitiateNewDownload (bool value) { canDownload = value; ((Command)SimulateDownloadCommand).ChangeCanExecute (); } void SimulateDownload () { // Simulate a 5 second pause var endTime = DateTime.Now.AddSeconds (5); while (true) { if (DateTime.Now >= endTime) { break; } } } ... }
The SimulateDownloadCommand
is data bound to the Command
property of a Button
, as shown in the following code example from the sample application:
<Label Text="Demo 3 - Async Command with CanExecute" FontAttributes="Bold" /> <Button Text="Simulate 5 Second Download" HorizontalOptions="Center" Command="{Binding SimulateDownloadCommand}" /> <StackLayout Orientation="Horizontal"> <Label Text="Result: " /> <Label Text="{Binding SimulatedDownloadResult}" /> </StackLayout>
When the Button
is clicked the SimulateDownloadAsync
method is invoked and the Button
is disabled and re-enabled once the five second simulation has completed. This is achieved by specifying a ICommand.CanExecute
method in the SimulateDownloadCommand
constructor. The Button
calls CanExecute
when its Command
property is first set. If CanExecute
returns false
, the Button
disables itself and doesn’t generate Execute
calls. The Button
also handles the ICommand.CanExecuteChanged
event. Therefore, whenever the ViewModel fires the CanExecuteChanged
event by calling the Command.CanExecuteChanged
method, the Button
calls CanExecute
again to determine if it should be enabled.
The following screenshots demonstrate the disabled Button
, while the simulated download asynchronously executes:
Note that because the simulated download is executed on a background thread, it’s still possible to interact with the UI while the simulated download is executing.
Wrapping Up
Commanding allows data bindings to make method calls directly to a ViewModel and is supported by eight Xamarin.Forms classes. To implement commanding, a ViewModel defines one or more properties of type ICommand
, which are then connected to the Command
properties of UI controls through data binding. Within the ViewModel, there should then be an object of type Command
or Command<T>
for each public property in the ViewModel of type ICommand
.
For more information about asynchronous programming, see our Async Support Overview. For more information about data binding, see Data Binding Basics. For more information about data binding and MVVM, see From Data Bindings to MVVM. Xamarin University also provides a class on data binding in Xamarin.Forms.
The post Simplifying Events with Commanding appeared first on Xamarin Blog.