Category Archives: MVVM Cross

MVVM Cross Upgrade to 4.2.2

Coming back to MVVMCross and trying to create a new project, I found that some of the documentation available for the new version (4.2.2 at the time of writing this) is no longer correct; for example, the ToDo file in the sample projects still looks like this:

The steps to get this Store UI working are:

1. Add a reference to your Core PCL project
2. Change App.Xaml.cs so that it creates a ‘new Setup(RootFrame)’ during its OnLaunched:

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var rootFrame = Window.Current.Content as Frame;

// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();

if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}

// Place the frame in the current Window
Window.Current.Content = rootFrame;
}

if (rootFrame.Content == null)
{
// When the navigation stack isn’t restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter

var setup = new Setup(rootFrame);
setup.Initialize();

var start = MvvmCross.Core.Mvx.Resolve();
start.Start();
}
// Ensure the current window is active
Window.Current.Activate();
}

3. For Windows 8 – Add a views folder and a view – xaml.cs and .xaml based on BasicPage – this
will add 5 files to the Common folder.
– Change the Common/LayoutAwarePage.cs inheritance to MvvmCross.WindowsStore.Views.MvxStorePage
– Change the Common/LayoutAwarePage.cs – remove the OnNavigatedTo and OnNavigatedFrom handlers
– Add some content for your Xaml – e.g.

5. For Windows 8.1 – Add a views folder and a view based on the BasicPage template
– In the .xaml.cs – remove public NavigationHelper NavigationHelper and all referencing code
– In the .xaml.cs – remove the OnNavigatedTo and OnNavigatedFrom handlers
– Add some content for your Xaml – e.g.

This document was very useful. I was looking specifically at the Babel project in the above sample; this won’t compile under MvvmCross 4.2.2. I’ve listed here everything I needed to do to make it.

Mvx has now been replaced with MvxSimpleIoCContainer.Instance

In App.xaml.cs:

var start = MvxSimpleIoCContainer.Instance.Resolve<IMvxAppStart>();

Is now:

var start = MvxSimpleIoCContainer.Instance.Resolve<IMvxAppStart>();
start.Start();

In App.cs:

        private void InitializeText()
        {
            var builder = new TextProviderBuilder();
            Mvx.RegisterSingleton<IMvxTextProviderBuilder>(builder);
            Mvx.RegisterSingleton<IMvxTextProvider>(builder.TextProvider);
        }

Is now is a separate plug-in by the looks of things:

mvvmcrossupgrade

The new code is:

        private void InitializeText()
        {            
            var builder = new TextProviderBuilder();
            MvxSimpleIoCContainer.Instance.RegisterSingleton<IMvxTextProviderBuilder>(builder);
            MvxSimpleIoCContainer.Instance.RegisterSingleton<IMvxTextProvider>(builder.TextProvider);
        }

Serialise and De-Serialise Helpers for ObservableCollection

I recently came across a need to serialise and de-serialise an ObservableCollection from an MVVMCross application. To achieve this, I created a couple of helper methods which I’d like to share.

Both use the MVVM Cross File plug-in.

Serialise

        public static void Serialise<T>(ObservableCollection<T> collection, string fileName)
        {
            var file = Mvx.Resolve<IMvxFileStore>();
            var fileData = file.OpenWrite(fileName);

            DataContractSerializer serializer = new
                        DataContractSerializer(typeof(ObservableCollection<T>));
            serializer.WriteObject(fileData, collection);
            fileData.Flush();
        }

De-serialise

        public static ObservableCollection<T> DeSerialise<T>(string fileName)
        {
            var file = Mvx.Resolve<IMvxFileStore>();
            if (!file.Exists(fileName))
                return null;

            var fileData = file.OpenRead(fileName);
            if (!fileData.CanRead || fileData.Length == 0)
                return null;

            DataContractSerializer serializer = new
                        DataContractSerializer(typeof(ObservableCollection<T>));

            ObservableCollection<T> data = (ObservableCollection<T>)serializer.ReadObject(fileData);
            return data;
        }

The Serialise method can be wrapped in an extension method, too:

        public static void Serialise<T>(this ObservableCollection<T> collection, string fileName)
        {
            Helpers.SerialiseHelper.Serialise(collection, fileName);
        }

Obviously, the `DeSerialise` cannot, as it would change the object that you are extending.

MVVM Cross – Stubbing out IMvxMainThreadDispatcher with RhinoMocks

This article describes how to stub out the IMvxMainThreadDispatcher, used by MVVM Cross, using Rhino Mocks.

Here is an excellent article on unit testing in MVVM Cross.

In it, Stuart Lodge describes a manual mock to replace the `IMvxMainThreadDispatcher`. I’ve recently started using RhinoMocks again, and the following is basically the manual mock described in the above article, in RhinoMocks:

