1 Comments

For my recent blog post about how to consume a web service in the Portable Class Library (PCL) I decided to write the client for Windows 10 which allows to create apps for every platform that runs Windows 10. In this post I will focus on the platforms Desktop, Tablet and Mobile showing how to create a basic application based on a MVVM architecture. To create a Windows 10 app you will need a computer running Windows 10 and Visual Studio 2015.

Creating a basic app

First lets create a list of people that we can navigate to in the detail view. Here fore we will create two pages. On the first page MainPage.xaml we will simply show the list:

<Page
    x:Class="HttpClientSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"></GridView>

        <AppBar VerticalAlignment="Bottom" IsOpen="True" >
            <AppBarButton Icon="Add" Label="Add Person" Command="{Binding AddNewPerson}" />
        </AppBar>
    </Grid>
</Page>

The user can select an element of the list on which we will navigate to the detail of the person allowing us to edit the person. This is done in the MainViewModel.cs which is based on the MVVM Light Framework for implementation:

public class MainViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private ObservableCollection<Person> _people;
    private Person _selectedPerson;

    public MainViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;
        _people = new ObservableCollection<Person>();
        ShowPerson = person => { };
        AddNewPerson = new RelayCommand(() => ShowPerson(-1));
    }

    public ObservableCollection<Person> People => _people;
    public Action<int> ShowPerson { get; set; }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            if (_selectedPerson == value) return;
            _selectedPerson = value;
            RaisePropertyChanged(nameof(SelectedPerson));
            if (_selectedPerson != null) ShowPerson(_people.IndexOf(_selectedPerson));
        }
    }

    public ICommand AddNewPerson { get; private set; }

    public async Task Init()
    {
        var people = await _personService.GetPeople();

        _people.Clear();

        foreach (var person in people)
        {
            _people.Add(person);
        }
    }
}

The View Model also prepares the List of people that is displayed on the main page. The PersonDetailPage.xaml will allow to edit the first and surname of the person:

<Page
    x:Class="HttpClientSample.PersonDetailPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Person, Source={StaticResource Locator}}"
    Loaded="PersonDetail_OnLoaded"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Header="Firstname" Text="{Binding Firstname, Mode=TwoWay}"/>
        <TextBox Header="Lastname" Text="{Binding Lastname, Mode=TwoWay}"/>
        <Button Content="Save" Command="{Binding StoreCommand, Mode=TwoWay}" IsEnabled="{Binding HasPendingChanges}" HorizontalAlignment="Center" Margin="0,10"/>
    </StackPanel>
</Page>

When selecting save the person will be updated, all the logic is implemented in the PersonDetailViewModel.cs:

public class PersonDetailViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private int _id;
    private string _firstname;
    private string _lastname;
    private bool _hasPendingChanges;

    public PersonDetailViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;

        StoreCommand = new RelayCommand(StorePerson, () => true);
        HasPendingChanges = false;
    }

    public bool HasPendingChanges
    {
        get { return _hasPendingChanges; }
        set
        {
            if (value == _hasPendingChanges) return;
            _hasPendingChanges = value;
            RaisePropertyChanged(nameof(HasPendingChanges));
        }
    }

    public string Firstname
    {
        get { return _firstname; }
        set
        {
            if (value == _firstname) return;
            _firstname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Firstname));
        }
    }

    public string Lastname
    {
        get { return _lastname; }
        set
        {
            if (_lastname == value) return;
            _lastname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Lastname));
        }
    }

    public ICommand StoreCommand { get; set; }

    public async Task Init(int id)
    {
        _id = id;
        var person = id > 0 ? (await _personService.GetPeople()).ToList()[id] : new Person("", "");
        Firstname = person.FirstName;
        Lastname = person.LastName;
        HasPendingChanges = false;
    }

    private async void StorePerson()
    {
        HasPendingChanges = false;

        var person = new Person(Firstname, Lastname);

        if (_id >= 0)
        {
            await _personService.UpdatePerson(_id, person);
        }
        else
        {
            await _personService.CreatePerson(person);
        }
    }
}

To prevent the user from invoking the storing of a person multiple times the store button is only enabled when there are pending changes and you probably want to improve the error handling in production code as it is non-existent in the StorePerson method.

Basic Navigation

From the main page we implement the navigation in MainPage.xaml.cs which allows the user to navigate to the detail page. We also pass along a navigation parameter which contains the ID or ahem in this basic example the array index of the person we want to see:

