Tag Archives: c#

Creating and Binding to a Custom User Control in MVVM Cross

While creating my game, I recently came across the problem of navigation. This post describes how to create a custom user control and react to the event inside.

The usual disclaimer still applies here; although this is an MVVM Cross post, the contents of it should be applicable for any MVVM Framework or, in fact, any XAML binding at all.

User Control

The user control that I’m going to use is simply a navigation bar to appear at the top of each screen.

The XAML for the user control is here:

<UserControl
    x:Name="NavigationControlRoot">
    
    <Grid DataContext="{Binding ElementName=NavigationControlRoot}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Button Content="Home" Grid.Column="0" Command="{Binding HomeClick}" />
        <Button Content="Back" Grid.Column="1" Command="{Binding BackClick}" />
    </Grid>
</UserControl>

So, I’ve got two commands, binding to the code behind. The key point here is that the root control (grid) binds to the DataContext of the user control – effectively this binds it to the containing DataContext. Here’s the code behind:


    public sealed partial class NavigationPanel : UserControl
    {
        public static DependencyProperty BackCommandProperty =
            DependencyProperty.Register(
                "BackClick",
                typeof(ICommand),
                typeof(NavigationPanel),
                new PropertyMetadata(null));

        public static DependencyProperty HomeCommandProperty =
            DependencyProperty.Register(
                "HomeClick",
                typeof(ICommand),
                typeof(NavigationPanel),
                new PropertyMetadata(null));

        public NavigationPanel()
        {
            this.InitializeComponent();
        }
        
        public ICommand BackClick
        {
            get
            {
                return (ICommand)GetValue(BackCommandProperty);
            }

            set
            {
                SetValue(BackCommandProperty, value);
            }
        }

        public ICommand HomeClick
        {
            get
            {
                return (ICommand)GetValue(HomeCommandProperty);
            }

            set
            {
                SetValue(HomeCommandProperty, value);
            }
        }        
    }

So, you’ve now exposed two dependency properties and bound them to the XAML in the user control.

Host App

Here’s the relevant XAML for the hosting view:

<controls:NavigationPanel BackClick="{Binding BackClickCommand}"                                  
                                  HomeClick="{Binding HomeClickCommand}"/>

And that just binds to the ViewModel as you would expect.

        private IMvxCommand _homeClickCommand;
        public IMvxCommand HomeClickCommand
        {
            get
            {
                if (_homeClickCommand == null)
                {
                    _homeClickCommand = new MvxCommand(() => GoHome());
                }
                return _homeClickCommand;
            }
            set
            {
                _homeClickCommand = value;
            }
        }

        private void GoHome()
        {
            ShowViewModel<MainViewModel>();
        }

For me, this is in a base view model, so it responds to the same command in every view.

Conclusion

I think the final version of this code will interact with an IMvxPresenter in some way, which may make another post.

Updating a View Model from Inside a Collection

My last post suggested a concept of having a `Selectable` Model, which effectively wraps a model in a class with a generic item and an `IsSelected` property. This does, however, present a slight issue. What if you want to update the view model, based on the item being selected, or de-selected?

Say, for example, that from my previous post, you had a property on the Person class called Wages, and wanted to display the total wages of all the selected people. You would have defined `TotalCostSummary` in the ViewModel, and bound it in the View.

My solution is to pass a delegate into the Selectable item. Here’s how I did it (this doesn’t really make any sense without referring back to the first post).

SelectableItem Model

In the `SelectableItem`, define a new property like so:

        private Action _updateMethod = null;
        public Action IsSelectedChangedMethod
        {
            get { return _updateMethod; }
            set
            {
                _updateMethod = value;
            }
        }

And change `IsSelected` to looks like this:

        private bool _isSelected;
        public bool IsSelected
        {
            get { return _isSelected; }
            set
            {
                _isSelected = value;                
                RaisePropertyChanged();
                
                if (_updateMethod != null)
                    _updateMethod();
            }
        }

ViewModel

        private void UpdateTotalCost()
        {
            _summary = SelectablePeople.Where(a => a.IsSelected).Sum(s => s.Item.Wages);
            RaisePropertyChanged(() => TotalCostSummary);
        }

Next, change the code to define the list:

List<Person> population = GetPeople();
SelectablePeople = new ObservableCollection<SelectableItem<Person>>(population
	.Select(n => new SelectableItem<Person>() 
	{ 
		Item = n, IsSelected = false, IsSelectedChangedMethod = (() => UpdateTotalCost())  
	}).ToList());

Conclusion