var mainThreadDispatcher = MockRepository.GenerateMock<IMvxMainThreadDispatcher>();
mainThreadDispatcher.Stub(x => x.RequestMainThreadAction(Arg<Action>.Is.Anything)).WhenCalled(a => ((Action)a.Arguments.First())()).Return(true);
Mvx.RegisterSingleton<IMvxMainThreadDispatcher>(mainThreadDispatcher);            

As with many of my posts, this is predominantly for my own use; and, as with those other posts, I hope you’ll find this useful.

MVVM Cross – Creating a New Plug-in

This is quite a straightforward process, and well documented in several places – including here and here; and the sample that I used to create mine (and this tutorial) is here. However, I couldn’t find a step-by-step tutorial in a single place. So this is pretty much for my future self.

Disclaimer(s)

This only applies to Windows Store and Windows Phone. Although I believe the same process applies to iOS and Android.

The plug-in that I’m creating here will create a secondary tile on Windows Phone / Windows Store. However, this only covers the phone part, and doesn’t actually cover tile creation.

Create a Project

The project that I’m dealing with is a re-write of this application, using C# and MVVM Cross.

Obviously, your structure may be different, but the important thing is the Plugins folder at this stage; create a new portable project.

plugin1

Next, add the MVVMCross libraries:

plugin2

Interface and Plugin Loader

The portable class library above needs two files. Start with creating an interface:

    public interface ITile
    {
        Task<bool> CreateTile(string title);
    }

And next, the plug-in loader:

    public class PluginLoader : IMvxPluginLoader
    {
        public static readonly PluginLoader Instance = new PluginLoader();

        public void EnsureLoaded()
        {
            var manager = Mvx.Resolve<IMvxPluginManager>();
            manager.EnsurePlatformAdaptionLoaded<PluginLoader>();
        }
    }
}

Obviously, the next stage depends on your specific implementation. Mine depends entirely on the platform, so that’s all I need to do in the portable library.

Windows Phone

Create a new library project:

plugin3

plugin4

As before, you need to add the MVVM Cross Libraries, and a reference to the portable class above:

plugin5

The next stage is to implement your plug-in logic for the destination platform; in my case, this is logic to add a tile to Windows Phone:

    public class TilePlugin : ITile
    {
        public async Task<bool> CreateTile(string title)
        {
            // Create Tile code
        }
    }

Finally, just implement IMvxPlugin like this:

    public class Plugin : IMvxPlugin
    {
        public void Load()
        {
            Mvx.RegisterSingleton<ITile>(new TilePlugin());
        }
    }

Using the plug-in – the View Model

So, to all intents and purposes, the plug-in is now written (admittedly it only exists for Windows Phone, but that’s beside the point).

Next, it needs to be used; the first thing is to reference it.

plugin6

Here’s my logic to actually use the plug-in inside the view model:

    class SetupNewMailViewModel : BaseViewModel
    {
	. . . 
	
	        private void AddTile()
	        {
	            var tile = Mvx.Resolve<ITile>();
	            tile.CreateTile(MailHeading);
	        }
	    }
	

Using the plugin – Platform Specific

In the relevant project, a reference is needed:

plugin7

The only thing left to do for the platform is to add the bootstrap code:

public class TilePluginBootstrap : MvxPluginBootstrapAction<Tile.Plugin.PluginLoader> {    }

`MvxPluginBootstrapAction` signifies that the call to `MvxSetup` will call the BootstrapRunner for this plugin. Or, to put it another way, this magically makes MVVMCross aware of your new plugin for each platform.

Notes on Deployment

Above, I’ve basically manually added the reference to the correct project. This works fine when I’m working locally, but for an actual distributed plug-in, it’s NuGet that handles this.

MVVMCross – Overriding The Default Plugins

Following on from this post I discovered that I did, indeed, have a recursive reference in my game file. After a little searching, I found this excellent article on how to prevent this error, and to make the Json serializer behave rationally.

In MVVMCross, the code to serialize JSON is based on a standard plugin; it looks like this (or at least this is how I am saving my game):

public void Save()
{
    var jsonConv = Mvx.Resolve<IMvxJsonConverter>();            
    string text = jsonConv.SerializeObject(this);
    FileHelper.SaveGameFile(text);
}

The type is registered in App.cs like this:

Mvx.RegisterType<IMvxJsonConverter, MvxJsonConverter>();

What’s the fix?

The above article says the fix is this:

Settings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects

(it does go into more detail and I encourage everyone to read it).

So this is a change to MVVM Cross

Might be.