private void ShowPerson(int personId)
{
    Frame.Navigate(typeof (PersonDetailPage), personId);
    _viewModel.SelectedPerson = null;
}

The navigation is done over Frame.Navigate, which takes the type of the target and a parameter as an argument. The SelectedPerson is then set to null, after invoking the navigation. This is done so that the user may reselect the person the second time around.

Additionally when the user adds a person over the AppBar it will invoke the same navigation method but pass in the –1 as parameter indicating that no Index is set.

Further the user has the possibility to navigate back to the main page. Here fore we have to enable the back navigation which we set in the Loaded event handler of the person detail page and add an event handler for the BackRequest:

private void PersonDetail_OnLoaded(object sender, RoutedEventArgs e)
{
    SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
    SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}

The event handler is implemented as follows:

private void OnBackRequested(object sender, BackRequestedEventArgs backRequestedEventArgs)
{
    if (Frame.CanGoBack)
    {
        Frame.GoBack();
        backRequestedEventArgs.Handled = true;
    }
}

While testing the app under Windows 10 mobile I noticed that the navigation was invoked twice when selecting the hardware back button. By setting the Handled property to true in the event arguments the framework is indicated that the navigation has been taken care of.

Taking it to other form factors

A great thing about creating your apps as a Universal Windows Platform app is that the APIs remain the same across the devices. In regards to the upcoming Windows 10 Mobile release we can even reuse the UI code. So we can run this basic app on a phone without making any changes. The UI will be automatically adopted to the new form factor.

Now of course for more complex apps you will want to use different layouts according to the screen size, but even then you will be creating adaptive layouts (same as with responsive Websites) rather than developing multiple apps to target different platforms. So a lot less overhead and work to have a running app across multiple form factors.

Conclusion

In this post we saw how to create a basic Windows 10 UWP app including basic navigation features and how to implement the MVVM pattern. If you are coming from a WPF, Silverlight, Windows 8.x or Windows Phone background you have seen that a lot of elements are very familiar.

I’ve been lately playing around with F# which unfortunately is currently not a supported language to write UWP apps. This also includes not being able to share Portable Class Libraries with UWP apps. If you feel the same way as me or want to throw the F# community a bone please let Microsoft know that they enable support for F# UWP apps here.

You can find the entire sample code of this blog post on GitHub.

0 Comments

When working with a mobile app you will often work with a backend, which if you are working with C# might very probably be a Web API backend. In this blog we will look at how we can consume and write to a Web API Controller that we can host on Azure. Why Azure? Because it is the easiest way of hosting a web service straight out of Visual Studio and if you happen to have a MSDN subscription you can do this all for free. For the client we will be using a Windows 10 Universal App which allows us to write a client for Desktop, Tablet and Phone.

The app we will be building will add the capability to read a list of people from a service and add a person to the existing. So we will see how we can read and write to a HTTP service.

The client

As a client we will be targeting Windows Phone (soon to be Windows Mobile again), Android and iOS. Our implementation of integrating with the backend we will perform in the Portable Class Library (PCL) which provides us the unique advantage of only having to write our backend service integration once.

PCL integration

In the PCL we will require the following NuGet packages:

Armed with the capabilities of now being able to communicate to a HTTP backend and serializing i.e. deserializing objects to and from JSON we can start implementing our communication layer by creating a HTTP client in the constructor. We usually only need one instance of the HTTP client as it will handle multiple requests and only spawn as many active connections as are reasonable over HTTP:

public class PersonService : IPersonService
{
    private HttpClient _httpClient;

    public PersonService()
    {
        _httpClient = new HttpClient();
    }

    // ... Person Service implementation
}

For reading over HTTP we should use the GET keyword which is provided by the HTTP client and is implemented as follows:

public async Task<IEnumerable<Person>> GetPeople()
{
    var result = await _httpClient.GetAsync(BASE_URI);
    var peopleJson = await result.Content.ReadAsStringAsync();

    return JsonConvert.DeserializeObject<IEnumerable<Person>>(peopleJson);
}

Note that if you are using a free website on Azure you can choose to run communications over SSL, the only thing you have to change for this is adding an s in the URI after http i.e. resulting in an https URI.

Writing to a HTTP service depends on the action we want to perform. Creating something new e.g. adding a new person to the existing person list, should be performed over a HTTP POST.  Implementing the post can be done as follows:

