Monthly Archives: August 2014

WinRT Data Binding Using MVVM

How to bind Windows 8 XAML to a View Model. Although this post is based on an example using MVVM Cross, it will work for any MVVM framework, or even a customised one.

The Problem

I have a collection of data that I want to display in a customised format. My architecture is MVVM (using MVVM Cross).

Architecture

The principle here is that my data is stored in a model, but shaped in the ViewModel into a digestible format for the view. In my specific example, I have a list of people, and based on a specific criteria, I want to display a selection of these people in the view. For the sake of this article, I want to display people with a name starting with “D”.

Implementation

My model looks something like this:

    public class Person
    {
        #region Basic attributes
        public string Name { get; set; }

When my ViewModel is shown, I override an initialise method. Whilst this is not part of MVVM Cross per-se, it is basically a call to a custom initialise from the default `Init`:

private IEnumerable<Person> _people;
public IEnumerable<Person> People
{
    get { return _people; }
    set
    {
        _people = value;
        RaisePropertyChanged(() => People);
    }
}

// Override custom init method
protected override void RealInit(NavigationParameter parameter)
{            
    var population = Mvx.Resolve<Population>();
    People = population.Where(p => p.Name.StartsWith("D"));
}

So, my ViewModel now contains the correct, shaped data, I can just bind this:

    <Page.Resources>
        <DataTemplate x:Name="PeopleTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}"/>
            </StackPanel>
        </DataTemplate>    
    </Page.Resources>

    …


    <ListView x:Name="ItemListView" 
                      ItemsSource="{Binding People}"
                      Width="Auto" Height="Auto" 
                      ItemTemplate="{StaticResource PeopleTemplate}" 
                      ShowsScrollingPlaceholders="False"                          
                      />

And that should work.

MVVM Cross Visibility Plugin

A quick forward: there is nothing in this post that isn’t already published here: https://github.com/MvvmCross/MvvmCross/wiki/Value-Converters#the-mvx-visibility-valueconverters.

In this post I referred to a BooleanToVisibilityConverter Windows Store implementation for MVVM Cross. The approach that I outlined in the post will definitely work; however, it will mean re-writing the converter for each platform. So, this post corrects that error.

It was then pointed out to me by a work colleague that there is a Visibility plug-in for MVVM Cross. I wasn’t aware of this, but now that I am, here’s how it works.

Add a reference from NuGet in the front end:

refnuget

Once you’ve added that, here is the revised and simplified code for the converter:

using Cirrious.CrossCore.WindowsStore.Converters;
using Cirrious.MvvmCross.Plugins.Visibility;


namespace MyGame.Converters
{
    public class BooleanToVisibilityConverter : MvxNativeValueConverter<MvxVisibilityValueConverter> { }
}

You will need a wrapper like this for each platform, but at least you’re not re-writing the visibility converter again and again.

MVVMCross – ShowViewModel not working?

I thought I’d jot this down, as it had me for a short while. Imagine that you have a line of code that looks like this:

ShowViewModel<MyViewModel>();

But nothing happens when you call it.

The Output Window

The output window is definitely your friend with MVVMCross; it may say something like this:

mvx:Diagnostic: 36.44 Error seen during navigation request to MyViewModel – error KeyNotFoundException: Could not find view for MyApp.PCL.ViewModels.MyViewModel
at Cirrious.MvvmCross.Views.MvxViewsContainer.GetViewType(Type viewModelType)
at Cirrious.MvvmCross.WindowsStore.Views.MvxStoreViewPresenter.Show(MvxViewModelRequest request)

So, what’s the problem?

Some things to check: firstly, check that you are using an MVVMCross view; that is, for example, in Windows 8, you need your page to inherit from MvxStorePage, not Page:

Conclusion

Nothing here that you won’t see on one of Stuart Lodge’s tutorials, and probably a good handful of SO questions. So now it’s here as well.

Updating a Progress Bar using MVVM Cross

As usual with these posts, although the specific code in the article relates to MVVM Cross, it should be applicable to any MVVM framework. Where it is specific, I’ll try to flag that up.

The Scenario

In the current game that I’m writing in MVVM Cross (yes, that’s right – a game), I have a situation where the user selects to create a “New Game” and the game world needs to be generated. As this can take some time, I want to display a progress bar. Roughly speaking, the process flow is as follows:

On the Menu Page, the User selects “New Game”.
The Menu View Model calls a service that creates the game world.
It then calls the Main Page View Model to display the main page.

The Problem

Basically, communicating between view models without tightly coupling them together.

That’s what messages are for isn’t it?

Yes.

Here’s my implementation.

First step is to add the progress bar to the screen that you want to update:

<views:MvxStorePage
    x:Class=…
    xmlns:converters="using:MyGame.Converters"
    mc:Ignorable="d">

    <views:MvxStorePage.Resources>
        <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConv"/>    
    </views:MvxStorePage.Resources>

    …

    <ProgressBar Value="{Binding LoadingProgress}" Maximum="{Binding TotalProgress}" Margin="20" Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibilityConv}}"/>