However, you can always use your own Serializer. One of the things that I’ve come to really like about MVVM Cross if that if you don’t like something, just write your own and override that specific thing. I stole this code, verbatim, from MVVM Cross, with the single exception of the one line above:

    public class MyJSonConverter : IMvxJsonConverter
    {
        private static readonly JsonSerializerSettings Settings;

        static KMJSonConverter()
        {
            Settings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize,
                Converters = new List<JsonConverter>
                        {
                            new MvxEnumJsonConverter(),
                        },
                DateFormatHandling = DateFormatHandling.IsoDateFormat,
                PreserveReferencesHandling = PreserveReferencesHandling.Objects
            };
        }

        public T DeserializeObject<T>(string inputText)
        {
            return JsonConvert.DeserializeObject<T>(inputText, Settings);
        }

        public string SerializeObject(object toSerialise)
        {
            return JsonConvert.SerializeObject(toSerialise, Formatting.None, Settings);
        }

        public object DeserializeObject(Type type, string inputText)
        {
            return JsonConvert.DeserializeObject(inputText, type, Settings);
        }
    }

Now, in App.cs, just change how it is registered:

Mvx.RegisterType<IMvxJsonConverter, MyJSonConverter>();
//Mvx.RegisterType<IMvxJsonConverter, MvxJsonConverter>();

Job done. It now works!

Detecting Recursion – JSON.Net Stack Overflow

Trying to save the game class of a game that I’m working on, I got a Stack Overflow error. I’m using MVVMCross, and my code looked like this:

        public void Save()
        {
            var jsonConv = Mvx.Resolve<IMvxJsonConverter>();
            string text = jsonConv.SerializeObject(this);
            FileHelper.SaveGameFile(text);
        }

The problem was that I got this error:

An unhandled exception of type ‘System.StackOverflowException’ occurred in mscorlib.dll

stackoverflow

I had a pretty good idea why. My game features a large population of “people”. Some of these people relate to each other; for example, they are parents, children, employers, etc. My guess was that I’d somehow messed up the creation routine and ended up with a recursive reference. (As it happened, far from messing it up, I hadn’t considered that a spouse relationship is recursive by definition!)

The Problem

The problem was that I had a starting population of 10,000 people. There are other ways to solve this: representing the reference between the classes as some kind of index, debugging the creation code, etc… However, I wanted to see if I could write a program to detect this.

My test program looks like this:

    class MyData
    {
        public MyData recursiveRef { get; set; }
        public string test { get;set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<MyData> data = new List<MyData>()
            {
                new MyData() {recursiveRef = null, test="non-recursive" },
                new MyData() {recursiveRef = null, test="recursive ref 1" },
                new MyData() {recursiveRef = null, test="recursive ref 2" },
                new MyData() {recursiveRef = null, test="recursive ref 3" },
                new MyData() {recursiveRef = null, test="recursive ref back to 1" }
            };
            data[1].recursiveRef = data[2];
            data[2].recursiveRef = data[3];
            data[3].recursiveRef = data[4];
            data[4].recursiveRef = data[1];

            SerialiseData(data);

            Console.ReadLine();
        }

        private static void SerialiseData(List<MyData> data)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings()
            {
                ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize,
                DateFormatHandling = DateFormatHandling.IsoDateFormat,
            };

            var ser = JsonConvert.SerializeObject(data, Formatting.None, settings);
            Console.Write(ser);
        }

Quickly running this will error with a stack overflow (to clarify, slowly running it will result in the same error!).

Detection Routine

Here’s the functions that I wrote to detect recursion:


        /// Itterate the list and call method CheckElement to analyse each element
        private static bool DetectRecursion<T>(IEnumerable<T> data)
        {
            Type typeT = typeof(T);

            foreach (T element in data)
            {
                if (CheckElement<T>(typeT, element, typeT, element))
                {
                    Console.WriteLine("Recursion found - exiting");
                    Console.ReadLine();
                    return true;
                }
            }

            return false;
        }

        private static List<object> recursionChain;

        /// Method recursively traverses the object to determine if there are any recursove references
        private static bool CheckElement<T>(Type baseType, T baseElement, Type checkType, object checkElement)
        {
            PropertyInfo[] piArr = checkType.GetProperties();
            foreach (PropertyInfo pi in piArr)
            {
                Console.WriteLine("Checking {0}, type {1}", pi.Name, pi.PropertyType);
                if (pi.PropertyType != baseType)
                    continue;

                var val = pi.GetValue(checkElement);
                if (val == null) continue;

                Console.WriteLine("Value for {0} is {1}", pi.Name, val.ToString());

                Type piType = val.GetType();

                if (piType == baseType && val.Equals(baseElement))
                {
                    return true;
                }

                if (CheckRecursionChain(val, piType)) return true;

                if (CheckElement<T>(baseType, baseElement, piType, val))
                {
                    Console.WriteLine("Successfully found recursive element {0}, {1}", piType.ToString(), val.ToString());
                    return true;
                }
            }

            return false;
        }

        /// Check the static recursion chain for a match
        private static bool CheckRecursionChain(object val, Type piType)
        {            
            if (Program.recursionChain != null && Program.recursionChain.Contains(val))
            {
                Console.WriteLine("Successfully found recursive element {0}, {1}", piType.ToString(), val.ToString());
                return true;
            }

            if (Program.recursionChain == null)
                Program.recursionChain = new List<object>();

            Program.recursionChain.Add(val);
            
            return false;
        }

