Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / XAML

WinRT: StyleMVVM Demo 1 of 2

Rate me:
Please Sign up or sign in to vote.
5.00/5 (24 votes)
4 Nov 2013CPOL17 min read 52.1K   36   8
A look at an excellent WinRT MVVM framework.

Contents

Series Links

PART 1 : StyleMVVM Fundamentals (this article)

PART 2 : StyleMVVM Demo App Walkthrough

Introduction

About a year ago I contacted by this uber sharp American guy called Ian Johnson, who asked me if I would be so kind as to review his upcoming Windows 8 MVVM library. I stated that I was currently on holiday, but when I got back I would be glad to. Now I have been in pretty much constant contact with Ian over the past year and have been fielding his questions, and we have even written a joint article (Expression API Cookbook). What immediately struck me about Ians framework (here after known as StyleMVVM) was how feature rich it was, and how well thought out it all was. Remember I have taken time to look at his code base.

At the time I was lucky enough to be asked to be an advisory member for the new PRISM offering for Windows 8 code name "Kona". I didn't really have enough time to do much on this but it was still an honor. Though I have since spent quite a bit of time getting to known "Kona" now known as "PRISM for Windows Runtime".

Now I love PRISM and have nothing but respect for that team, and previous team members, but I have to also say at the moment, I prefer the StyleMVVM offering, as I think it is just more feature rich, and some of the code seems to be better to use than PRISM for Windows Runtime.

One thing I really liked in StyleMVVM was the fact that Ian had written a Expression Tree (fast as hell) IOC container from scratch. He has bench marked this and it is right up there, with speeds far exceeding Castle / Unity and AutoFac. It is based around the MEF style attribute model, but fluent registration is also happening any second now (I know I have seen the beta versions of it, and it looks very cool). Ian is very proud of this piece of StyleMVVM , and rightly so, its awesome.

Now that is no small thing, for a single individual to come up with a framework as feature rich as one of the big boys in the MVVM arena, kudos to Ian.

I believed in Ians work so much I have been working on a demo app using it in my spare time. This demo app will be the source for the next article in this series of articles.

In this article we will concentrate on some of the features of StyleMVVM.

Prerequisites

If you just want to read this article as an introduction to StyleMVVM, then you don't need anything. If you like what you read and you want to take StyleMVVM for a spin, you will need

  1. Visual Studio 2012 / 2013
  2. Windows 8 / 8.1

If you like what you have read even more, and decide to take the attached demo code (that is my demo not the one that comes with the StyleMVVM source code), you will additionally need to install the following:

  1. SQLite Windows 8 stuff: http://sqlite.org/2013/sqlite-winrt80-3080002.vsix (though that is included in the demo code download you just need to run it. It is a Visual Studio Extension so just double click it)
  2. Once you have done step 1 here, ensure that the NuGet packages are all present, and if they aren't restore them. And also ensure that you have references the installed (from step 1) SQLite library

What Does StyleMVVM Provide Out Of The Box?

As I have already stated StyleMVVM is extremely feature rich, and as such provides a great many (and Ian is very open to adding new stuff, I know because I have asked him to add stuff for me, which he did straight away) services/helpers that one would expect from any awesome MVVM framework.

A list of some of the core StyleMVVM features which I have shamelessly stolen from the StyleMVVM codeplex site is shown below:

  • StyleMVVM is the only MVVM toolkit for Window Store App that supports all three development languages C#, C++/CX and HTML/JS. Allowing you to export components written in C++/CX and import them into a C# applications.
  • Built-in validation engine that supports ValidationAttributes, Fluent validation and Method validation depending on your needs. You can validate ViewModels as well as DataModels.
  • Conventions module to allow for easier development, as well as templates to setup your project to use conventions.
  • Event Handlers can be easily hooked up to your view model using the simple syntax View:EventHandler.Attach="EventName => ViewModelMethod($sender,$eventArgs); etc..."
  • Supports Regions similarly to Prism with region registration happening in XAML and navigation being driven from the ViewModel
  • Attribute Based IoC container (Export, Import), container is also environment aware and sorts exports accordingly returning the best match at Locate time (RunTime, DesignTime, UnitTest).
  • Fluent interfaces for configuring IoC Container programmatically (required for C++/CX and Windows Runtime Components)
  • Design time ViewModel support. ViewModels are located at design time using IOC so you can use your real ViewModel and replace your IDataService with a Faux version for Design and UnitTest.
  • Auto Registration of Views and WCF Clients (i.e., all classes inheriting from ClientBase<T> & Page)
  • Implementations for ICommand and Attached Event Commands.
  • Messenger service that is Dispatcher Aware (i.e., handlers are called back on the proper dispatcher)
  • NavigationViewModel that is tied into the Metro Page Navigation system (Supporting Navigate method and Navigation Events)
  • Extensible logging solution
  • Configuration service that is expandable by Exporting the IConfigurationStorageProvider interface
  • Improved Suspension Manager (auto adds DataContract classes to KnownTypes)
  • IMessageBoxService and IFilePickerService wrappers that allow you to mock out your dialogs for Design and Unit Testing purposes
  • ICharmService makes creating fly-out easy by automatically registering charm controls with the SettingPane.
  • ITileService, IBadgeService, and IToastService allow for easy updates of tiles and toasts.
  • IActivationService that can create or clone any Object (satisfying Imports and message registration)
  • ITransformService can transform data objects from one type to another using reflection and LINQ Expressions, you can use the Transform attribute to give the service hints on how to transform the property.
  • Visual Studio Template for Projects and Items