public async Task<bool> CreatePerson(Person person)
{
    var personJson = JsonConvert.SerializeObject(person);
    var content = new StringContent(personJson, Encoding.UTF8, "application/json");
    var result = await _httpClient.PostAsync(BASE_URI, content);

    return result.IsSuccessStatusCode;
}

The StringContent method has additional parameters to indicate to the server how the content can be interpreted. This is required to inform the backend service that the data we are sending is serialized as JSON. Not doing so would end in false information in the header which would prevent Web API to automatically deserialize the body.

Updating an existing person usually is done via PUT, which is similar to the CreatePerson method but contains an ID in the URI which usually corresponds with the ID from the Person which is set on the backend.

public async Task<bool> UpdatePerson(int id, Person person)
{
    var uri = Path.Combine(BASE_URI, id.ToString());

    var personJson = JsonConvert.SerializeObject(person);
    var content = new StringContent(personJson, Encoding.UTF8, "application/json");

    var result = await _httpClient.PutAsync(uri, content);

    return result.IsSuccessStatusCode;
}

As you can see implementing a Web service is quite straight forward with the HTTP Client and allows to easily create a backend integration for native clients that can be shared across platforms.

The UI

On the client side we now can invoke our portable service and display a list of people.

<Page
    x:Class="HttpClientSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"></GridView>

        <AppBar VerticalAlignment="Bottom">
            <AppBarButton Icon="Add" Label="Add" Command="{Binding AddNewPerson}" />
        </AppBar>
    </Grid>
</Page>

In the ViewModel we can invoke the backend service to provide the data.

public class MainViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private ObservableCollection<Person> _people;
    private Person _selectedPerson;

    public MainViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;
        _people = new ObservableCollection<Person>();
        ShowPerson = person => { };
        AddNewPerson = new RelayCommand(() => ShowPerson(0));
    }

    public ObservableCollection<Person> People => _people;
    public Action<int> ShowPerson { get; set; }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            if (_selectedPerson == value) return;
            _selectedPerson = value;
            RaisePropertyChanged(nameof(SelectedPerson));
            if (_selectedPerson != null) ShowPerson(_people.IndexOf(_selectedPerson));
        }
    }

    public ICommand AddNewPerson { get; private set; }

    public async Task Init()
    {
        var people = await _personService.GetPeople();

        _people.Clear();

        foreach (var person in people)
        {
            _people.Add(person);
        }
    }
}

Adding a person means we have to add a further page to our client application that provides us with a form to enter the name and first name of a person. To keep things simple we will just use the same UI and identify via the navigation parameter if we have to create or update the person on the backend.

<Page
    x:Class="HttpClientSample.PersonDetail"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Person, Source={StaticResource Locator}}"
    Loaded="PersonDetail_OnLoaded"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Header="Firstname" Text="{Binding Firstname, Mode=TwoWay}"/>
        <TextBox Header="Lastname" Text="{Binding Lastname, Mode=TwoWay}"/>
        <Button Content="Save" Command="{Binding StoreCommand, Mode=TwoWay}" IsEnabled="{Binding HasPendingChanges}" HorizontalAlignment="Center" Margin="0,10"/>
    </StackPanel>
</Page>

The ViewModel is handling the integration with the PersonService from the PCL library:

public class PersonViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private int _id;
    private string _firstname;
    private string _lastname;
    private bool _hasPendingChanges;

    public PersonViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;

        StoreCommand = new RelayCommand(StorePerson, () => true);
        HasPendingChanges = false;
    }

    public bool HasPendingChanges
    {
        get { return _hasPendingChanges; }
        set
        {
            if (value == _hasPendingChanges) return;
            _hasPendingChanges = value;
            RaisePropertyChanged(nameof(HasPendingChanges));
        }
    }

    public string Firstname
    {
        get { return _firstname; }
        set
        {
            if (value == _firstname) return;
            _firstname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Firstname));
        }
    }

    public string Lastname
    {
        get { return _lastname; }
        set
        {
            if (_lastname == value) return;
            _lastname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Lastname));
        }
    }

    public ICommand StoreCommand { get; set; }

    public async Task Init(int id)
    {
        _id = id;
        var person = id > 0 ? (await _personService.GetPeople()).ToList()[id] : new Person("", "");
        Firstname = person.FirstName;
        Lastname = person.LastName;
        HasPendingChanges = false;
    }

    private async void StorePerson()
    {
        HasPendingChanges = false;

        var person = new Person(Firstname, Lastname);

        if (_id > 0)
        {
            await _personService.UpdatePerson(_id, person);
        }
        else
        {
            await _personService.CreatePerson(person);
        }

        HasPendingChanges = false;
    }
}

