Wednesday, June 12, 2013

Intercepting RaisePropertyChanged

We've recently pushed an update which allows developers to intercept all MvxNotifyPropertyChanged notifications if you want to.

The aim of this is to allow you to provide custom RaisePropertyChanged functionality.

At this first release, the framework doesn't provide any standard Interceptors - but we might write an initial one at some point soon.


An example Interception

The core of interception is the IMvxInpcInterceptor interface.


    public interface IMvxInpcInterceptor
    {
        MvxInpcInterceptionResult Intercept(IMvxNotifyPropertyChanged sender, PropertyChangedEventArgs args);
    }


You might use this, for example, to provide things like automated additional notifications for certain types - e.g. you might use it to send dependent change notifications.

For example, suppose you have a Person ViewModel with properties:
  • FirstName
  • LastName
  • FullName

This new functionality would allow you to provide an interceptor which would automatically send a FullName change notification whenever FirstName or LastName change - ie.e you could implement this interceptor as:

    public class MyInterceptor : IMvxInpcInterceptor
    {
        public MvxInpcInterceptionResult Intercept(
                        IMvxNotifyPropertyChanged sender,
                        PropertyChangedEventArgs args)
        {
            if (sender.GetType () == typeof(Person)) 
            {
                if (args.PropertyName == "FirstName" ||
                    args.PropertyName == "LastName") 
                {
                    sender.RaisePropertyChanged ("FullName");
                }
            }

            return MvxInpcInterceptionResult.RaisePropertyChanged;
        }
    }



With this done you could then register your implementation with IoC during Setup.InitializeInpcInterception - e.g.

        protected override void InitializeInpcInterception()
        {
            Mvx.RegisterSingleton((
IMvxInpcInterceptor)new MyInterceptor());
        }


For release software, I wouldn't normally expect you to use this particular interceptor implementation, but I hope this illustrates how you might be able to use this mechanism.



For inspiration!


For some inspiration about the sort of thing that some people are doing in a similar area, take a look at the excellent: https://github.com/zleao/MvvmCross-PropertyChangedEventPropagation

CommandParameter binding


We recently added a special CommandParameter parse step to allow the binding to specify fixed values (strings, ints, bools) to ICommand bindings.

This can be used as:

        local:MvxBind="Click MyCommand,CommandParameter=Thursday"

which uses a ValueConverter to turn a Click into a call on:

       MyCommand.Execute("Thursday")

So can be received in

       new MvxCommand(day => DoAction(day));
      
This helps where you want to reuse a command across multiple buttons

However, please note that this cannot be used currently with valueconverters - as it itself uses a valueconverter to achieve the effect.

Hope that helps :)

Tuesday, June 11, 2013

My standard reply to MvvmCross support emails

This is the type of message I generally send to everyone when they send me an email about MvvmCross. I'm afraid I currently get perhaps 5 emails every day and answering them is simply not efficient or practical
 
Thanks for understanding

Stuart






Hi (friend)

Thanks for the email

I provide lots of support to the community and I do this in public. I find talking in public is better:
  • it helps as many people as possible and 
  • it allows others to also help out with answers - most of the best ideas come from other people.

Questions

If you need help or have questions, please try asking on StackOverflow or on the Xamarin forums - I and others can help there. Please provide a good level of detail in your question - e.g.:
  • if you have a question about an exception, then please include some code near where the error occurred and the exception message and stack trace.
  • if you have a question about an idea or concept, then maybe try adding a diagram that will help others understand the concept - and tell everyone what you've already tried

If you ask a good question, then I and others will often spend hours answering it. If you ask a vague one sentence question that lacks detail, then no-one will be able help you. The better your question - the better the answers.

There are some great tips on asking questions in http://stackoverflow.com/help/on-topic


Bugs and Features

If you believe you have found a bug or if you have a new Feature Request, then please try raising an issue on github - https://github.com/slodge/MvvmCross/issues/new - but please again include a good level of information if you can. It really helps if you can provide a complete github repo which demonstrates the problem - this makes it easier and quicker for people to find, fix and test the problem - so quicker for you to get a solution.

