MVX=0 : A first MvvmCross Application (MVX+1 days of MvvmCross)

MVX=0 : A first MvvmCross Application (MVX+1 days of MvvmCross)

[Repost: Apologies for those who have already read this but there were some issues with the link generated for the previous post, so I’ve reposted it]

Updated 16/4/2018: Reference to MvvmCross have been updated to v6.0.0

Yes, this is going to be a sequence of posts reworking the infamous N+1 series that Stuart Lodge did starting almost exactly 5 years ago. As we approach the 5 year anniversary of these posts I thought it only fitting to cover this series again as a way of introducing MvvmCross v6 which will be released very shortly has just been released. Unlike the original series that were YouTube videos accompanied by blog posts, this series will only contain the posts, mainly because I find generating videos to be time consuming. Anyhow, here goes:

We’ll start by creating a Blank Solution.

image_thumb4_thumb

Into the solution we’ll add a Core Library that will contain an App class and our first ViewModel:

  1. Add a Class Library (.NET Standard) called FirstDemo.Core
    image_thumb3_thumb
  2. Add a reference to MvvmCross NuGet package (v6.0.0-beta.8 v6.0.0 at time of writing)
  3. Rename the default Class1.cs to App.cs, and allow Visual Studio to rename class to App
  4. Change App to inherit from MvxApplication
  5. Add a folder, ViewModels, and add a class called FirstViewModel.
  6. Change FirstViewModel to inherit from MvxViewModel
  7. Add logic to FirstViewModel to include FirstName, LastName and a calculated FullName
  8. Override Initialize method in App to call RegisterAppStart, specifying FirstViewModel as the startup ViewModel

Let’s start with a Universal Windows Platform UI:

  1. Add a Blank App (Universal Windows) called FirstDemo.Uwp
    image_thumb6_thumb
  2. Make sure Minimum and Target versions are set to at least the Fall Creators Update so that it supports .NET Standard 2.0
    image_thumb8_thumb
  3. Update NuGet package Microsoft.NETCore.UniversalWindowsPlatform to the latest stable version (6.0.8 at time of writing)
  4. Add a reference to MvvmCross NuGet package
  5. Add reference to FirstDemo.Core project
  6. Add a help class ProxyMvxApplication to the FirstDemo.Uwp project – this is a proxy class to compensate for the lack of generics support in XAML
  7. public abstract class ProxyMvxApplication: MvxApplication<MvxWindowsSetup<Core.App>, Core.App> { }

  8. Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication
  9. Remove all code in App.xaml.cs other than the constructor which should contain a single call to InitializeComponent
  10. Delete MainPage.xaml and MainPage.xaml.cs
  11. Add a Views folder, and  add a FirstView based on the Blank XAML page template
  12. Change FirstView.xaml and FirstView.xaml.cs to inherit from MvxWindowsPage
  13. Add some TextBoxes and a TextBlock to the FirstView, complete with databinding
  14. Hit F5 and run the application (you may have to set the FirstDemo.Uwp project as the startup project and make sure it’s set to build and deploy using the Configuration Manager)