Again integrating a PCL library is not difficult and requires no additional hoops to jump through. What we gain by putting our logic into the PCL is that we can reuse the code across multiple platforms.

The Controller

We will focus on the client part during this post but for getting an understanding of the bigger picture here is the controller we will be communicating with.

public class PersonController : ApiController
{
    private readonly static Lazy<IList<Person>> _people = new Lazy<IList<Person>>(() => new PersonService().GeneratePeople(1000), LazyThreadSafetyMode.PublicationOnly);
    // GET: api/Person
    public IEnumerable<Person> Get()
    {
        return _people.Value;
    }

    // GET: api/Person/5
    public Person Get(int id)
    {
        if (id < 0 || _people.Value.Count < id) return null;
        return _people.Value[id];
    }

    // POST: api/Person
    [HttpPost]
    public IHttpActionResult Post(Person value)
    {
        if (value == null) return BadRequest();

        _people.Value.Add(value);

        return CreatedAtRoute("DefaultApi", new { id = _people.Value.IndexOf(value) }, _people.Value.Last());
    }

    // PUT: api/Person/5
    [HttpPut]
    public IHttpActionResult Put(int id, [FromBody]Person value)
    {
        if (id < 0 || id >= _people.Value.Count()) return BadRequest();

        _people.Value[id] = value;

        return Ok(value);
    }

    // DELETE: api/Person/5
    public IHttpActionResult Delete(int id)
    {
        if (id < 0 || id >= _people.Value.Count()) return BadRequest();

        _people.Value.RemoveAt(id);

        return StatusCode(System.Net.HttpStatusCode.NoContent);
    }
}

internal class PersonService
{
    public IList<Person> GeneratePeople(int count)
    {
        var firstNames = new List<string>(count);
        var lastNames = new List<string>(count);

        for (int i = 0; i < count; ++i)
        {
            firstNames.Add(NameGenerator.GenRandomFirstName());
            lastNames.Add(NameGenerator.GenRandomLastName());
        }

        return firstNames.Zip(lastNames, (firstName, lastName) => new Person(firstName, lastName)).ToList();
    }
}

As you can see it is rather basic and through the static variable we have some sort of poor mans database. Do not use this way of storing data in a production environment!

Conclusion

In this post we saw how we can integrate a ASP.Net Web API server in a PCL. Thereby seeing how to read and write objects to a web service. Further we saw how we can display and enter the data on a Windows 10 client. The entire sample could have been written for Xamarin.iOS, Xamarin.Android or WPF which is exactly the sweet spot of writing your business logic in the PCL it does not matter what client you are intending to write now or in the future as long as the PCL allows you to integrate multiple client platforms.

You can find the entire sample project on NuGet.

0 Comments

androidMvvmLight

This week we’ll have a look at how we can use the MVVM pattern on Xamarin.Android using the MVVM Light framework from Laurent Bugnion.

Creating the View

For this sample lets create a basic entry view with an EditText, Buttonand TextView to display the entry that was submitted via the button.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <EditText
        android:id="@+id/MessageText"
        android:hint="@string/MessageTextHint"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/SubmitMessage"
        android:layout_marginBottom="10dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/SubmitMessage" />
    <TextView
        android:id="@+id/SubmittedMessage"
        android:layout_marginBottom="10dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="@string/SubmittedMessageText" />
</LinearLayout>

As you can observe this is a standard LinearLayout containing default Android controls. With MVVM Light we do not have the option as in MVVM Cross to set the binding code directly in the AXML but more how it’s done later. So lets setup the corresponding ViewModel.

Creating the ViewModel

With in the ViewModel we need a property to store the entered message, another one to expose an ICommand which we can bind to the button and finally a third property where we can store the message that was entered at the time the button is being pushed:

public class MainViewModel : ViewModelBase
{
    private string _message;
    private string _previousMessage;

    public MainViewModel()
    {
        MessageCommand = new RelayCommand<string>(SubmitMessage);
    }