MvvmCross also accepts pull requests from other github repos. Please only send a pull request if you agree to have your code shared under the MvvmCross license. Pull requests including Unit Tests are encouraged - I am trying to improve the test coverage inside MvvmCross. Also please understand that currently I do personally maintain and support MvvmCross - so please do understand that sometimes I may decide not to merge your request. My aim is to try to keep MvvmCross extensible - so even if a Pull Request is not accepted, then you will still hopefully be able to work on a fork or in an extension in order to use that functionality yourself.


Privacy

If after reading this, you decide you still really need 1-to-1 support because of business reasons, then I understand and can provide this, but only as a paid business option. You are welcome to email me about that if you need it.


Thanks for understanding

Best wishes

Stuart

Monday, June 10, 2013

N=26 - Down at Android Fragments Rock (N+1 Days of MvvmCross)

Today N+1 is back!


Sorry about the short break... and sorry about before another short break that's coming up - I'm going to NDC Oslo in Norway this week :)



Today, we're talking about Fragments!







Fragments are an Android-only thing. They're a type of User Control and they were invented by Jim Henson*


In this N+1 we talk through:

  • how to data-bind static fragments
  • how to data-bind dynamic fragments
  • briefly how to data-bind fragments in:
  • tabs
  • dialogs
  • the little-known MvxFrameControl


For more on fragments:





The video is:














Today's source code is available on: https://github.com/slodge/NPlus1DaysOfMvvmCross/tree/master/N-26-Fraggle



A full and wonderful index for N+1 is available on





---

* ok, not really :) For more on Fraggle Rock... http://muppet.wikia.com/wiki/Fraggle_Rock - which is where the images above come from (under CC). Also for the full Fraggle Rock theme song, try http://www.youtube.com/watch?v=l_zsz_MlVvI

Sunday, June 09, 2013

Presenter roundup

There have been quite a few awesome* custom presenters around recently. Among the highlights have been:


Better Tabbing


A custom tab presenter that combines UINavigationController and UITabBarController more neatly: http://deapsquatter.blogspot.co.uk/2013/06/custom-presenter-for-uitabbarcontroller.html



Navigation by Fragments


An excellent tutorial on how to navigate using fragments in Android - http://enginecore.blogspot.ro/2013/06/more-dynamic-android-fragments-with.html



Stack Clearing


A custom presenter that allows you to request the iOS back stack to be cleared

https://gist.github.com/gshackles/5735595


A Presenter combined with a sliding 'hamburger' menu


A full sample using a sliding hamburger menu - https://github.com/fcaico/MvxSlidingPanels.Touch/blob/master/MvxSlidingPanelsSample.Touch/MvxSlidingPanelsTouchViewPresenter.cs


N+1

There have been a couple of videos recently:



And finally.... A presenter presentation...





* judging for badges of awesomeness still pending!

Friday, June 07, 2013

IoC and ServiceLocation in v3 - a brain dump....

Two key ideas that are use in MvvmCross are:
  • the Service Locator pattern
  • Inversion of Control

There are lots of articles and introductions available on this - some good starting places are Martin Fowler's introduction and Joel Abrahamsson's IoC introduction. I've also made some animated slides as a simple demonstration.



Specifically within MvvmCross, we provide a single static class Mvx which acts as a single place for both registering and resolving interfaces and their implementations.

 

Service Location - Registration and Resolution


The core idea of MvvmCross Service Location is that you can write classes and interfaces like:
    public interface IFoo
    {
         string Request();
    }

    public class Foo : IFoo
    {
        public string Request()
        {
            return "Hello World";
        }
    }

 

Singleton Registration


With this pair written you could then register a Foo instance as a singleton which implements IFoo using:
    // every time someone needs an IFoo they will get the same one
    Mvx.RegisterSingleton<IFoo>(new Foo());
