Prism UWP for beginners: binding and commands

We setup the foundation of a Prism UWP app in the last post. Now we explore binding and commands.

Binding

Binding is the mechanism that connects the UI to the view-model properties to display data in the page and to receive input from the user (with two way binding). We can do binding by implementing the INotifyPropertyChanged interface in our view-model so the view is notified when a property in the view-model changes.

Prism helps us by providing classes that we can use to avoid reinventing the wheel and to start quickly with binding: VisualStateAwarePage and ViewModel.

We use VisualStateAwarePage instead of Page when we create a new view, for example:

<mvvm:SessionStateAwarePage 
x:Class="IC6.Buongiorno.Views.MainPage"
mvvm:ViewModelLocator.AutoWireViewModel="True"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:IC6.Buongiorno.Views"
xmlns:mvvm="using:Prism.Windows.Mvvm" >
    <mvvm:SessionStateAwarePage.Background>
        <ImageBrush Stretch="Fill" 
            ImageSource="ms-appx:///Assets/wallpaper.jpg" />
    </mvvm:SessionStateAwarePage.Background>

    <Grid Margin="50">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="10*" />
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Column="0"  Margin="10">
            <Button Command="{Binding Update}" Foreground="White">Update
            </Button>
            <TextBlock Text="{Binding Timeline}" Foreground="White" TextWrapping="Wrap" />
        </StackPanel>
        <StackPanel Grid.Column="1"                     HorizontalAlignment="Right">
            <TextBlock Text="{Binding WeatherDescription}" FontSize="32" Foreground="White" />
            <TextBlock Text="{Binding WeatherTemperature}" FontSize="50" Foreground="White" />
        </StackPanel>
    </Grid>
</mvvm:SessionStateAwarePage>

We must replace the Page type in the code-behind, too.

using Prism.Windows.Mvvm;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238

namespace IC6.Buongiorno.Views
{
    ///
<summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>

    public sealed partial class MainPage : SessionStateAwarePage
    {
        public MainPage()
        {
            InitializeComponent();

        }

    }
}

We create a MainPageViewModel class in the ViewModels directory and inherit from ViewModel. ViewModel is class of Prism that provides several helpers. In this example we create 3 properties in the ViewModel: Timeline, WeatherDescription, WeatherTemperature. Timeline will expose our Twitter timeline to the UI, WeatherDescrption will expose a brief textual description of the current weather (like “sunny”, “heavy rain”) and WeatherTemperature will expose the current temperature. This is the full MainPageViewModel.

using IC6.Buongiorno.Services.Twitter;
using IC6.Buongiorno.Services.Weather;
using Prism.Commands;
using Prism.Windows.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IC6.Buongiorno.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {
        ///<summary>
        /// Gets the command to Update Timeline and weather data.
        /// </summary>

        public DelegateCommand Update { get; private set; }

        ///<summary>
        /// Gets or sets the Twitter timeline.
        /// </summary>

        public string Timeline
        {
            get { return _timeline; }
            set { SetProperty(ref _timeline, value); }
        }

        ///<summary>
        /// Gets or sets the current weather description.
        /// </summary>

        public string WeatherDescription
        {
            get { return _weatherDescription; }
            set { SetProperty(ref _weatherDescription, value); }
        }

        ///<summary>
        /// Gets or sets the current weather temperature.s
        /// </summary>

        public string WeatherTemperature
        {
            get { return _weatherTemperature; }
            set { SetProperty(ref _weatherTemperature, value); }
        }

        ///<summary>
        /// Constructor with services.
        /// </summary>

        /// <param name="twitterService">The <see cref="ITwitterService"/> to access Twitter data.</param>
        /// <param name="weatherService">The <see cref="IWeatherService"/> to get current weather information.</param>
        public MainPageViewModel(ITwitterService twitterService, IWeatherService weatherService)
        {
            if (twitterService is null)
            {
                throw new ArgumentNullException(nameof(twitterService));
            }

            if (weatherService is null)
            {
                throw new ArgumentNullException(nameof(weatherService));
            }

            _twitterService = twitterService;

            _weatherService = weatherService;

            Update = new DelegateCommand(async () =>
            {
                Timeline = (await _twitterService.GetTimelineAsync()).Timeline;

                var weatherInfo = (await _weatherService.GetWeather());

                WeatherDescription = weatherInfo.Description;

                WeatherTemperature = $"{weatherInfo.Temperature} °C";
            });
        }

        private string _weatherTemperature;

        private string _weatherDescription;

        private readonly ITwitterService _twitterService;

        private readonly IWeatherService _weatherService;

        private string _timeline;
    }
}

In the code above the SetProperty method is provided by the ViewModel base class and with this we leverage the INotifyPropertyChanged interface to inform the UI that a property has updated its value.

In the constructor we have two dependencies: ITwitterService and IWeatherService. They are handled by the Unity container that we configured in the previuos post. When we’ll ask Unity to resolve an instance of MainPage it will automatically resolve ITwitterService and IWeatherService avoing to us all the heavylifting. This way our code remain clean and easier to read and mantain.

The view-model is automatically linked to the view by Prism beacuse in the page we declared mvvm:ViewModelLocator.AutoWireViewModel="True".

Commands

Commands are the mechanism to support the user interaction without using event handlers. In the Prism framework we find the DelegateCommand that implements the ICommand interface required by XAML.

The ICommand interface exposes a method called CanExecute that is very powerful. With a boolean condition we check if the command is enabled or not. In the MainPageViewModel class we declare an ICommand property and in the constructor we assign a DelegateCommand. In this example we’re getting the timeline from the Twitter service and the weather data from the weather service and assingn to the properties.

In the XAML code above we bind the button Update to this command with the standard binding syntax in the Command property of the Button.

TL;DR

In this post we explored the concepts of bindings and the commands to handle user input and display data retrieved with our services.

Cattura.PNG

Stay tuned for other Prims UWP posts.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s