Next let’s add the Android UI:

  1. Add a Android App (Xamarin) called FirstDemo.Droid
    image_thumb10_thumb
  2. Select the Blank App template, and the minimum Android version
  3. Update the Xamarin.Android.Support.Design NuGet package (at time of writing the latest is 27.0.2)
  4. Update the Android version to Use Latest Platform
    image_thumb12_thumb
  5. Add a reference to MvvmCross NuGet package
  6. Add a reference to MvvmCross.Droid.Support.V7.AppCompat package
  7. Add reference to FirstDemo.Core project
  8. Add a new class, MainApplication, that inherits from MvxAppCompatApplication
    public class MainApplication : MvxAppCompatApplication<MvxAppCompatSetup<App>, App>
  9. Rename MainActivity.cs to SplashScreen.cs and let Visual Studio rename the class
  10. Rename activity_main.axml to SplashScreen.axml, and adjust layout to indicate application loading
  11. Adjust SplashScreen class to inherit from MvxSplashScreenAppCompatActivity and set NoHistory to true (since we don’t want the user to be able to press the back button and go back to the splash screen)
  12. [Activity(Label = “@string/app_name”, Theme = “@style/AppTheme”, MainLauncher = true, NoHistory = true)]
    public class SplashScreen : MvxSplashScreenAppCompatActivity

  13. Add a folder, Views, and add a new Activity, FirstView.cs
    1. Add a new Android Layout to the Resources/Layout folder, FirstView.axml, with a couple of EditText and a TextView, all data bound using MvxBind
    2. You may run into an error: “error XA4210: You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute.” If you do, you just need to Add Reference to Mono.Android.Export (search in the Add Reference dialog).
    3. Set the startup project to be FirstDemo.Droid and press F5 to run the application

    Lastly, let’s add the iOS UI:

    1. Add an iOS App (Xamarin) called FirstDemo.iOS
      image_thumb2_thumb
    2. Select the Blank App template, Universal devices support and Minimum iOS Version of 11.2
      1. Add a reference to MvvmCross NuGet package
        1. Add reference to FirstDemo.Core project
        2. Update AppDelegate class to inherit from MvxApplicationDelegate
          public class AppDelegate : MvxApplicationDelegate<MvxIosSetup<App>, App>
        3. Add an Empty Storyboard, called Main.storyboard, to the root of the project
        4. Add a ViewController to the Main.storyboard using the designer and set the Class and Storyboard ID to FirstView (also make sure the “User Storyboard ID” checkbox is set to true)
        5. Move the generated FirstView.cs and FirstView.designer.cs files (from the previous step) into a new folder called Views, and adjust the namespace of the FirstView class to FirstView.iOS.Views
        6. Add two UITextField and a UILabel to the FirstView ViewController using the Main.storyboard designer (make sure each element has a Name set so it can be referenced from code)
        7. Update the FirstView class to inherit from MvxViewController
          [MvxFromStoryboard(“Main”)]
          public partial class FirstView : MvxViewController<FirstViewModel>
        8. Add logic to FirstView to enable databinding using the CreateBindingSet extension method
        9. Set the startup project to be FirstDemo.Droid and press F5 to run the application
          Update 16/4/2018: For some reason the iOS App (Xamarin) project template still uses a package.config. During the update to the stable v6.0.0 package the package.config file in FirstDemo.iOS was removed, the reference in FirstDemo.iOS.csproj to MvvmCross was manually removed and the following ItemGroup added:
          <ItemGroup>
             <PackageReference Include=”MvvmCross” Version=”6.0.0″ />
          </ItemGroup>

        The final code is available at https://github.com/nickrandolph/MvxPlus1DaysOfMvvmCross/tree/master/Mvx-00-FirstDemo

        To get this to work I would suggest running the latest Visual Studio for Mac or PC. Hit me up on Twitter or Slack if you have any issues following the steps or running the samples.

        Making MvvmCross with Xamarin Forms Friction Free

        Making MvvmCross with Xamarin Forms Friction Free

        My last two posts (part 1 and part 2) outlined all the steps necessary to get a new Xamarin Forms with MvvmCross project setup. What I thought was going to be a simple post ended up being much longer due to all the unnecessary steps to setup both Xamarin Forms and MvvmCross. I’ve recently been contributing a little to MvvmCross and one of my concerns with it is that there are just way to many things that you need to get right in order to get it to work nicely with Xamarin Forms. If you don’t follow one of the introductory posts, such as the one provided by Martjin van Dijk, you’ll probably start hacking around with the numerous extension points in order to get it to work. I spent time over the last day seeing if I could reduce this initial friction to getting started.

        When you adopt a framework, or any library for that matter, you do so to reduce the need to reinvent the wheel – there’s no point in recreating, or creating something new, if there are existing solutions available. However, I’m of the opinion that you should be able to determine how much the framework influences the way that your code is structured. You should only have to modify your code if the framework offers a clear advantage. If we do a quick review of some of the changes required to take advantage of MvvmCross in our Xamarin Forms project you’ll see that quite a few of these are artificial requirements, mandated by the current MvvmCross implementation, rather than for any specific need. Here are just a couple:

        • App needs to inherit from MvxFormsApplication – this doesn’t add anything other than a couple of events, so unless you want to use those events, this is unnecessary
        • All pages need to inherit from the Mvx equivalent (eg MvxContentPage instead of ContentPage) – the Mvx equivalent expose a ViewModel property which can be useful but is not required in order to take advantages of data binding to the corresponding ViewModel since all Forms elements have a BindingContext that’s used for this purpose. The actual requirement here is for views/pages to implement IMvxView but unless you need the ViewModel property this shouldn’t be a requirement.
        • You need to create a class that inherits from MvxApplication which can do things like register services but most importantly defines what the starting ViewModel is going to be. This is kind of unnecessary if the only thing that it’s doing is defining the starting ViewModel, although I do understand the desire to have the starting ViewModel defined somewhere that is independent of the head projects.
        • All ViewModels need to inherit from MvxViewModel or implement IMvxViewModel – again this is somewhat unnecessary since ViewModels should just be a regular class. Now I do agree that in most cases your ViewModel is likely to implement INotifyPropertyChanged, so this additional requirements isn’t a massive addition but needless to say it shouldn’t be a requirement.

        Ok, so after a bit of experimenting without modifying MvvmCross or MvvmCross.Forms (ie I’m just using the NuGet packages) what I came up with is BuildIt.MvvmCross.Forms (currently in prerelease!) which is a NuGet package which adds a couple of helper classes to get you going just that bit quicker. Here are the steps to get started using BuildIt.MvvmCross.Forms:

        Start by following the steps outlined in part 1 – this will give you a Xamarin Forms project that’s completely up to date. I’ll call this project LowFriction

        Next, follow the early steps in part 2 to add an additional project for your ViewModels, LowFriction.Core, and subsequently add references to MvvmCross (to all projects) and MvvmCross.Forms (to all projects except the Core project).

        Add a reference to the BuildIt.MvvmCross.Forms NuGet package to all projects except the Core project. A primary requirement here is that the Core project should not have a reference to the view technology, which in this case is Xamarin Forms – if you find yourself adding a reference (directly or otherwise) to Xamarin Forms to your Core project, you’ve done something wrong and you should rethink the decisions that led you to that point.

        You still need to change App.xaml to inherit from MvxFormsApplication – I couldn’t find a work around this requirements

        Your pages do not need to change to implement iMvxView – MainPage inherits from ContentPage

        In your Core project you will need to create ViewModels that map to your pages, and they need to implement iMvxViewModel – again I couldn’t find a work around for this requirement. MainViewModel inherits from MvxViewModel.

        In your Core project you do not  need to create a class that inherits from MvxApplication – we’ll come to this later but essentially BuildIt.MvvmCross.Forms has class called TypedMvxApplication whose type parameter is the starting ViewModel. If you do want to extend the MvxApplication you can still create your own application but I would recommend using TypedMvxApplication as a starting point

        UWP

        In App.xaml.cs replace

        Xamarin.Forms.Forms.Init(e);

        with

        var setup = new SetupFromViewModel<MainViewModel, LowFriction.App>(rootFrame, e);
        setup.Initialize();

        You can see here that the SetupFromViewModel class accepts the starting ViewModel as a parameter. If you’d prefer to define the starting ViewModel in the Core project I recommend defining a class that inherits from TypedMvxApplication, specify the starting ViewModel as the type parameter, and then use the SetupFromApplication class in App.xaml.cs.

        Change MainPage to inherit from BuildIt.MvvmCross.Forms.UWP.MvxFormsWindowsPage (I also updated the layout of MainPage to show some data coming from databinding from the ViewModel, similar to what I did in my previous post)

        Change the MainPage constructor to

        public MainPage()
        {
             this.InitializeComponent();


            MvxLoadApplication();
        }

        Android

        Change MainActivity to inherit from CustomMvxFormsAppCompatActivity<SetupFromViewModel<MainViewModel, LowFrictionApp>, MainViewModel>

        Comment out the Xamarin Forms init code:

        //global::Xamarin.Forms.Forms.Init(this, bundle);
        //LoadApplication(new App());

        iOS

        Change AppDelegate to inherit from CustomMvxFormsApplicationDelegate

        Change FinishedLaunching

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
             Window = new UIWindow(UIScreen.MainScreen.Bounds);


            var setup = new SetupFromViewModel<MainViewModel, App>(this, Window);
             setup.Initialize();


            MvxLoadApplication();


            Window.MakeKeyAndVisible();


            //global::Xamarin.Forms.Forms.Init();
             //LoadApplication(new App());


            return base.FinishedLaunching(app, options);
        }

        And we’re done! Build and run on each platform and you should be good to go.

        As you can see there are significantly fewer steps involved in getting started, and few additional classes to be created. I do note that there is still room for improvement and I feel that as frameworks go MvvmCross has been developed with extensibility in mind – which is why I was able to streamline the getting started experience so much.

        Getting Started: MvvmCross with Xamarin Forms (Part 2)

        Getting Started: MvvmCross with Xamarin Forms (Part 2)

        In my previous post I covered the first part of this post on Getting Started with MvvmCross and Xamarin Forms where I covered the initial steps in getting a new Xamarin Forms project started. In this post I’m going to continue on and show how you can configure a Xamarin Forms solution to make use of MvvmCross.

        Before I get started with MvvmCross I’m going to add a new project which will contain all my ViewModels. Whilst not entirely necessary, particularly with Xamarin Forms where the views/pages are in a .NET Standard library, it’s good practice to completely separate your ViewModels away from the views/pages to avoid any accidental interdependencies forming. I’ll add a new project based on the .NET Standard class library template.

        image_thumb11[1]

        For this library I’m going to adjust the .NET Standard version back to 1.0 – I prefer to start with a low .NET Standard version and increase it only when I need to take advantage of features in the higher versions. This ensures that the library can be referenced by the widest set of targets platforms.

        image_thumb11

        I’ll add a reference to the new project to each of the other projects in the solution.

        image_thumb31

        The next step is to add a reference to the MvvmCross NuGet package. Currently MvvmCross is still distributed as a set of Portable Class Libraries and if we attempt to add the NuGet package to either our MvvmcrossGettingStarted or MvvmcrossGettingStarted.Core projects, we’ll get an error as they’re both .NET Standard library. What’s annoying about this is that the MvvmCross PCLs are fully compatible with .NET Standard, meaning that it should be possible to add a reference to them. Unfortunately Visual Studio isn’t clever enough to be able to resolve this, and as such we need to adjust the csproj files for both projects before attempting to add a reference to MvvmCross.

        Add the following line into the first PropertyGroup of the csproj files for both MvvmcrossGettingStarted or MvvmcrossGettingStarted.Core projects. One saving grace is that it’s now easy in Visual Studio to edit a csproj by right-clicking on the project and selecting “Edit <project name>.csproj”.

        <PackageTargetFallback>$(PackageTargetFallback);portable-net45+win8+wpa81</PackageTargetFallback>

        Eg.

        image_thumb23

        Next we can go ahead and add a reference to MvvmCross to all our projects. Right-click on the solution node in Solution Explorer and select Manage NuGet Packages for Solution, and then search for mvvmcross. Select the most recent stable version of MvvmCross (this image is a little old as the version is at 5.6.3 at time of writing this)

        image_thumb9

        In addition to the main MvvmCross package, we also want to add in the Xamarin Forms support library, MvvmCross.Forms. Note that we do not add this to the MvvmcrossGettingStarted.Core project – this is the separation of concerns we setup at the beginning of this post to ensure there is no dependencies on the viewing technology within our ViewModels.

        image_thumb21

        Now that we have added the references to MvvmCross there are a bunch of small changes we need to apply to our application in order to get it all up and running. We’ll start in the MvvmcrossGettingStarted.Core project where we need to create two classes.

        The first class we’ll create inherits from MvxApplication and is used to setup the application within the ViewModel world. MvvmCross has an opinionated navigation model whereby navigation is defined at a ViewModel level, and simply implemented at a View level. As such the MvxApplication class, in this case GettingStartedApplication, defines the first ViewModel for the application.

        public class GettingStartedApplication : MvxApplication
        {
             public override void Initialize()
             {
                 RegisterNavigationServiceAppStart<MainViewModel>();
             }
        }

        The second class is the ViewModel that matches the first view or page of the application. MainPage was created back when we created the Xamarin Forms application, so we’ll create a class called MainViewModel. Whilst you can override the default view to viewmodel mapping in MvvmCross, it’s preconfigured to align views and viewmodels based on a naming convention. I typically stick with XXXViewModel and XXXPage but XXXView is also supported out of the box.

        In this case MainViewModel exposes a simple property that we’ll data bind to later to show that the Page and ViewModel have been glued together correctly.

        public class MainViewModel: MvxViewModel
        {
             public string WelcomeText => “Welcome to my data bound Xamarin Forms + MvvmCross application!”;
        }

        Now we’ll switch over to the MvvmcrossGettingStarted project and make some changes to both the App and MainPage classes.

        In the App.xaml, we need to change the root element to reference MvxFormsApplication

        <?xml version=”1.0″ encoding=”utf-8″ ?>
        <mvx:MvxFormsApplication http://xamarin.com/schemas/2014/forms"”>http://xamarin.com/schemas/2014/forms”
                             http://schemas.microsoft.com/winfx/2009/xaml"”>http://schemas.microsoft.com/winfx/2009/xaml”
                            
                            
        x:Class=”MvvmcrossGettingStarted.App”>
             <Application.Resources>
             </Application.Resources>
        </mvx:MvxFormsApplication>

        And in App.xaml.cs, remove the inheritance – the Microsoft templates insist on including the inheritance in both the xaml and xaml.cs files which is quite unnecessary and should be removed.

        public partial class App
        {
             public App()
             {
                 InitializeComponent();
             }
        }

        We need to make a similar change to MainPage.xaml, changing the root element to MvxContentPage. We’ll also change the Label to use data binding to return the WelcomeText property from the MainViewModel.

        <?xml version=”1.0″ encoding=”utf-8″ ?>
        <mvx:MvxContentPage http://xamarin.com/schemas/2014/forms"”>http://xamarin.com/schemas/2014/forms”
                             http://schemas.microsoft.com/winfx/2009/xaml"”>http://schemas.microsoft.com/winfx/2009/xaml”
                            
                            
                            
        x:Class=”MvvmcrossGettingStarted.MainPage”>
             <Label Text=”{Binding WelcomeText}”
                    VerticalOptions=”Center”
                    HorizontalOptions=”Center” />
        </mvx:MvxContentPage>

        Again, remove the inheritance specified in MainPage.xaml.cs

        public partial class MainPage
        {
             public MainPage()
             {
                 InitializeComponent();
             }
        }

        The next step involves adding a Setup class to each of the head projects, and then creating an instance of the Setup class to invoke MvvmCross when the application starts up.

        UWP

        The UWP Setup inherits from MvxFormsWindowsSetup and unlike the Android and iOS Setup classes, the UWP Setup needs to override the default log behaviour by setting the log provider type to None and then creating an instance of the EmptyVoidLogProvider  (the implementation of this is coming up soon) – this should be fixed in a future MvvmCross version.

        public class Setup : MvxFormsWindowsSetup
        {
             public Setup(Frame rootFrame, LaunchActivatedEventArgs e) : base(rootFrame, e)
             {
             }


            protected override MvxLogProviderType GetDefaultLogProviderType() => MvxLogProviderType.None;


            protected override IMvxLogProvider CreateLogProvider() => new EmptyVoidLogProvider();


            protected override IEnumerable<Assembly> GetViewAssemblies()
             {
                 return new List<Assembly>(base.GetViewAssemblies().Union(new[] { typeof(MvvmcrossGettingStarted.App).GetTypeInfo().Assembly }));
             }


            protected override MvxFormsApplication CreateFormsApplication() => new MvvmcrossGettingStarted.App();


            protected override IMvxApplication CreateApp() => new Core.GettingStartedApplication();
        }

        Now in App.xaml.cs we need to replace

        Xamarin.Forms.Forms.Init(e);

        with

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

        And in Main.xaml.cs replace

        LoadApplication(new MvvmcrossGettingStarted.App());

        with

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


        var presenter = Mvx.Resolve<IMvxFormsViewPresenter>() as MvxFormsUwpViewPresenter;
        LoadApplication(presenter.FormsApplication);

        Finally, we need to add the EmptyVoidLogProvider

        public class EmptyVoidLogProvider : IMvxLogProvider
        {
             private readonly EmptyVoidLog voidLog;


            public EmptyVoidLogProvider()
             {
                 voidLog = new EmptyVoidLog();
             }


            public IMvxLog GetLogFor<T>()
             {
                 return voidLog;
             }


            public IMvxLog GetLogFor(string name)
             {
                 return voidLog;
             }


            public IDisposable OpenNestedContext(string message)
             {
                 throw new NotImplementedException();
             }


            public IDisposable OpenMappedContext(string key, string value)
             {
                 throw new NotImplementedException();
             }


            public class EmptyVoidLog : IMvxLog
             {
                 public bool Log(MvxLogLevel logLevel, Func<string> messageFunc, Exception exception = null, params object[] formatParameters)
                 {
                     return true;
                 }
             }
        }

        Now when we build and run the UWP project we can see that the MainPage is shown and is data bound to the MainViewModel.

        image

        iOS

        The iOS Setup is the simplest out of the three platforms.

        public class Setup : MvxFormsIosSetup
        {
             public Setup(IMvxApplicationDelegate applicationDelegate, UIWindow window)
                 : base(applicationDelegate, window)
             {
             }


            protected override IEnumerable<Assembly> GetViewAssemblies()
             {
                 return new List<Assembly>(base.GetViewAssemblies().Union(new[] { typeof(MvvmcrossGettingStarted.App).GetTypeInfo().Assembly }));
             }


            protected override MvxFormsApplication CreateFormsApplication() => new MvvmcrossGettingStarted.App();


            protected override IMvxApplication CreateApp() => new Core.GettingStartedApplication();
        }

        In AppDelegate we need to change the inheritance from  global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate to MvxFormsApplicationDelegate and change the FinishedLaunching method as follows:

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
             Window = new UIWindow(UIScreen.MainScreen.Bounds);


            var setup = new Setup(this, Window);
             setup.Initialize();


            var startup = Mvx.Resolve<IMvxAppStart>();
             startup.Start();


            LoadApplication(setup.FormsApplication);


            Window.MakeKeyAndVisible();


            return base.FinishedLaunching(app, options);
        }

        Now we’re good to build and run the iOS project

        image

        Android

        Lastly, add Setup to the Android project. Note this is slightly different from the iOS and UWP projects in that the GetViewAssemblies method excludes the assembly for the Android head project. This is to avoid the MainActivity being added as a view, that based on our naming convention would match with MainViewModel giving a duplicate when attempting to resolve the View that should be rendered.

        public class Setup : MvxFormsAndroidSetup
        {
             public Setup(Context applicationContext) : base(applicationContext)
             {
             }


            protected override IEnumerable<Assembly> GetViewAssemblies()
             {
                 return new List<Assembly>(base.GetViewAssemblies()
                     .Union(new[] { typeof(MvvmcrossGettingStarted.App).GetTypeInfo().Assembly })
                     .Except(new[] {this.GetType().Assembly})
                     );
             }


            protected override MvxFormsApplication CreateFormsApplication() => new MvvmcrossGettingStarted.App();


            protected override IMvxApplication CreateApp() => new Core.GettingStartedApplication();
        }

        The MainActivity needs to be updated to change its inheritance from global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity to MvxFormsAppCompatActivity<MainViewModel>. And the OnCreate needs to be updated to

        [Activity(Label = “MvvmcrossGettingStarted”, Icon = “@drawable/icon”, Theme = “@style/MainTheme”, MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
        public class MainActivity : MvxFormsAppCompatActivity<MainViewModel>
        //global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
        {
             protected override void OnCreate(Bundle bundle)
             {
                 TabLayoutResource = Resource.Layout.Tabbar;
                 ToolbarResource = Resource.Layout.Toolbar;


                base.OnCreate(bundle);


                var startup = Mvx.Resolve<IMvxAppStart>();
                 startup.Start();
                 InitializeForms(bundle);


             }
        }

        Finally the last platform, Android, is good to build and run. Note however that Android has a tendency to be a pain and that after setting everything up correctly you may still run into issues building, deploying and running. Before you waste hours looking at your code to see what you’ve done wrong, make the assumption that the tools are crap – delete both bin and obj folders from the Android head project, and uninstall the application from the device/emulator (assuming it has already been installed). Try building and running again – if this still fails, then you may indeed have something wrong with your code!

        image

        Coded Design Time Data using Mvvmcross for Windows and Windows Phone

        Coded Design Time Data using Mvvmcross for Windows and Windows Phone

        A question came in today regarding the use of design time data in conjunction with Mvvmcross. My initial response was “it just works” because I assumed that everyone does design time data in Blend….. and I’m still not sure why you won’t do this, since it promotes better design by giving designers the freedom to dictate the information architecture of each page. As it happens what they were really after was a way to plug in design time data that is generated in code. Without using mvvmcross this was relatively easy using a ViewModelLocator pattern – as part of serving up the view models, you could simply change the data source to be design time data when running in the dev tools. Because mvvmcross abstracts a lot of the work involved in associating pages with view models, it also means that it’s a bit harder to wire up coded design time data. In this post I’ll provide a summary (read “crude”) way I found to do this:

        The assumption here is that your Mvvmcross project follows how Stuart describes a typical project in any of his getting started videos. Essentially this means a UI project (eg a Windows Phone project), that would contain your views (eg pages) and a Portable Class Library, that would contain your view models. There is also an App class in the PCL which is used to initialise mvvmcross. In this example we’re just going to work with the FirstView and its corresponding FirstViewModel but we’re going to add in support for a service which is used to populate data. Here’s the FirstViewModel:

        public class FirstViewModel
            : MvxViewModel
        {
            private IDataService Data { get; set; }

            public FirstViewModel(IDataService data)
            {
                Data = data;
            }

            public string Hello
            {
                get { return Data!=null?Data.TestData:"Missing"; }
            }
        }

        The IDataService has two implementations: DataService and DesignData, as illustrated here:

        public interface IDataService
        {
            string TestData { get; }
        }

        public class DesignData : IDataService
        {
            public string TestData
            {
                get
                {
                    return "Designtime";
                }
            }
        }

        public class DataService:IDataService
        {
            public string TestData
            {
                get
                {
                    return "Runtime";
                }
            }
        }

        At runtime we don’t need to worry about creating an instance of the DataService as it is automatically picked up by mvvmcross and injected into the FirstViewModel constructor. However, the DesignData is a little harder to use. At design time we somehow have to coerce mvvmcross to generate the FirstViewModel and populate it with an instance of DesignData. One option would be to go down the ViewModelLocator path again and use it only at design time to create our view model using design time data. However, this is rather clumsy given we have a perfectly good DI framework that we can leverage. The other thing is we’d have to continually update it to expose properties for each view model we want.

        An alternative is to use a Factory pattern coupled with a Converter to dynamically create the appropriate view model. This is a bit of a chicken-and-egg thing to describe so I’ll start with how we wire it up in the UI project. Firstly, in the App.xaml we need to create both the Factory and Converter as resources:

        <Application.Resources>
           <codedDesignTimeData:DesignFactory x_Key="Factory"/>
            <codedDesignTimeData:DesignTimeConverter x_Key="DesignConverter" />
        </Application.Resources>

        Next, in the page we set the d:DataContext (ie the design time data context) as follows:

        <views:MvxPhonePage
            x_Class="CodedDesignTimeData.Views.FirstView"
            d_DataContext="{Binding Source={StaticResource Factory}, Converter={StaticResource DesignConverter}, ConverterParameter=FirstViewModel}"
            … >

        Let’s read through what this is saying – at design time, the DataContext for this page is going to be the Factory, passed through the Converter with the parameter “FirstViewModel”. As you can imagine what we’re really saying is that we’re asking the Factory to produce an instance of the FirstViewModel that we can data bind to.

        Ok, so now we know what it’s saying, let’s look at the implementation of firstly the Converter, and then the Factory itself:

        public class DesignTimeConverter:IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            { 
                var typeName = parameter as string;
                if (string.IsNullOrWhiteSpace(typeName)) return null;

                var factory = value as DesignFactory;
                return factory.Create(typeName);
            }

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return value;
            }
        }

        There isn’t much to the converter, it simply passes the parameter (ie the type of the view model to be created) into the Create method on the Factory object.

        public class DesignFactory
        {
            private Core.App app;
            public object Create(string typeName)
            {

                if (app==null)
                {
                    MvxSimpleIoCContainer.Initialize();

                        app = new Core.App();
                    app.Initialize();

                    Mvx.RegisterType<IDataService,DesignData>();
                }

                var type = app.FindViewModelTypeByName(typeName);

                if (type == null) return null;

                var req = MvxViewModelRequest.GetDefaultRequest(type);
                if (req == null) return null;
                var locator = app.FindViewModelLocator(req);
                if (locator == null) return null;

                IMvxViewModel vm;
                if (locator.TryLoad(type, null, null, out vm))
                {
                    return vm;
                }

                return null;
            }
        }

        The factory is where all the smarts are. The first thing we do is make sure that mvvmcross is initialized – this is similar to what happens in your app. We then call FindViewModelTypeByName (see below for implementation) to exchange the view model type name with a reference to the actual type. Next we invoke the view model locator infrastructure within mvvmcross to retrieve an actual instance to the view model we’re after, which we then return (and is subsequently set as the DataContext for the page).

        public Type FindViewModelTypeByName(string typeName)
        {
            return CreatableTypes().FirstOrDefault(t => t.Name == typeName);
        }

        Ok, but wouldn’t is just be better to create an instance of the view model, once we have a reference to the type? No, because that view model may have any number of dependencies, which is why we need to rely on the DI framework provided by mvvmcross. You’ll notice I skipped over one quite important line, which was that we register the type DesignData as the implementation of IDataService we want to use. By default the Initialize method on our App class will look for types that end in “Service” and register them, which is why our DesignData doesn’t end in “Service”, but it also means we have to manually register it.

        The upshot of this is that an instance of the DesignData class will be used to service up design time data for our view models in Blend. I hope this helps anyone working with mvvmcross.