If you did this, then any code can call:
    var foo = Mvx.Resolve<IFoo>();
and every single call would return the same instance of Foo

 

Lazy Singleton Registration


As a variation on this, you could register a lazy singleton. This is written
    // every time someone needs an IFoo they will get the same one
    // but we don't create it until someone asks for it
    Mvx.RegisterSingleton<IFoo>(() => new Foo());
In this case:
  • no Foo is created initially
  • the first time any code calls Mvx.Resolve<IFoo>() then a new Foo will be created and returned
  • all subsequent calls will get the same instance that was created the first time

 

'Dynamic' Registration


One final option, is that you can register the IFoo and Foo pair as:
    // every time someone needs an IFoo they will get a new one
    Mvx.RegisterType<IFoo, Foo>();
In this case, every call to Mvx.Resolve<IFoo>() will create a new Foo - every call will return a different Foo.

Last-registered wins


If you create several implementations of an interface and register them all:
    Mvx.RegisterType<IFoo, Foo1>();
    Mvx.RegisterSingleton<IFoo>(new Foo2());
    Mvx.RegisterType<IFoo, Foo3>();
Then each call replaces the previous registration - so when a client calls Mvx.Resolve<IFoo>() then the most recent registration will be returned.

This can be useful for:
  • overwriting default implementations
  • replacing implementations depending on application state - e.g. after a user has been authenticated then you could replace an empty IUserInfo implementation with a real one.

 

Bulk Registration by Convention


The default NuGet templates for MvvmCross contain a block of code in the core App.cs like:
        CreatableTypes()
            .EndingWith("Service")
            .AsInterfaces()
            .RegisterAsLazySingleton();
This code uses Reflection to:
  • find all classes in the Core assembly
    • which are creatable - i.e.:
      • have a public constructor
      • are not abstract
    • with names ending in Service
  • find their interfaces
  • register them as lazy singletons according to the interfaces they support

Technical Note> the lazy singleton implementation here is quite technical - it ensures that if a class implements IOne and ITwo then the same instance will be returned when resolving both IOne and ITwo.

The choice of name ending here - Service - and the choice to use Lazy singletons are only personal conventions. If you prefer to use other names or other lifetimes for your objects you can replace this code with a different call or with multiple calls like:
        CreatableTypes()
            .EndingWith("SingleFeed")
            .AsInterfaces()
            .RegisterAsLazySingleton();
        CreatableTypes()
            .EndingWith("Generator")
            .AsInterfaces()
            .RegisterAsDynamic();
        CreatableTypes()
            .EndingWith("QuickSand")
            .AsInterfaces()
            .RegisterAsSingleton();
There you can also use additional Linq helper methods to help further define your registrations if you want to - e.g. Inherits, Except. WithAttribute, Containing, InNamespace ... e.g.
        CreatableTypes()
            .StartingWith("JDI")
            .InNamespace("MyApp.Core.HyperSpace")
            .WithAttribute(typeof(MySpecialAttribute))
            .AsInterfaces()
            .RegisterAsSingleton();
And you can also, of course, use the same type of registration logic on assemblies other than Core - e.g.:
        typeof(Reusable.Helpers.MyHelper).Assembly.CreatableTypes()
            .EndingWith("Helper")
            .AsInterfaces()
            .RegisterAsDynamic();
Alternatively, if you prefer not to use this Reflection based registration, then you can instead just manually register your implementations:
        Mvx.RegisterSingleton(new MyMixer());
        Mvx.RegisterSingleton(new MyCheese());
        Mvx.RegisterType();
        Mvx.RegisterType();
The choice is your's

Constructor Injection


As well as Mvx.Resolve, the Mvx static class provides a reflection based mechanism to automatically resolve parameters during object construction.

For example, if we add a class like:
    public class Bar
    {
        public Bar(IFoo foo)
        {
            // do stuff
        }
    }
Then you can create this object using:
    Mvx.IocConstruct();