A Deeper Dive Into Using StyleMVVM

In this section we will dive into how you can use StyleMVVM to develop your own applications.

Typical Boostrapper Code

I have to say I am not a massive fan of the whole WinRT app file. I think it is a bloody mess truth be told. That said it is what it is, and as such we must work with it. To kick start StyleMVVM we need to apply a BootStrapper (just like we did in PRISM). Shown below is a typical App.xaml.cs file that one might use when using StyleMVVM:

C#
sealed partial class App : Application
{
    /// <summary>
    /// Initializes the singleton Application object.  This is the first line of authored code
    /// executed, and as such is the logical equivalent of main() or WinMain().
    /// </summary>
    public App()
    {
        this.InitializeComponent();
        this.Suspending += OnSuspending;

        CreateBootstrapper();
    }

    /// <summary>
    /// Invoked when the application is launched normally by the end user.  Other entry points
    /// will be used when the application is launched to open a specific file, to display
    /// search results, and so forth.
    /// </summary>
    /// <param name="args">Details about the launch request and process.</param>
    protected override async void OnLaunched(LaunchActivatedEventArgs args)
    {
        LaunchBootStrapper();

        // Do not repeat app initialization when already running, just ensure that
        // the window is active
        if (args.PreviousExecutionState == ApplicationExecutionState.Running)
        {
            Window.Current.Activate();
            return;
        }

        // Create a Frame to act as the navigation context and associate it with
        // a SuspensionManager key
        var rootFrame = new Frame();

        StyleMVVM.Suspension.SuspensionManager.RegisterFrame(rootFrame, "AppFrame");

        if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
        {
            // Restore the saved session state only when appropriate
            await StyleMVVM.Suspension.SuspensionManager.RestoreAsync();
        }

        if (rootFrame.Content == null)
        {
            Type navigateType = Bootstrapper.Instance.Container.LocateExportType("StartPage");

            // Could not find start page. make sure you have a page marked as [StartPage]
            if (navigateType == null)
            {
                throw new Exception("Could not find start page.");
            }

            if (!rootFrame.Navigate(navigateType))
            {
                throw new Exception("Failed to create initial page");
            }
        }

        // Place the frame in the current Window and ensure that it is active
        Window.Current.Content = rootFrame;
        Window.Current.Activate();
    }

    /// <summary>
    /// Invoked when application execution is being suspended.  Application state is saved
    /// without knowing whether the application will be terminated or resumed with the contents
    /// of memory still intact.
    /// </summary>
    /// <param name="sender">The source of the suspend request.</param>
    /// <param name="e">Details about the suspend request.</param>
    private async void OnSuspending(object sender, SuspendingEventArgs e)
    {
        var deferral = e.SuspendingOperation.GetDeferral();
        await StyleMVVM.Suspension.SuspensionManager.SaveAsync();
        deferral.Complete();
    }

    /// <summary>
    /// Create StyleMVVM BootStrapper
    /// </summary>    
    private void CreateBootstrapper()
    {
        if (!Bootstrapper.HasInstance)
        {
            Bootstrapper newBootstrapper = new Bootstrapper();

            newBootstrapper.Container.RegisterAssembly(
                GetType().GetTypeInfo().Assembly);

            // Required for Validation
            newBootstrapper.Container.RegisterAssembly(
                typeof(CSharpContainerLoader).GetTypeInfo().Assembly);

            newBootstrapper.Start(false);
        }
    }

    private void LaunchBootStrapper()
    {
        Bootstrapper.Instance.Launched();
    }
}

As I say I think the amount of code that has to be placed in this file is dreadful, a bad separation of concern, and a total abortion frankly. This is nothing to do with Ian or StyleMVVM, it is the WinRT way. Cool huh?

IOC Usage

What Ian has done within StyleMVVM is to go for a MEF type of approach where you use certain attributes to indicate what you want Exported and how.

There is a fluent interface coming (which I am glad to say I had some part in), that will be coming very soon.

For now, let's look at a table of how you might do certain things:

Task What Do I Do
Export something to the container
C#
[^__strong__^Export]
public class ScheduleViewModel
Mark something as a Singleton
C#
[Singleton]
[Export(typeof(ISqlLiteDatabaseService))]
public class SqlLiteDatabaseService : ISqlLiteDatabaseService
Export as a specific Type
C#
[Singleton]
[Export(typeof(ISqlLiteDatabaseService))]
public class SqlLiteDatabaseService : ISqlLiteDatabaseService
Import stuff in the constructor
C#
[ImportConstructor]
public MainPageViewModel(IEnumerable<ipageinfo> pageInfos)
{
}</ipageinfo>
Run a particular View as the start View for the app
C#
[StartPage]
public sealed partial class MainPage : LayoutAwarePage
{
}

You can expect to see more around the container in future releases of StyleMVVM.

Base ViewModels

StyleMVVM includes a number of handy base class ViewModels that you may like to inherit from.

Here is a list of them:

  • PageViewModel
    • Base class to use for ViewModels that might go with a Page type view. This also provides these extra helper methods:
      • public INavigationService Navigation { get; }
      • public FrameworkElement View { get; set; }
      • public virtual void OnLoaded(object sender, 
                    RoutedEventArgs args);
      • public virtual void OnUnloaded(object sender, 
                    RoutedEventArgs args);
  • NavigatingViewModel
    • Base class to use for ViewModels that might go with a navigation aware type view. This also provided these extra helper methods:
      • protected virtual Task InternalNavigatingFrom(object 
                    sender, StyleNavigatingCancelEventArgs e);
      • public void NavigatedFrom(object sender, 
                    StyleNavigationEventArgs e);
      • public void NavigatedTo(object sender, 
                    StyleNavigationEventArgs e);
      • public IAsyncAction NavigatingFrom(object sender, 
                    StyleNavigatingCancelEventArgs e);
      • protected virtual void OnNavigatedFrom(object sender, 
                    StyleNavigationEventArgs e);
      • protected virtual void OnNavigatedTo(object sender, 
                    StyleNavigationEventArgs e);
      • protected virtual Task OnNavigatingFrom(object sender, 
                    StyleNavigatingCancelEventArgs e);
  • BaseViewModel
    • Simple container aware INPC viewmodel

These base classes are invaluable in my opinion, and tackle some of the really tricky stuff when dealing with MVVM, such as these:

  1. When my my page loads I want to run some method. Ok so simply override the OnLoaded(..) method in PageViewModel
  2. I need to get the navigation parameters. Ok so simply override the
    NavigatedTo(..)
    
    method in NavigatingViewModel

Those that have used PRISM will certainly, seems some similarities.

PageViewModel

Now that we have discussed some of the bases classes provided by StyleMVVM, I just want to look at one of them in detail, which is the PageViewModel:

When you use the StyleMVVM PageViewModel you can do neat things like

  • Interact with the View as a Framework element, which means you can get its Dispatcher
  • Do things when the View loads/unloads
  • Override the OnNavigatedTo(..) and use the
    StyleNavigationEventArgs
    
    to grab the navigation context parameters

Navigation

If you inherit from PageViewModel you will get access to the Navigation property (which gives you the INavigationService), which you can use to navigate quite simply as follows:

C#
string state = "Sending state";
Navigation.Navigate("SomeView",state);