This is, admittedly, not a simple or short piece of code; having said that, it doesn’t do anything complex, once you’re happy with the reflection, the rest is just a recursive tree.

To use this, simply call `DetectRecursion` in the above test program before calling serialize (or instead of).

...
DetectRecursion(data);

//SerialiseData(data);

...

MVVM Cross MvxStorePage Missing for 3.2.1

Recently I upgraded from MVVMCross 3.1.1 to 3.2.1 and everything broke. The reason was that suddenly, the MvxStorePage was unavailable.

After downloading the latest MVVMCross source, I found it safe and well:

namespace Cirrious.MvvmCross.WindowsStore.Views
{
    public abstract class MvxStorePage
        : Page
          , IMvxStoreView
    {

So – the page was still there in Cirrious.MvvmCross.WindowsStore.Views, but NuGet was no longer referencing its assembly:

Cirrious.MvvmCross.WindowsStore.dll

I posted this question.

And prompted by Stuart’s comments, I revisited the MVVMCross source. The confusing thing here is that the MvxStorePage has not been moved; it’s just been ignored and replaced by the MvxWindowsPage; here’s the new version:


namespace Cirrious.MvvmCross.WindowsCommon.Views
{
    public abstract class MvxWindowsPage
        : Page
          , IMvxWindowsView
    {

I’m sure many people knew this; but I wasn’t one of them.

Creating a Shared Project in WPF

The new thing for VS 2013 is Universal Apps. They allow you to create a Win 8 and Phone app with shared code. But what if you’re writing LOB apps in WPF, maybe using MVVM? You may have a Winforms app and a XAML app, and want to share code; or have two WPF apps that share a core code base, and some screens.

This post walks through creating a sample shared app.

Create WPF App

I’ll just cover WPF in this post. Start by creating a new application:

sharedcode1

Okay, so we have a WPF application (as you might already have). How to create a shared project? Well, the bad news is: you can’t; at least as far as I’m aware (please, please, please let me know in the comments if you know this to be false!).

So, if you can’t create a shared application without a universal one then create a universal one in the same solution:

sharedcode2

This creates a shared app with a reference from Windows 8.1 and Windows Phone 8.1:

sharedcode3

Now, what comes next might feel like a hack… and there’s a good reason for that!

Have a look in the Win 8 app csproj:

sharedcode4

Copy this into the csproj file of the WPF project (remember the path may be different – although in this case, are not):

sharedcode6

The important thing here is the `Label`. However, you’re most likely to get the path wrong. If you do then when you update the project in VS it will fail to load and give you an error message telling you where it’s trying to find the shared project. Having done this a couple of times, my advice is have this error message up, and try to navigate to the path in Windows Explorer: you should see where you went wrong quickly enough.

Adding stuff to the shared project

Start by adding a page to the shared project so that we can see that it works:

sharedcode7

Make it obvious so that you can recognise it:

sharedcode8

Okay, so you’ve now created a shared project, added some shared content, and referenced it from your main project. Next, tidy up by removing Windows 8 and Phone 8 apps and add a second WPF app:

sharedcode9

To make sure that this is, in fact, a shared project, create and make the same change to the second project and then modify each to call the shared page; e.g.:

    private void Button_Click(object sender, RoutedEventArgs e)
        {
            TestPage test = new TestPage();
            Window w = new Window();
            w.Content = test;
            w.Show();

        }

Then run both projects:

sharedcode10

Notes, and using this in an MVVM architecture

Okay – some things that are worth noting here. The main thing is this: the shared code is just that – shared. If you call something like:

typeof(TestPage).Assembly

You will get the assembly of the running application. Effectively, you’ve created a kind of link between the projects, without the messiness of actually creating a link. The consequences of this are that you must ensure that code in the shared project only has dependencies that can be resolved in ALL the projects that include the shared project.

MVVMCross

I’ve tried this on MVVM Cross using two projects and sharing XAML files; and it works. MVVM Cross looks in the current assembly for a `MyView`, when you navigate to a `MyViewModel`. It will find it providing all your projects reference the shared project and you do not try to re-implement the view.

To clarify:

– Creating a shared project between Winforms and WPF that shares a XAML file will most probably not work (admittedly I haven’t tried it).

– Creating a shared project for two WPF projects and copying MyView.xaml into the shared project, leaving the original intact will cause MVVM Cross to fail to resolve the page (because it doesn’t know which one you want).

Creating and Binding to a 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.

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.