What happens during this call is:
  • MvvmCross:
    • uses Reflection to find the constructor of Bar
    • looks at the parameters for that constructor and sees it needs an IFoo
    • uses Mvx.Resolve() to get hold of the registered implementation for IFoo
    • uses Reflection to call the constructor with the IFoo parameter

 

Constructor Injection and ViewModels


This "Constructor Injection" mechanism is used internally within MvvmCross when creating ViewModels.

If you declare a ViewModel like:
     public class MyViewModel : MvxViewModel
     {
         public MyViewModel(IMvxJsonConverter jsonConverter, IMvxGeoLocationWatcher locationWatcher)
         {
            // ....
         }
     }

then MvvmCross will use the Mvx static class to resolve objects for jsonConverter and locationWatcher when a MyViewModel is created.


This is important because:
  1. It allows you to easily provide different locationWatcher classes on different platforms (on iPhone you can use a watcher that talk to CoreLocation, on WindowsPhone you can use a watcher that talks to System.Device.Location
  2. It allows you to easily provide mock implementations in your unit tests
  3. It allows you to override default implementations - if you don't like the Json.Net implementation for Json, you can use a ServiceStack.Text implementation instead.

 

Constructor Injection and Chaining


Internally, the Mvx.Resolve mechanism uses constructor injection when new objects are needed.

This enables you to register implementations which depend on other interfaces like:
     public interface ITaxCalculator
     {
         double TaxDueFor(int customerId)
     }

     public class TaxCalculator
     {
         public TaxCalculator(ICustomerRepository customerRepository, IForeignExchange foreignExchange, ITaxRuleList taxRuleList)
         {
             // code...
         }

         // code...
     }
If you then register this calculator as:
     Mvx.RegisterType<ITaxCalculator, TaxCalculator>();
Then when a client calls Mvx.Resolve<ITaxCalculator>() then what will happen is that MvvmCross will create a new TaxCalculator instance, resolving all of ICustomerRepository IForeignExchange and ITaxRuleList during the operation.

Further, this process is recursive - so if any of these returned objects requires another object - e.g. if your IForeignExchange implementation requires a IChargeCommission object - then MvvmCross will provide Resolve for you as well.

 

How do I use IoC when I need different implementations on different platforms?


Sometimes you need to use some platform specific functionality in your ViewModels. e.g. for example, you might want to get the current screen dimensions in your ViewModel - but there's no existing portable .Net call to do this.

When you want to include functionality like this, then there are two main choices:
  1. Declare an interface in your core library, but then provide and register an implementation in each of your UI projects.
  2. Use or create a plugin

 

1. PCL-Interface with Platform-Specific Implementation


In your core project, you can declare an interface and you can use that interface in your classes there - e.g.:
    public interface IScreenSize
    {
        double Height { get; }
        double Width { get; }
    }

    public class MyViewModel : MvxViewModel
    {
        private readonly IScreenSize _screenSize;

        public MyViewModel(IScreenSize screenSize)
        {
             _screenSize = screenSize;
        }

        public double Ratio
        {
            get { return (_screenSize.Width / _screenSize.Height); }
        }
    }
In each UI project, you can then declare the platform-specific implementation for IScreenSize - e.g. a trivial example is:
    public class WindowsPhoneScreenSize : IScreenSize
    {
        public double Height { get { return 800.0; } }
        public double Width { get { return 480.0; } }
    }
You can then register these implementations in each of the platform-specific Setup files - e.g. you could override MvxSetup.InitializeFirstChance with
    protected override void InitializeFirstChance()
    {
        Mvx.RegisterSingleton<IScreenSize>(new WindowsPhoneScreenSize());
        base.InitializeFirstChance();
    }
With this done, then MyViewModel will get provided with the correct platform specific implementation of IScreenSize on each platform.

 

2. Use or create a plugin


A Plugin is an MvvmCross pattern for combining a PCL assembly, plus optionally some platform specific assemblies in order to package up some functionality.

This plugin layer is simply a pattern - some simple conventions - for naming related Assemblies, for including small PluginLoader and Plugin helper classes, and for using IoC. Through this pattern it allows functionality to be easily included, reused and tested across platforms and across applications.

For example, existing plugins include:
  • a File plugin which provides access to System.IO type methods for manipulating files
  • a Location plugin which provides access to GeoLocation information
  • a Messenger plugin which provides access to a Messenger/Event Aggregator
  • a PictureChooser plugin which provides access to the camera and to the media library
  • a ResourceLoader plugin which provides a way to access resource files packaged within the .apk, .app or .ipa for the application
  • a SQLite plugin which provides access to SQLite-net on all platforms.

Plugin Use 

 If you want to see how these plugins can be used in your applications, then:

Plugin Authoring 

 Writing plugins is easy to do, but can feel a bit daunting at first.

The key steps are:
  1. Create the main PCL Assembly for the plugin - this should include:
    • the interfaces your plugin will register
    • any shared portable code (which may include implementations of one or more of the interfaces)
    • a special PluginLoader class which MvvmCross will use to start the plugin
  2. Optionally create platform specific assemblies which:
    • is named the same as the main assembly but with a platform specific extension (.Droid, .WindowsPhone, etc(
    • contains
      • any platform specific interface implementations
      • a special Plugin class which MvvmCross will use to start this platform-specific extension
  3. Optionally provide extras like documentation and nuget packaging which will make the plugin easier to reuse.

I'm not going to go into any more detail on writing plugins here.

If you'd like to see more about writing your own plugin, then:

 

What if...

 

What if... I don't want to use Service Location or IoC


If you don't want to use this in your code, then don't.

Simply remove the CreatableTypes()... code from App.cs and then use 'normal code' in your ViewModels - e.g.:
     public class MyViewModel : MvxViewModel
     {
         private readonly ITaxService _taxService;

         public MyViewModel()
         {
             _taxService = new TaxService();
         }
     }

 

What if... I want to use a different Service Location or IoC mechanism


There are lots of excellent libraries out there including AutoFac, Funq, MEF, OpenNetCF, TinyIoC and many, many more!

If you want to replace the MvvmCross implementation, then you'll need to:
  • write some kind of Adapter layer to provide their service location code as an IMvxIoCProvider
  • override CreateIocProvider in your Setup class to provide this alternative IMvxIoCProvider implementation.
Alternatively, you may be able to organise a hybrid situation - where two IoC/ServiceLocation systems exist side-by-side.

 

What if... I want to use Property Injection as an IoC mechanism


There is an example Property Injection implementation for IoC provided.

This can be initialised using a Setup override of:
  protected override IMvxIoCProvider CreateIocProvider()
  {
      return MvxPropertyInjectingIoCContainer.Initialise();
  }

 

What if... I want advanced IoC features like child containers


The IoC container in MvvmCross is designed to be quite lightweight and is targeted at a level of functionality required in the mobile applications I have built.

If you need more advanced/complex functionality, then you may need to use a different provider or a different approach - some suggestions for this are discussed in: Child containers in MvvmCross IoC

 


Note: this article is part of the v3 attempt to get MvvmCross documentation produced. If you'd like to help with this work, please say hello on https://github.com/slodge/MvvmCross/issues/252 - we need you!

Thursday, June 06, 2013

Wednesday, June 05, 2013

Some code for finding LoaderExceptions

Just for my own future reference really....


An MvvmCross v1 Xamarin.Android app for crime witnesses

Just heard that Self Evident has been published on the Google Play store: https://play.google.com/store/apps/details?id=org.witnessconfident.app



Self Evident is a free app that records, validates and secures evidence. While the android version has been designed primarily as a crime reporting app, it also lets you file a report for work, notify an adviser or business of a claim, send the media a news story or just secure the evidence in your private account. 

It's built using the original v1 of MvvmCross with input from a few UK developers including Matthew at Sky Fish Technologies and Gavin at GB Software Solutions.