    public RelayCommand<string> MessageCommand { get; private set; }

    private void SubmitMessage(string message)
    {
        PreviousMessage = message;
    }

    public string PreviousMessage
    {
        get { return _previousMessage; }
        set
        {
            _previousMessage = value;
            RaisePropertyChanged(propertyName: nameof(PreviousMessage));
        }
    }

    public string Message
    {
        get { return _message; }
        set
        {
            _message = value;
            RaisePropertyChanged(propertyName: nameof(Message));
        }
    }
}

If you have been using ViewModels before you will not notice anything out of the ordinary with this code which means you could reuse this ViewModel for a WPF, Windows 8, UWP apps or even Xamarin.iOS i.e. Xamarin.Forms app. (This is good Winking smile)

Setting up the Locator

Another step we want to make is to ensure that the ViewModel and any future services will be created and setup over the Inversion of Control container. MVVM Light provides us the SimpleIoC container which usually is setup in the ViewModelLocator.cs class. Currently we only use one view model so that is all we have to setup:

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel Main
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }

    public static void Cleanup()
    {
        // TODO Clear the ViewModels
    }
}

As there is no fixed starting point in Android we have not Main method or such to configure our container on startup. I personally like the idea of a lazy container such in one that is only created when it is really used. So lets create an App.cs class in the root of our Android project. In this class we will instantiate the locator and provide access to this one instance:

public static class App
{
    private static ViewModelLocator _locator;

    public static ViewModelLocator Locator => _locator ?? (_locator = new ViewModelLocator());
}

Now that we have all the basics covered lets move on to the juicy part of wiring up the bindings.

Setting up the bindings

We have to manually set the bindings in the activity for the corresponding view. In this sample app we will do it in the MainActivity.cs. First we wire up the EditText:

_messageBinding = this.SetBinding(() => EditMessage.Text, BindingMode.TwoWay);

The command with the button:

MessageButton.SetCommand("Click", Vm.MessageCommand, _messageBinding);

And the TextViewto the PreviousMessage property:

_textViewBinding = this.SetBinding(() => Vm.PreviousMessage, () => PreviousMessage.Text);

Now whenever we edit a text and select the button the text will appear on the TextView bellow.

Conclusion

In this post we saw how we can create a simple form application and write & read from a ViewModel. We further saw how we can setup the dependency injection module for a Xamarin.Android application and ensure that even if the app should be started with a different activity the container is setup correctly.

You can find the entire little sample project up on GitHub.

References

MVVMLight flowers sample by Laurent Bugnion.

2 Comments

In this weeks blog post lets look at how we can enable bindings with MVVM Light under iOS using a Storyboard with Xamarin. So lets create a simple application that has a label, button and text entry field.

MvvmLightiOSBinding

The label will display the previous message which was entered in the text entry field and submitted with the button. The entire UI is designed in the Storyboard designer and then hooked up to the ViewModel in the code behind.

Wiring up the View to the ViewModel

Under iOS the bindings have to be defined within the code, so for the label that gets updated from the ViewModel the binding looks as follows:

_textLabelBinding = this.SetBinding (
() => Vm.TheResponse,
() => TextLabel.Text);

The button is wired via a command binding:

SubmitTextButton.SetCommand("TouchUpInside", Vm.SubmitTextCommand);

When it comes to the text field we have to register ourselfs to an event of the UI control on which we are invoked. Then we pass the value of the text field to our MainViewModel i.e. the property.

_textFieldBinding = this.SetBinding (
() => EntryTextField.Text)
.ObserveSourceEvent ("EditingDidEnd")
.WhenSourceChanges (() => Vm.TheInput = EntryTextField.Text);

So as you can see there is a bit more work to do for using ViewModels under iOS than under Xamarin.Forms, Android or Windows – but it can be done Smile

Taking a peek at the ViewModel

The MainViewModel is pretty straight forward and does not differ from ViewModels you may use for Windows applications e.g. Universal Windows Apps.