There are three properties bound here: None exist yet. Obviously, if you want the progress bar to always display, you might not need all three.

Let’s create the properties in the VM:

        private bool _isLoading = false;
        public bool IsLoading
        {
            get { return _isLoading; }
            set
            {
                _isLoading = value;
                RaisePropertyChanged(() => IsLoading);
            }
        }

        private int _loadingProgress = 0;
        public int LoadingProgress
        {
            get { return _loadingProgress; }
            set
            {
                _loadingProgress = value;
                RaisePropertyChanged(() => LoadingProgress);
            }
        }

        private int _totalProgress = 0;
        public int TotalProgress
        {
            get { return _totalProgress; }
            set
            {
                _totalProgress = value;
                RaisePropertyChanged(() => TotalProgress);
            }
        }

You will also need to declare the BooleanToVisiblityConverter:

    public class BooleanToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return (bool)value ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

Now there’s something to bind to. Next, set-up the messenger.

Messenger

You need to register the messenger object. I have a base model that I do this in, but anywhere before you use it is fine:

Mvx.LazyConstructAndRegisterSingleton<IMvxMessenger, MvxMessengerHub>();

(Warning: MVVM Cross specific)
A caveat here; if you use something like `RegisterType` to register the messenger object, that will also (appear to) work. However, it won’t actually work; it will create a fresh instance of the messenger object each time. If you decide to do it that way then you will need to inject the messenger object into the subscriber and publisher (it has to be the same instance).

Next, you need to create the message:

    class UpdateProgressMessage : MvxMessage
    {
        public UpdateProgressMessage(object sender, int currentProgress, int totalProgress) : base(sender)
        {
            CurrentProgress = currentProgress;
            TotalProgress = totalProgress;
        }

        public int CurrentProgress { get; set; }
        public int TotalProgress { get; set; }
    }

This isn’t much, but the important thing is the constructor. Okay, now let’s subscribe to that message at the start of the task:

_subscriptionTag = Messenger.Subscribe<UpdateProgressMessage>(UpdateProgress);

(A note on `_subscriptionTag` later)

`UpdateProgress` is a method defined like this:

        private void UpdateProgress(UpdateProgressMessage updateProgressMessage)
        {            
            LoadingProgress = updateProgressMessage.CurrentProgress;
            TotalProgress = updateProgressMessage.TotalProgress;
            IsLoading = (updateProgressMessage.CurrentProgress > 0 &amp;&amp; 
                updateProgressMessage.TotalProgress != updateProgressMessage.CurrentProgress);

        }

Notice that you accept the `UpdateProgressMessage`.

That note on `_subscriptionTag`

Firstly, _subscriptionTag is a class level variable, defined like this:

private MvxSubscriptionToken _subscriptionTag;

Once the task is complete you can unsubscribe. For MVVM Cross specifically, the subscription uses weak references, meaning that as soon as `_subscriptionTag` goes out of scope, it will be garbage collected, and will effectively unsubscribe (which is why it needs to be class level in the first place). Having said that, personally, I prefer things to happen in code when I tell them to, and not at some undefined and unpredictable point in the future; so, to unsubscribe:

Messenger.Unsubscribe<UpdateProgressMessage>(subscriptionTag);

Publish

Finally, just wire in the publish code. I have a helper method that instantiates the services and calls the game setup code, but this should work anywhere in the application:

Messenger.Publish<UpdateProgressMessage>(new UpdateProgressMessage(this, count, total));

Because `IMvxMessenger` is registered as a singleton, once you resolve it, you should be able to publish this from anywhere.

A Word About Threading

Okay, so this will all work, but where the task runs on the UI thread, you probably won’t see it update. Consequently, I start a new task for my long running process. Remember that if you do this, then subscribing to messages on the main thread may not work.

Conclusion

Okay, so now I have a progress bar for the set-up of my game. Like I said at the start, I think this should work for any architecture that supports IoC and messaging, but MVVM Cross seems to handle this very neatly.