Then within the page (providing you inherited from PageViewModel you can grab out the Navigation context data via the use of the OnNavigatedTo(..) and use the

StyleNavigationEventArgs

View / ViewModel WireUp

StyleMVVM supports wiring up a View to its ViewModel via an attached DependencyProperty (much like I used to do with my own Cinch framework), here is how it is done.

In the View you simply need to do this:

XML
<Common:LayoutAwarePage
    x:Class="Demo.Views.SomePage"
    ....
    xmlns:View="using:StyleMVVM.View"
    View:ViewModel.Name="SomePageViewModel">
...
...
...
</Common:LayoutAwarePage>

And in the Views code behind you need to do this. This step is mandatory, without this setup the View will not be able to resolve its ViewModel.

C#
[Export]
public sealed partial class SomePage : LayoutAwarePage
{
    public MainPage()
    {
        this.InitializeComponent();
    }
}

Where your ViewModel might look like this:

C#
public class SomePageViewModel : PageViewModel
{

}

Validation

StyleMVVM comes with several different flavors of validation out of the box, it is pretty much up to you which of these you go for. Before we look at each of the different types of validation within StyleMVVM lets just come up with a simple ViewModel that the examples below will all work against to perform their validation.

C#
public class BasicValidationViewModel : PageViewModel, IValidationStateChangedHandler
{
    private string prefix;
    private string firstName;
    private string lastName;
    private string middleName;
    private string emailAddress;
    private DelegateCommand saveCommand;

    public DelegateCommand SaveCommand
    {
        get
        {
            if (saveCommand == null)
            {
                saveCommand = new DelegateCommand(SaveMethod,
                    x => ValidationContext.State == ValidationState.Valid);
            }
            return saveCommand;
        }
    }

    public IEnumerable<string> Prefixes
    {
        get { return new []{ "Mr","Mrs","Ms","MD","Phd"};}
    }
        
    [Required]
    public string Prefix
    {
        get { return prefix; }
        set { SetProperty(ref prefix, value); }
    }

    [Required]
    public string FirstName
    {
        get { return firstName; }
        set { SetProperty(ref firstName, value); }
    }

    [Required]
    public string LastName
    {
        get { return lastName; }
        set { SetProperty(ref lastName, value); }
    }

    [Required]
    public string EmailAddress
    {
        get { return emailAddress; }
        set { SetProperty(ref emailAddress, value); }
    }
        
    public string MiddleName
    {
        get { return middleName; }
        set { SetProperty(ref middleName, value); }
    }
        
    [Import]
    public IValidationContext ValidationContext { get; private set; }

    [Import]
    public IMessageBoxService MessageBox { get; set; }


    [ActivationComplete]
    public void Activated()
    {
        ValidationContext.RegisterValidationStateChangedHandler(this);
    }

    private void SaveMethod(object parameter)
    {
        MessageBox.Show("Save Clicked");
    }

    
    public void StateChanged(IValidationContext context, ValidationState validationState)
    {
        SaveCommand.RaiseCanExecuteChanged();
    }
}

A couple of salient points in this example ViewModel:

  1. It can be seen that you free to use the
    System.ComponentModel.DataAnnotations
    
    namespace attributes, such as RequiredAttribute. StyleMVVM will work just fine with the
    System.ComponentModel.DataAnnotations
    
    namespace attributes.
  2. That you should make sure that the IValidationContext is marked as an [Import] property. This can not come via constructor injection, as we need the target object to be created prior to the IValidationContext being created. So it must be a property [Import]
  3. That we hook up the IValidationContext in the
    Activated
    
    method (see the [ActivationComplete] usage) which we can then use to disable ICommand objects based on the current objects valid/invalid state. Have a look at the constructor above you will see what I mean

Fluent Validation Framework

StyleMVVM comes with an inbuilt fluent API for configuring the validation. here is a small example based on the example ViewModel above.

C#
[Export(typeof(IFluentRuleProvider<BasicValidationViewModel>))]
public class FluentValidationForBVVM : IFluentRuleProvider<BasicValidationViewModel>
{
    public void ProvideRules(IFluentRuleCollection<BasicValidationViewModel> collection)
    {
        collection.AddRule("MiddleNameRule")
                    .Property(x => x.MiddleName)
                    .IsRequired()
                    .When.Property(x => x.FirstName)
                    .IsNotEmpty();
    }
}

By inherited from IFluentRuleProvider<T> and exporting it via the [ExportAttribute] StyleMVVM will make sure the ViewModel that the Fluent rules have been created for get setup correctly for you. I think the best way to get to grips with the StyleMVVM fluent validation API is to have a play with it.

Method Type Validation

You can also create a custom method validation where you can run any logic you want. As before here is an example for the ViewModel just shown above:

C#
[Export(typeof(IValidationMethodProvider<BasicValidationViewModel>))]
public class MethodValidationForBVVM : IValidationMethodProvider<BasicValidationViewModel>
{
    public void ProvideRules(IValidationMethodCollection<BasicValidationViewModel> methodCollection)
    {
        methodCollection.AddRule(IanJohnsonRule).
            MonitorProperty(x => x.FirstName).MonitorProperty(x => x.LastName).MonitorProperty(x => x.MiddleName);
    }

    private void IanJohnsonRule(IRuleExecutionContext<BasicValidationViewModel> obj)
    {
        if (string.Compare(obj.ValidationObject.FirstName, "Ian", 
                StringComparison.CurrentCultureIgnoreCase) == 0 &&
                string.Compare(obj.ValidationObject.MiddleName, 
                "Phillip", StringComparison.CurrentCultureIgnoreCase) == 0 &&
                string.Compare(obj.ValidationObject.LastName, 
                "Johnson", StringComparison.CurrentCultureIgnoreCase) == 0)
        {
            obj.AddError(x => x.FirstName, "Your first name can't be Ian when your last name is Johnson");
            obj.AddError(x => x.MiddleName,"Your middle name can't be Ian Phillip Johnson ... I am!");
            obj.AddError(x => x.LastName, "Your first name can't be Ian when your last name is Johnson");

            obj.Message = "You can not be Ian Phillip Johnson ... Identity Thief!";
        }
    }
}

By inherited from IValidationMethodProvider<T> and exporting it via the [ExportAttribute] StyleMVVM will make sure the ViewModel that the rules the method provides have get setup correctly for you. As before, the best way to deal with this is have a play.

Validation Control Templates And Styles

Sadly and quite strangely, there does not seem to be any standard validation Styles/ControlTemplates supplied out of the box for Windows 8/WinRT. Luckily Ian has rectified this by providing some within the StyleMVVM source code. You just need to look for the following

ResourceDictionary
in the downloaded StyleMVVM source code:

Release-XXXX\Examples\ExampleApp\ExampleApp\Common\FrameworkStyles.xaml

And you should see that, that ResourceDictionary contains a few useful validation Styles/ControlTemplates that can be used with StyleMVVM, such as:

  • ValidationTextbox
  • ValidationComboBox

These can then be applied like this in the XAML:

XML
<UserControl
    x:Class="ExampleApp.Views.Validation.BasicValidationView"
    .....
    xmlns:View="using:StyleMVVM.View"
    View:ViewModel.Name="BasicValidationViewModel">
    <Grid>
        <ComboBox Template="{StaticResource ValidationComboBox}" 
            SelectedItem="{Binding Prefix,Mode=TwoWay}" 
            View:Validation.Property="Prefix"      
            ItemsSource="{Binding Prefixes}"/>

        <TextBox Text="{Binding FirstName,Mode=TwoWay}" 
                 View:Validation.Property="FirstName" 
                 Template="{StaticResource ValidationTextbox}"/>

   </Grid>
</UserControl>

Also note how we pick out what property we would like to use for the validation filter. When run this would produce something like this:

Image 1

The good thing about how StyleMVVM does its validation is that every type of control can potentially show validation errors. You just need to create the correct Style/ControlTemplate. As I say Ian has created the 2 listed above, but if you find you need more just borrow ideas from the TextBox one (ValidationTextBox) and ComboBox (ValidationComboBox) one that Ian has already crafted for you.

Restorable ViewModels

Windows 8 follows the same type of lifecycle as Windows Phone, where an app can go through various lifecycles, including suspension. Windows 8 comes with a standard SuspensionManager. However to make things simple StyleMVVM comes with its own, SuspensionManager which we saw wired up in the App.xaml.cs code we looked at earlier.

Now to make things uber simper StyleMVVM provides two attributes (SyncableAttribute and

SyncAttribute
shown below) you can use to ensure your ViewModel state gets stored on suspension and restored correctly on re-activation.

Here is an example of a small ViewModel that uses these two StyleMVVM attributes:

C#
[Export]
[Syncable]
public class ScheduleViewModel : BaseViewModel
{

    [Sync]
    public bool HasItems
    {
        get { return hasItems; }
        set { SetProperty(ref hasItems, value); }
    }
}

And that is all you need to do. StyleMVVM takes care of things for you by using the DataContractSerializer behind the scenes. Good stuff I say.

DelegateCommand

An oldy but a goody, the by now famous DelegateCommand (these days I tend to use a more Rx based ICommand, for those interested you can read more here : http://sachabarbs.wordpress.com/2013/10/18/reactive-command-with-dynamic-predicates/)

However back to the subject at hand, here is StyleMVVM DelegateCommand, which you can use to run command logic directly in your ViewModel. Though again I recommend a separate controller, or maybe even many micro controllers to get your ViewModel nice and lean.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace StyleMVVM.ViewModel
{
    public delegate void DelegateAction(object parameter);

    public delegate bool DelegateCanExecute(object parameter);

    /// <summary>
    /// A general implementation of ICommand used by ViewModels to bind to commands and events
    /// </summary>
    public sealed class DelegateCommand : ICommand
    {
        private readonly DelegateAction command;
        private readonly DelegateCanExecute canExecute;

        public DelegateCommand(DelegateAction command)
        {
            this.command = command;
        }

        public DelegateCommand(DelegateAction command, DelegateCanExecute canExecute)
        {
            this.command = command;
            this.canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            if (canExecute != null)
            {
                return canExecute(parameter);
            }

            return true;
        }

        public void Execute(object parameter)
        {
            command(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            if (InternalCanExecuteChanged != null)
            {
                InternalCanExecuteChanged(this, EventArgs.Empty);
            }
        }

        event EventHandler ICommand.CanExecuteChanged
        {
            add { InternalCanExecuteChanged += value; }
            remove { InternalCanExecuteChanged -= value; }
        }

        internal EventHandler InternalCanExecuteChanged;
    }
}

Which you can use like this (say):

C#
CaptureImageCommand = new DelegateCommand(ExecuteCaptureImageCommand,
                        x => ValidationContext.State == ValidationState.Valid);

Event To Command / Method

Now one thing to note with WinRT development. Out of the box you can't fall back to the old tricks you used with WPF/SL where you used the Blend.Interactivity DLLs. They don't work.

There is a CodePlex offering http://winrttriggers.codeplex.com/ should you want to use it. For this article I will stick to what StyleMVVM offers, for one of the most common interactivity scenarios. The Event to Command scenario, which again is pretty standard in most MVVM frameworks out there.

Here is how StyleMVVM does it.

In the XAML you would do this:

XML
<ListView View:EventHandlers.Attach="ItemClick => ItemClicked($sender,$eventArgs)" />

And in your ViewModel you would do this:

C#
public void ItemClicked(FrameworkElement element,ItemClickEventArgs eventArgs)
{
    MessageBoxService.Show("You clicked: " + eventArgs.ClickedItem);
}

Core Services

This section outlines some of the core services supplied by StyleMVVM. I will not cover every single one of them in this article (as there just is not enough time in the day for that). You can however see the example application that comes with StyleMVVM. This example is located within the source code at a path something like:

Release-3.0.3\Examples\ExampleApp

Messager / Mediator

Any MVVM worth its salt will have a weak event messaging component, whether that is an internal Rx stream based approach (this is what I use these days) or a standard weak event handling mediator, they should all still have one. StyleMVVM as you would expect, has one. Ian calls his IDispatchedMessager (see how it works with JavaScript too) which looks like this:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using StyleMVVM.Data;

namespace StyleMVVM.Messenger
{
    public delegate void JSCallback(object message);

    /// <summary>
    /// IDispatchedMessenger allows you to send messages between loosely coupled consumers.
    /// Note: The default implementation of DispatchedMessenger uses WeakActions to call back consumers
    /// so there is no need to unregister for garbage collection reasons.
    /// </summary>
    public interface IDispatchedMessenger
    {
        /// <summary>
        /// Sends a message of Type T to consumers.
        /// </summary>
        /// <param name="message">message to send, cannot be null</param>
        void Send(object message);

        /// <summary>
        /// Registers an action as a consumer of type T messages.
        /// </summary>
        /// <typeparam name="T">message Type</typeparam>
        /// <param name="callback">message handler</param>
        void Register(object callback);

        /// <summary>
        /// Registers an action as a consumer of type T messages.
        /// </summary>
        /// <typeparam name="T">message Type</typeparam>
        /// <param name="callback">message handler</param>
        /// <param name="background">should it be called back on a background thread</param>
        /// <param name="holdReference"> </param>
        void Register(object callback, bool background, bool holdReference);

        /// <summary>
        /// Registers a method info on a target for callback later.
        /// </summary>
        /// <typeparam name="T">message Type</typeparam>
        /// <param name="target">handler object</param>
        /// <param name="methodName"> </param>
        /// <param name="background"> </param>
        /// <param name="holdReference"> </param>
        void RegisterMethod(object target, string methodName, bool background, bool holdReference);

        /// <summary>
        /// Registers a JavaScript callback
        /// </summary>
        void RegisterJSCallback(TypeWrapper messageType, JSCallback callback, bool background);

        /// <summary>
        /// Unregisters a consumer handler
        /// </summary>
        /// <param name="callback">action to unregister</param>
        void Unregister(object callback);

        /// <summary>
        /// Allows you to register all methods on an object marked with MessageHandler attributes 
        /// </summary>
        /// <param name="handlerObject"></param>
        void RegisterObjectHandlers(object handlerObject);

        /// <summary>
        /// Allows you to unregister all methods on an object marked with MessageHandler attributes 
        /// </summary>
        /// <param name="handlerObject"></param>
        void UnregisterObjectHandlers(object handlerObject);
    }
}

This is how you might publish something out on the IDispatchedMessager, which is a singleton by the way

C#
DispatchedMessenger.Instance.Send(new TextMessage {Text = TextMessage});

And this is how you might subscribe to a particular message on the IDispatchedMessager

C#
[MessageHandler]
public void TextMessageHandler(TextMessage message)
{
    TextMessage = message.Text;
}

Note: Messages subscription is weak by default.

IMessageBoxService

This is a simple MessageDialog wrapper. Once you see the interface exposed via the service its should make total sense how to use it. Here is the exposed interface:

C#
using System.Collections.Generic;
using System.Threading.Tasks;
#if !DOT_NET
using Windows.Foundation;
#endif
#if !NETFX_CORE
using System.Windows;

#endif

namespace StyleMVVM.View
{
    /// <summary>
    /// This service gives you easy access to the MessageDialog class
    /// as well as creates IMessageDialog wrappers
    /// </summary>
    public interface IMessageBoxService
    {
        /// <summary>
        /// Opens a message box to the user with just the ok button
        /// </summary>
        /// <param name="message">message to display to the user</param>
        void Notify(string message);

        /// <summary>
        /// Opens a message box to the user with just the ok button
        /// </summary>
        /// <param name="message">message to display to the user</param>
        /// <param name="title">title on the message box</param>
        void Notify(string message, string title);

#if NETFX_CORE
        void Notify(string message, string title, string buttonText);
        
        /// <summary>
        /// Show a new message dialog
        /// </summary>
        /// <param name="message"></param>
        /// <returns>returns the command clicked</returns>
        IAsyncOperation<string> Show(string message);
        
        /// <summary>
        /// Show a new message dialog with the specified title and commands
        /// </summary>
        /// <param name="message">message to display</param>
        /// <param name="title">title for the message dialog</param>
        /// <param name="commands">command to show in the dialog</param>
        /// <returns>returns the command that was clicked</returns>
        IAsyncOperation<string> Show(string message, string title, params string[] commands);

        /// <summary>
        /// Creates a new message Dialog object that can be configured then shown
        /// </summary>
        /// <param name="message">message for the dialog</param>
        /// <param name="title">title for the dialog</param>
        /// <returns>returns a new message dialog object that you configure then show</returns>
        IMessageDialog MessageDialog(string message, string title);

        /// <summary>
        /// Show a new message dialog
        /// </summary>
        /// <param name="message"></param>
        /// <returns>returns the command clicked</returns>
        IAsyncOperation<SystemMessageBoxResult> ShowSystemMessageBox(string message);

        /// <summary>
        /// Show a new message dialog with the specified title and commands
        /// </summary>
        /// <param name="message">message to display</param>
        /// <param name="title">title for the message dialog</param>
        /// <param name="commands">command to show in the dialog</param>
        /// <returns>returns the command that was clicked</returns>
        IAsyncOperation<SystemMessageBoxResult> ShowSystemMessageBox(
               string message, string title, SystemMessageBoxButton button);

#else

        /// <summary>
        /// Show a new message dialog
        /// </summary>
        /// <param name="message"></param>
        /// <returns>returns the command clicked</returns>
        Task<string> Show(string message);

#if DOT_NET
    /// <summary>
    /// 
    /// </summary>
    /// <param name="message"></param>
    /// <param name="title"></param>
    /// <param name="buttonText"></param>
        void Notify(string message, string title, string buttonText);

        /// <summary>
        /// Show a new message dialog with the specified title and commands
        /// </summary>
        /// <param name="message">message to display</param>
        /// <param name="title">title for the message dialog</param>
        /// <param name="commands">command to show in the dialog</param>
        /// <returns>returns the command that was clicked</returns>
        Task<string> Show(string message, string title, params string[] commands);

        /// <summary>
        /// Shows a new message dialog with specified title and commands
        /// </summary>
        /// <param name="message"></param>
        /// <param name="title"></param>
        /// <param name="commands"></param>
        /// <returns></returns>
        Task<MessageBoxCommand> Show(string message,
                                     string title,
                                     MessageBoxCommand command,
                                     params MessageBoxCommand[] commands);

        /// <summary>
        /// Shows a new message dialog with specified title and commands
        /// </summary>
        /// <param name="message"></param>
        /// <param name="title"></param>
        /// <param name="commands"></param>
        /// <returns></returns>
        Task<MessageBoxCommand> Show(string message, string title, IEnumerable<MessageBoxCommand> commands);
#endif

        /// <summary>
        /// Show a new message dialog
        /// </summary>
        /// <param name="message"></param>
        /// <returns>returns the command clicked</returns>
        Task<SystemMessageBoxResult> ShowSystemMessageBox(string message);

        /// <summary>
        /// Show a new message dialog with the specified title and commands
        /// </summary>
        /// <param name="message">message to display</param>
        /// <param name="title">title for the message dialog</param>
        /// <param name="commands">command to show in the dialog</param>
        /// <returns>returns the command that was clicked</returns>
        Task<SystemMessageBoxResult> ShowSystemMessageBox(string message, 
                    string title, SystemMessageBoxButton button);
#endif
    }
}

Based on that, we can simply do this

C#
var result = await messageBoxService.Show("There was a problem save the Patient data");

IFilePickerService

This is a simple OpenFileDialog / SaveFileDialog wrapper. Once you see the interface exposed via the service its should make total sense how to use it. Here is the exposed interface:

C#
using System.Collections.Generic;
using System.Threading.Tasks;
using StyleMVVM.Utilities;
#if !DOT_NET
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Pickers;

#endif

namespace StyleMVVM.View
{
    /// <summary>
    /// The IFilePickerService acts as a wrapper around the default file picker class
    /// </summary>
    public interface IFilePickerService
    {
#if NETFX_CORE
        /// <summary>
        /// Opens a file picker and allows the user to pick multiple
        /// files and return a list of the files the user chose
        /// </summary>
        /// <param name="location"></param>
        /// <param name="filterTypes"></param>
        /// <returns></returns>
        IAsyncOperation<IReadOnlyList<StorageFile>> PickMultipleFilesAsync(
            PickerLocationId location, params string[] filterTypes);

        /// <summary>
        /// Opens a file picker and allows the user to pick one file and returns a StorageFile to the caller
        /// </summary>
        /// <param name="location"></param>
        /// <param name="filterTypes"></param>
        /// <returns></returns>
        IAsyncOperation<StorageFile> PickFileAsync(PickerLocationId location, params string[] filterTypes);
#elif WINDOWS_PHONE
        /// <summary>
        /// Opens a file picker and allows the user to pick multiple
        /// files and return a list of the files the user chose
        /// </summary>
        /// <param name="location"></param>
        /// <param name="filterTypes"></param>
        /// <returns></returns>
        Task<IReadOnlyList<StorageFile>> PickMultipleFilesAsync(
            PickerLocationId location, params string[] filterTypes);

        /// <summary>
        /// Opens a file picker and allows the user to pick one file and returns a StorageFile to the caller
        /// </summary>
        /// <param name="location"></param>
        /// <param name="filterTypes"></param>
        /// <returns></returns>
        Task<StorageFile> PickFileAsync(PickerLocationId location, params string[] filterTypes);
#elif DOT_NET
        /// <summary>
        /// Opens a file picker and allows the user to pick multiple files and return a list of the files the user chose
        /// </summary>
        /// <param name="location"></param>
        /// <param name="filterTypes"></param>
        /// <returns></returns>
        Task<IReadOnlyList<string>> PickMultipleFilesAsync(
            PickerLocationId location, params string[] filterTypes);

        /// <summary>
        /// Opens a file picker and allows the user to pick one file and returns a StorageFile to the caller
        /// </summary>
        /// <param name="location"></param>
        /// <param name="filterTypes"></param>
        /// <returns></returns>
        Task<string> PickFileAsync(PickerLocationId location, params string[] filterTypes);

        /// <summary>
        /// Opens the Save file dialog allowing a user to pick a file to save to
        /// </summary>
        /// <param name="location"></param>
        /// <param name="filterTypes"></param>
        /// <returns></returns>
        Task<string> PickSaveFileAsync(PickerLocationId location, params string[] filterTypes);
#endif
    }
}

Based on that, we can simply do this

C#
StorageFile storageFile = await FilePicker.PickFileAsync(PickerLocationId.DocumentsLibrary, ".txt");

ICharmService

This is the service that controls the creation of the settings pane and activates charms. I will not be covering this within this article see the StyleMVVM example:

ITileService

This interface provides a wrapper around TileUpdater as well as providing an easy way to generate Tile updates. I will not be covering this within this article see the StyleMVVM example.

IBadgeService

Service wrapper around the badge functionality. I will not be covering this within this article see the StyleMVVM example.

IToastService

Represents a service that allows you to create Toast Notifications. I will not be covering this within this article see the StyleMVVM example.

ITransformService

This service offers a code free way to transform from one type to another type. This could be useful when going from ViewModel to Model and vice versa. I will not be covering this within this article see the StyleMVVM example.

That's It

Anyway that is all I wanted to say this time. I am sure you will agree that Ian has done a rather splendid job on StyleMVVM, and that using this awesome framework kind of makes up for the complete PITA that Windows 8 is right now. If it had not have been for StyleMVVM I would have gone completely nuts working with WinRT in its current state, it was only saved by the fact that Ians code just worked and did exactly what I wanted out of the box. And when it didn't I told him and he added it, top fellow.

Next time we will be looking at a demo app that I put together using StyleMVVM, which uses most of the stuff outlined above, as well as interacting with a camera, it also makes use of the search contract, and uses a small SQLite database such that the demo app is more real world like.

Hopefully I will manage to write that up pretty soon. If you just can't wait to look at it, you can grab the demo app for the next article at the top of this article. Here is a brief overview of what the demo app for the next article does:

  • Page to capture patient details (Expects to capture an image for the patient here too)
  • Create appointments against a list of known doctors
  • View appointments for a given day
  • Drill in to a specific doctors appointments
  • Show some statistics for a given day (simple pie chart of how many appointments are scheduled against each doctor for a given day)
  • Search contract has been implemented, such that you can search the demo app right from the SearchPane in Windows 8

As always any votes/comments are welcome, and I am sure Ian would appreciate people taking his baby (StyleMVVM of course) for a spin.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
GeneralMy vote of 5 Pin
D V L5-May-16 23:51
professionalD V L5-May-16 23:51 
QuestionExcellent Article Pin
Garry Lowther4-Nov-13 0:56
Garry Lowther4-Nov-13 0:56 
AnswerRe: Excellent Article Pin
Sacha Barber4-Nov-13 3:26
Sacha Barber4-Nov-13 3:26 
AnswerRe: Excellent Article Pin
Sacha Barber4-Nov-13 22:13
Sacha Barber4-Nov-13 22:13 
GeneralMy vote of 5 Pin
S. M. Ahasan Habib1-Nov-13 3:27
professionalS. M. Ahasan Habib1-Nov-13 3:27 
GeneralRe: My vote of 5 Pin
Sacha Barber1-Nov-13 3:29
Sacha Barber1-Nov-13 3:29 
GeneralAnother great article Pin
Ian P Johnson30-Oct-13 11:42
professionalIan P Johnson30-Oct-13 11:42 
GeneralRe: Another great article Pin
Sacha Barber30-Oct-13 12:15
Sacha Barber30-Oct-13 12:15 
Biased you say. Curious
Sacha Barber
  • Microsoft Visual C# MVP 2008-2012
  • Codeproject MVP 2008-2012
Open Source Projects
Cinch SL/WPF MVVM

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.