public class MainViewModel : ViewModelBase
{
private string _theInput;
private string _theResponse;
private RelayCommand _submitTextCommand;

public MainViewModel ()
{
Names = new ObservableCollection<string>();
SubmitTextCommand = new RelayCommand (HandleSubmitTextCommand, () => CanExecuteSubmitText);
CanExecuteSubmitText = true;

TheResponse = "Awaiting your input";
}

public string TheInput {
get {
return _theInput;
}
set {
_theInput = value;
RaisePropertyChanged (() => TheInput);
}
}

public string TheResponse {
get {
return _theResponse;
}
set {
if (value == _theResponse) return;
_theResponse = value;
RaisePropertyChanged (() => TheResponse);
}
}

public RelayCommand SubmitTextCommand {
get {
return _submitTextCommand;
}
private set {
_submitTextCommand = value;
}
}

public bool CanExecuteSubmitText {
get;
set;
}

public ObservableCollection<string> Names { get; set; }

private void HandleSubmitTextCommand ()
{
CanExecuteSubmitText = false;

TheResponse = "You just entered: " + TheInput;

CanExecuteSubmitText = true;
}
}

When the command is invoked we simply register a handler for which in the case of the sample code is the HandleSubmitTextCommand method. You can also use set the CanExecute property of an ICommand and it will prevent the Command from re-executing while the handler is still working on a call from the user.

Conclusion

So as you could see the MVVM Light framework from Laurent Bugnion can be used to implement a MVVM client architecture under iOS using Storybaords. The biggest difference from the standard approach is that the developer has to handle wiring up the bindings and ensure that the bindings are attached to corresponding events in case of reacting to new values from the UI. Other then that the code is the same as you would expect it to be from Windows implementations.

You can find the sample code on GitHub.

References

Laurent Bugnions Xamarin Evolve talk.

Getting started with MVVM Light and Xamarin.Forms Post.

0 Comments

message

Messages are a common pattern used in the Model View ViewModel (MVVM) pattern approach. They allow the ViewModel and Model to communicate with the view without having to couple them to it. Messages should generally be used to communicate changes within the system. Similar to events they provide a looser coupling and the message provides all the functionality of a C# object if need be. In this post I’ll show you how a message can be created, sent and finally how to register a handler within an object for a defined message.

Setting up the project

The demonstration project will be a Windows Phone 8.1 solution. You will have to install the MVVM Light NuGet package. We will have a simple view containing a label and a button:

<Page
x:Class="Messenger.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Messenger"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="{Binding InvokedMessage}" Style="{StaticResource MessageDialogContentStyle}"
Margin="0,10" />
<Button Content="Invoke Service" HorizontalAlignment="Center" Command="{Binding InvokeServiceCommand}" Width="200" Margin="0,10" />
</StackPanel>
</Page>

The button triggers a command in the ViewModel, which invokes an update of the service:

private void InvokeService()
{
CanInvokeService = false;

_sampleService.NonBlockingAsyncMethod();
}

The service is a async void method which means it can not be awaited. After the delay has passed a message shall be sent any receiver:

public async void NonBlockingAsyncMethod()
{
_invokedCount += 1;
await Task.Delay(3000);

GalaSoft.MvvmLight.Messaging.Messenger.Default.Send(new SampleMessage(_invokedCount));
}

So lets see how the message is implemented.

Creating a message

A message is a POCO (Plain Old CLR Object) that inherits from MessageBase. It is up to the developer how many properties or even functions shall be added to the message. In general a message should be treated as a Data Object.

internal class SampleMessage:MessageBase
{
public SampleMessage(int invokedCount):base()
{
InvokedCount = invokedCount;
}

public int InvokedCount { get; set; }
}

For our sample we will simply add a count property that indicates the number of calls the service has been invoked.

Sending a message

Sending a message is simply done by invoking the Send method on the default Messanger, as it is done in the NonBlockingAsyncMethod in the SampleService:

GalaSoft.MvvmLight.Messaging.Messenger.Default.Send(new SampleMessage(_invokedCount));

So now all we have to do is register our receivers.

Subscribing/Registering the message receiver

On the view model we can register a handler that receives the message and updates the label with an according call:

GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<SampleMessage>(this, ReceiveSampleMessage);

 

Which is done in the MainViewModel.

Conclusion

Messaging allows to decouple objects that need to communicate with one another. In our sample the service communicates with the ViewModel but does not have any direct reference of the ViewModel and therefore is fully decoupled of it. Messaging can be a great help in writing maintainable code but be advised that though this method does allow to decouple objects it also adds complexity and therefore passing a method as call back function might be sometimes the more straight forward way of communicating to a developer.

You can find the entire code on GitHub.

References

Laurent Bugnion who is the creator and maintainer of the MVVM Light framework.