Thursday, January 24, 2013

Portable MVVM Light - Move Your View Models

,

Portable Class Libraries 

Portable Class Libraries were added as a project type in the interest of creating an assembly that you could use across the .NET Framework, Silverlight, Windows Phone 7, or Xbox 360 platforms without modifications.  Well, not really that easy.  There is some work to do and as you get into the development of PCLs you'll find out that there is really a sliver of what you'd hope is supported. (http://msdn.microsoft.com/en-us/library/vstudio/gg597391(v=vs.110).aspx)

MVVM Light

Where I have found it for me is in Windows Store and Windows Phone (7.5 and 8) with MVVM Light. I have been using this MVVM framework exclusively for a few years now on Silverlight, WPF, Windows Phone and now Windows Store platforms and each release gets better.

Most recently, another MVVM Light fan, Oren Novotny (@onovotny) ported the MVVM Light project and made it possible to use it in a Portable Class Library. This is great, code reuse is the ultimate time saver. And when developing Windows Store Apps or a Windows Phone App; making a complimentary piece for the other just makes sense when the UI is really the only difference and even that is almost the same.

Example Project

Open Visual Studio 2012 and create a new project.  I like to start with the "Other Project Types" and select the Blank Visual Studio Solution; name it MvvmPortable and click save. Next add a Windows Store App (C# Blank Template) and call it Mvvm.Store. Add a new Windows Phone 8 project to the solution named Mvvm.Phone.

Now add a new project to the solution and select the "Portable Class Library" project type.


Click OK and then you'll be presented with a dialog to choose the platforms to be supported. Select all except XBox and for Windows Phone choose 7.5 or higher. (An error will occur when adding the nuget packages later if the 'Windows Phone 7.1 or higher' option is chosen).


Click OK and now the MVVM Light packages can start to be added via nuget.

Nuget

If you are  not using nuget, please pause here and go to nuget.org and/or install via Tools->Extensions And Updates.

Mvvm.PCL Project
Right click the project and select the Manage Nuget Packages and in the dialog search for "Portable.MvvmLightLibs" and be sure that the Include Pre-release option is on, or you can use the package manager console and use the command install package portable.mvvmlightlibs -prerelease.


Repeat this process for the Windows Phone and Windows Store projects.

Next we need to add the MVVM Light specific platform assemblies to each of the respective platforms and do some setup and cleanup to make this all work.

Right Click the Windows Store project, select Manage Nuget Packages and search for MVVM Light and click the install button. In doing so, a few folders and files will be added to the project and you may see some errors which we'll clean up and repeat the process for the Phone project.


Moving ViewModelLocator,ViewModels and Wiring it Up

Now on to the fun! 

In the Mvvm.PCL project create a folder call ViewModel in the root of the project. Then expand the  ViewModel folder in the Mvvm.Store project and select the ViewModelLocator.cs and MainViewModel.cs file and cut and paste those to the ViewModel folder in the Mvvm.PCL project.

Open each of those and change the namespace to Mvvm.PCL.ViewModel from Mvvm.Store.ViewModel.

Since the ViewModelLocator has moved, the store app needs to know where to find it and the ViewModels, so open the App.xaml file in the Mvvm.Store project and change:

 xmlns:vm="using:Mvvm.Store.ViewModel" 
to

 xmlns:vm="using:Mvvm.PCL.ViewModel" 

and we need to modify the Resources section because the nuget installer for MvvmLight puts in some extra entries for the ViewModelLocator


    <ResourceDictionary>
        <vm:ViewModelLocator p7:Key="Locator" p8:IsDataSource="True"
                        xmlns:p8="http://schemas.microsoft.com/expression/blend/2008"
                        xmlns:p7="http://schemas.microsoft.com/winfx/2006/xaml" />
        <ResourceDictionary.MergedDictionaries>
                <!--
                    Styles that define common aspects of the platform look and feel
                    Required by Visual Studio project and item templates
                 -->
            <ResourceDictionary Source="Common/StandardStyles.xaml" />
        </ResourceDictionary.MergedDictionaries>
   
    </ResourceDictionary>

Finally for the Store app we'll go to the MainPage.xaml and set the DataContext and add a TextBlock to be filled from the MainViewModel.cs in the portable class library that we'll add following that.

In the MainView.xaml page add the DataContext property at the top of the page after the other declarations.


    ...
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    >
Next in the grid add the TextBlock as follows


    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Foreground="White" FontSize="42" Text="{Binding Hello, Mode=TwoWay}" />
    </Grid>
If you compile the store project at this point you will get some errors concerning MvvmLight confilcts. These occur because there are class duplicates in the portable and in the specific versions of the assemblies.  In order to alleviate the errors, expand the references folder in the project and select the *.Win8 assemblies and delete them.

Adding Hello to MainViewModel
Now that the wiring up of the relocated ViewModelLocator and MainViewModel are completed we can add the simple "Hello" property in the MainViewModel so it can be bound to in the store project.

Open MainViewModel.cs and add the property as follows:


        private string _hello = "Hello";
        public string Hello
        {
            get
            {
                return _hello;
            }
            set
            {
                _hello = value;
                RaisePropertyChanged(() => Hello);
            }
        }

Set the store project as the default project to run and either run in the simulator or on your local machine and you should see "Hello" appear in the top left of the application.


Wiring up the Phone Project

The process here is pretty much the same as was done for the store project.  Instead of moving the ViewModel folder in the phone project; it can be deleted.

Open the App.xaml and make the adjustments to let the application know where the ViewModelLocator and ViewModels are located. Note that making these references in the phone project are different that in the store project, albeit subtle can trip you up.

Change  

 ...xmlns:vm="clr-namespace:Mvvm.Phone.ViewModel" mc:Ignorable="d">

to

 ...xmlns:vm="clr-namespace:Mvvm.PCL.ViewModel;assembly=Mvvm.PCL">

then make the modifications to the Application.Resources portion as follows:

  <Application.Resources>
    <local:LocalizedStrings xmlns:local="clr-namespace:Mvvm.Phone" x:Key="LocalizedStrings" />
        <vm:ViewModelLocator p6:Key="Locator"
                         p7:IsDataSource="True" xmlns:p7="http://schemas.microsoft.com/expression/blend/2008"
                         xmlns:p6="http://schemas.microsoft.com/winfx/2006/xaml" />
    </Application.Resources>

Next, open the MainPage.xaml and add the DataContext declaration and the TextBlock as we did for the store application.


...
shell:SystemTray.IsVisible="True"
    DataContext="{Binding Main, Source={StaticResource Locator}}">

adding the TextBlock

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock Text="{Binding Hello, Mode=TwoWay}" Foreground="White" FontSize="18" />
        </Grid>

And finally as mentioned in the store project, you will get the assembly conflicts so be sure to remove the .*WP8 references in the phone project prior to building the solution here.

Run the application and you'll see the Hello presented in the same location on the phone app.


Wrapping Up

All of the other capabilities that you may or may not be familiar with in the MVVM Light framework is still available to you within the specific projects or of you'd like extract those as well too.  I find that the navigation and switching of the views is still best served within the specific platforms.

I have in my projects moved services negotiation for getting data into the PCL assembly using the Microsfoft.BCL.Async library via nuget too and that is also great but a little different depending on your experience with the platform and WebClient versus HttpClient requests.

Enjoy and feel free to ask questions.

Part 2 - Adding a Data Service


19 comments to “Portable MVVM Light - Move Your View Models ”

  • January 25, 2013 at 9:50 AM
    aziz says:

    interesting article, i like that.

    delete
  • January 25, 2013 at 11:23 AM
    Anonymous says:

    How will you solve the navigation?

    delete
  • January 25, 2013 at 11:33 AM
    Shayne Boyer says:

    Navigation I handle within each of the specific platforms. Windows Phone I generally handle using MvvmLight Messenger component and NavigateToView. In Windows 8 there are options depending on what template or structure you use.

    delete
  • January 27, 2013 at 8:31 AM
    Slodge says:

    Definitely recommend the PCL route - do it! For the navigation question you can also wrap this behind a common interface if you want to - that's what I do in MvvmCross

    delete
  • January 27, 2013 at 4:04 PM
    Oren Novotny says:

    Any reason you're referencing the regular non-PCL ver in the UI proj? It's probably best to use the PCL package for everything. It has platform-specific binaries that get referenced when in a UI project.

    delete
  • January 27, 2013 at 4:06 PM
    Oren Novotny says:

    If it's the initial files (ViewModelLocator & XAML files), I can create an equiv "non-libs" NuGet package.

    delete
  • January 28, 2013 at 11:40 AM
    Shayne Boyer says:

    Initial files and structure setup. You can remove the core if you like. But there was an instance in another project for why they were needed. I can't seem to replicate now, perhaps it was a version issue. I will update the post either way as I expand this series. The point here was to show how to use the PCL from a blank slate, and some devs start with the MVVM Light templates where I did not here.

    delete
  • January 29, 2013 at 12:57 PM

    Great article Shayne,

    Do you have a code sample? I am running into an issue with the PCL assembly and a missing reference to System.Runtime

    The primary reference "GalaSoft.MvvmLight" could not be resolved because it has an indirect dependency on the framework assembly "System.Runtime, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which could not be resolved in the currently targeted framework. ".NETPortable,Version=v4.0,Profile=Profile104". To resolve this problem, either remove the reference "GalaSoft.MvvmLight" or retarget your application to a framework version which contains "System.Runtime, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". Mvvm.PCL

    delete
  • January 29, 2013 at 1:36 PM
    Shayne Boyer says:

    Craig,

    Make sure that that the version of the MvvmLight assembly you are referencing in the PCL project is the portable version as mentioned and not the actual. Use nuget and search for Portable.MvvmLightLibs and make sure that Include PreRelease is selected

    delete
  • January 29, 2013 at 3:04 PM

    Shayne,

    It is definitely the pcl version Here is a list of all references in my project;
    .NET Portable Subset ( Framework\.NETPortable\v4.0\Profile\Profile104\)
    GalaSoft.MvvmLight (packages\Portable.MvvmLightLibs.4.1.27-beta02\lib\portable-net45+sl4+wp71+win8\GalaSoft.MvvmLight.dll)
    GalaSoft.MvvmLight.Extras (packages\Portable.MvvmLightLibs.4.1.27-beta02\lib\portable-net45+sl4+wp71+win8\GalaSoft.MvvmLight.Extras.dll)
    Microsoft.Practices.ServiceLocation (packages\Portable.CommonServiceLocator.1.2.2\lib\portable-net4+sl4+wp7+win8\Microsoft.Practices.ServiceLocation.dll)

    Anything else you can think of?

    delete
  • January 30, 2013 at 2:09 PM

    I have the same problem as Craig .. I have the same MVVM Light assemblies installed with the PreRelease tag and need this System.Runtime dll ...

    delete
  • January 30, 2013 at 2:14 PM
    Shayne Boyer says:

    Paul and Craig are you targeting Windows Phone 7.1?

    delete
  • January 31, 2013 at 2:17 AM

    I think I have solved my problem, but I think I might have found a bug with Nuget.
    Scenario;
    1. Create solution with 2 pcl projects and change the windows phone 7 and higher to windows phone 7.5 and higher
    2. Add nugget package mvvmlight pcl on the 2nd project.
    3. Notice that the project does not contain a reference for System.Runtime or System.Threading.Tasks.
    4. Open the 1st project references and you will notice that NuGet added them to the first project for some reason.
    Workaround;
    1. Add Microsoft.bcl NuGet package to the 2nd project. This will add the missing System.Runtime and System.Threading.Tasks to your project.
    Is anyone else able to repro this?

    delete
  • February 1, 2013 at 11:06 AM
    Philippe says:

    Very nice article.
    I share it on my own blog.

    http://dotnetcoffee.blogspot.be/2013/02/cross-platfom-avec-mvvm-light.html

    delete
  • February 11, 2013 at 7:15 AM
    Rui Marinho says:

    hello, same issue that Paulo and Craig,i solved adding async bcl

    delete
  • March 18, 2013 at 10:11 AM

    I get this fun error when I try adding a local database to my Windows Phone 8 project.

    The type 'System.ComponentModel.INotifyPropertyChanging' exists in both 'e:\users\keenan\Documents\Visual Studio 2012\Projects\MAL.WindowsPhone\packages\Portable.MvvmLightLibs.4.1.27.1\lib\wp8\GalaSoft.MvvmLight.dll' and 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\WindowsPhone\v8.0\System.dll'

    Why is 'System.ComponentModel.INotifyPropertyChanging' in the WP8 libraries of the MVVM Portable NuGet package?

    delete
  • November 1, 2013 at 12:55 PM
    Sean Roark says:

    Very nice. I may have found an issue and a solution, which I posted on my blog along with a finished sample project.

    The Store project was referencing the PCL version of ServiceLocator but it needed the regular one.

    Let me know if my solution makes sense or if you know a better way.

    delete
  • April 7, 2014 at 3:51 AM
    bitdisaster says:

    When referencing both, the PCL and the non PCL version of MVVMLight in the same project then a ton of conflicting types exist in bot versions of the DLL's. When I jus reference the PCL in a WP project then the compiler complains about a missing namespace 'Threading'. Any ideas?

    delete
  • April 10, 2014 at 10:34 AM
    Shayne Boyer says:

    @bitdisaster - only reference the PCL in the projects. Make sure that you have the Microsoft.BCL nuget package...

    get the sample code here: http://sdrv.ms/WpBGqS

    delete
Powered by Blogger.
 
Creative Commons License
TattooCoder.com by Shayne Boyer is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.