The net effect is that the changes now made inside the model can bubble up to the ViewModel, but the separation of the two has been maintained.

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:

<views:MvxStorePage
    x:Class="MyApp.Views.MyView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyApp.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:views="using:Cirrious.MvvmCross.WindowsStore.Views"

The second thing is to remember that MVVMCross uses the following convention it identify the View: View Model name with `Model` removed.

So, effectively, For `MyViewModel`, it’s looking for a class that inherits from `MvxStorePage` (in the case of Windows 8) which is called `MyView`.

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 && 
                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.

Unit Testing Methods With Random Elements (in MVVM Cross)

Okay, quick spoiler for this: you can’t. You can’t, not really; obviously, you can write the test, but unit tests should be predictive, and a random element should not.

Solution

I imagine there are a few ways of solving this. The way shown in this post is specific to MVVM cross, but should work with any system that uses an IoC container. In brief, we’re simply going to mock out the system Random class.

How?

Well, since System.Random is the domain of Microsoft, we’ll start with a wrapper; and since this is MVVM Cross, we’ll make it a service:

    class RandomService : IRandomService
    {
        private static Random _rnd = null;

        public virtual int SelectRandomNumber(int max)
        {
            if (_rnd == null)
            {
                _rnd = new Random();
            }

            return _rnd.Next(max);
        }
    }

Couple of notes on this:
1. I haven’t posted the interface but it’s just the one method.
2. The reason for the Random class being static is that the random seed is taken from the system clock, meaning that if you call this in quick succession, there is a possibility that you would get the same number returned.
3. This is not thread safe.

Okay – all that out of the way, the code is pretty basic. Now let’s call it:

        public static T SelectRandomElement<T>(this IEnumerable<T> enumeration)
        {
            var service = Mvx.Resolve<IRandomService>();            
            int idx = service.SelectRandomNumber(enumeration.Count() + 1);

            return enumeration.ElementAt(idx);
        }

Right, so you’ll recognise the extension method from the last post, but now it retrieves the instance of the random service; here’s where we register that:

        protected override void InitViewModel()
        {
            Mvx.ConstructAndRegisterSingleton<IRandomService, RandomService>();
        }

You can actually register it anywhere you like… before it’s actually called.

Okay, so now we should have unchanged functionality; everything works as before.

The Unit Tests

The first task here is to create the mock RNG:

    class MockRandomService : IRandomService
    {
        static int _lastNumber = 0;

        public int SelectRandomNumber(int max)
        {            
            if (_lastNumber < max)
                return ++_lastNumber;
            else
            {
                _lastNumber = 0;
                return _lastNumber;
            }                
        }
    }

This not allows me to determine what the next random number will be.

MVVM Cross Unit Testing

To set-up a test for MVVM Cross using the IoC container, you need to add some additional libraries to the test project first:

mvvmtest

This will add Cirrious.MccmCross.Test.Core:

refs

And that is important, because it allows you to declare your test class as follows:

    [TestClass]
    public class ExtensionMethodTests : MvxIoCSupportingTest
    {

Inheriting from MvxIoCSupportingTest allows you to call base.Setup(), which prevents the IoC container from crashing when you call it in a test. Here’s the full unit test code:

    [TestClass]
    public class ExtensionMethodTests : MvxIoCSupportingTest
    {
        [TestMethod]
        public void TestSelectRandomElement()
        {
            base.Setup();
            
            Mvx.ConstructAndRegisterSingleton<IRandomService, MockRandomService>();

            List<int> testCollection = new List<int>();

            testCollection.Add(1);
            testCollection.Add(3);
            testCollection.Add(5);
            testCollection.Add(7);
            testCollection.Add(9);

            // Cycle through all elements
            for (int i = 0; i <= 5; i++)
            {
                int e = testCollection.SelectRandomElement();
                Assert.AreNotEqual(e, 0);
            }
        }

        [TestMethod]
        public void TestSelectRandomElementPredicate()
        {
            base.Setup();

            Mvx.ConstructAndRegisterSingleton<IRandomService, MockRandomService>();

            List<int> testCollection = new List<int>();

            testCollection.Add(1);
            testCollection.Add(3);
            testCollection.Add(5);
            testCollection.Add(7);
            testCollection.Add(9);

            // Cycle through all elements
            for (int i = 0; i <= 5; i++)
            {
                int e = testCollection.SelectRandomElement(n => n < 2);
                Assert.AreNotEqual(e, 1);
            }
            
        }

    }
}

Conclusion

So, I now have a custom RNG and unit tests that will tell me what happens when I call the method for each element. Obviously these tests are not exhaustive, but they are deterministic.