Cimbalino Toolkit: Integrating with MVVM Light Toolkit

Picking up where we left off on the previous article, you now know how to install the Cimbalino Toolkit in your app, so congratulations for that! :)

On this article I will show how to integrate it with the MVVM Light Toolkit, and then build a really simple “Hello World” app!

Note: Though this article will focus on how to integrate with the MVVM Light Toolkit, the Cimbalino Toolkit can be combined with most Windows development toolkits and frameworks that are available (like MVVMCross, Caliburn, etc.)

Using the same approach to add NuGet packages to the solution shown in the previous article, now search for “MvvmLight” and select the package shown in this picture:

Searching for MVVM Light Toolkit

You should now click on the Install button, confirm that you want to install the package into both projects, review the details shown in the License Acceptance window, and click the I Accept button.

You will now see a couple of warnings about moving the ViewModel folder manually; this is expected and it is due to the fact that we are building a Universal App (you can find more information about this here).

Look at the Solution Explorer Window, you should see that we have two ViewModel folders, one on each of the projects:

Projects with different ViewModel folders

Go ahead and delete one of the ViewModel folders, and move the remaining one from the project to the shared files on the bottom. The end result should look something like this:

Projects with shared ViewModel folder

We now we need to register the IMessageBoxService with the ViewModelLocator so that we can use it in the MainViewModel to show message popups in the app!

Edit the ViewModelLocator.cs file and change it to the following:

using Cimbalino.Toolkit.Services;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;

namespace App1.ViewModel
{
    public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            SimpleIoc.Default.Register<IMessageBoxService, MessageBoxService>();

            SimpleIoc.Default.Register<MainViewModel>();
        }

        public MainViewModel Main
        {
            get
            {
                return ServiceLocator.Current.GetInstance<MainViewModel>();
            }
        }

        public static void Cleanup()
        {
            // TODO Clear the ViewModels
        }
    }
}

As you can see above, we registered the IMessageBoxService with the MVVM Light Toolkit IoC Container by calling SimpleIoc.Default.Register<IMessageBoxService, MessageBoxService>(), and this is how we will use all of the services provided by Cimbalino Toolkit – and there are quite a lot of them!!

Now open the MainViewModel.cs file and change it to the following code:

using Cimbalino.Toolkit.Services;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace App1.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        private string _name;

        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                Set(ref _name, value);
            }
        }

        public RelayCommand SayHelloCommand { get; private set; }

        public MainViewModel(IMessageBoxService messageBoxService)
        {
            SayHelloCommand = new RelayCommand(async () => await messageBoxService.ShowAsync("Hello " + Name + "!"));
        }
    }
}

We started by adding a couple of properties, Name and SayHelloCommand, that we are going to bind to the view.

We can also see a IMessageBoxService parameter in the MainViewModel constructor, which the IoC Container will satisfy by creating an instance of MessageBoxService and providing it to the constructor.

Inside the constructor, we declared what will happen when the SayHelloCommand is invoked: show a popup message box with the input name.

That takes care of the view model, time to work on the view!

On the shared files project, create a new folder named View, and inside it create a new user control named MainUserControl.xaml with the following content:

<UserControl x:Class="App1.View.MainUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             DataContext="{Binding Main,
                                   Source={StaticResource Locator}}"
             d:DesignHeight="300"
             d:DesignWidth="400"
             mc:Ignorable="d">

    <StackPanel>
        <TextBlock Text="name" />
        <TextBox Text="{Binding Name, Mode=TwoWay}" />
        <Button Command="{Binding SayHelloCommand, Mode=OneTime}" Content="Say Hello" />
    </StackPanel>
</UserControl>

For the view we will use root StackPanel control, containing a TextBlock with a “name” label, a TextBox binded to the Name property in the view model, and a Button binded to the SayHelloCommand property.

Notice also on the top of the file that we set the user control DataContext property to use the ViewModelLocator.Main property, which returns the instance of the MainViewModel.

Now all that we needed is to add our MainUserControl to the MainPage.xaml file in each of the app projects. In the end, each of the MainPage.xaml files should be similar to this:

<Page x:Class="App1.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:view="using:App1.View"
      mc:Ignorable="d">

    <Grid>
        <view:MainUserControl />
    </Grid>
</Page>

And… we are done!!!

Just run the Windows project and the Windows Phone project to confirm that our shared code does in fact work across the two platforms! :)

To make things even easier, you can download the full solution here:

Integrating Cimbalino Toolkit with MVVM Light Toolkit (36.59 kB)
Downloaded 66 times

Cimbalino Toolkit, step by step!

One of the biggest complaints I always had about Cimbalino Toolkit is the lack of documentation and samples!

Granted, some awesome developers like Sara Silva and Scott Lovegrove have done a lot more than I have to promote the toolkit and write some really good code using it, but I think it’s time I take on some of that work!

As such, I’m now making an effort to regularly write articles on Universal Apps development with Cimbalino Toolkit step by step, and here is the first one…

Adding the Cimbalino Toolkit NuGet to a Universal App

Open Visual Studio 2013, click File -> New -> Project, on the Templates on the left select Store Apps -> Universal Apps, on the right select Blank App (Universal Apps), pick a name and hit Ok to save the solution!

Creating a blank Universal App project

Click Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution….

On the top right of the Manage NuGet Packages window you will see a search box; type “Cimbalino” on it and press Enter. You should now be seeing two packages: “Cimbalino Toolkit Core” (compatible with background agents) and “Cimbalino Toolkit” (main component)

Installing Cimbalino Toolkit with NuGet Package Manager

Select “Cimbalino Toolkit” and click on the Install button. You will now see the Select Project window.

Select Projects to install package

Leave all projects of the solution selected and click Ok. You will now see the License Acceptance window, showing the licenses for all packages that will be installed.

License Acceptance

Please review the data and then click I accept to continue with the installation.

After this step, you should now have returned to the Manage NuGet Packages window, and a green checkmark should now be shown on the side of each of the toolkit components.

Packages successfuly installed

Congratulations: you have now successfully installed the Cimbalino Toolkit in your project! :)

Bye MixRadio!

Today was my last day as a MixRadio employee.

After Microsoft completed the acquisition of the Nokia Devices & Services business, MixRadio and all of it’s employees became part of Microsoft.

However, a couple of weeks after that Microsoft started a full reorganization and decisions were quickly made to ensure MixRadio would become a separate entity.

So the only visible changes resulting from the acquisition are actually the company signs around the office, the “blue badges”, and the new @microsoft.com email addresses… no other real integration ever happened for MixRadio, so I can’t actually say I felt like a Microsoft employee during this short period!

As a result of all this, plans have been made for the future of MixRadio as a new company that made me believe this is the right time for our paths to come apart.

During my time with the company, I was involved in almost every aspect of the MixRadio Windows Phone client development; every time I open the MixRadio 4.x client in my phone, I can’t help but to feel proud of what this team accomplished.

I wish the very best to MixRadio and all my colleagues in the upcoming future, and I’m sure to keep using MixRadio service as it is by far one of the best streaming music services available!

As for me, I will keep doing what I love, always related with development under Microsoft Technologies, but more to come on this over the next weeks…

Upgrading from the IsolatedStorageSettings to ApplicationData.LocalSettings

When Windows Phone 7 came out, the SDK provided a really easy class to maintain the app settings: the IsolatedStorageSettings.

Basically, the class is an IDictionary<string, object> with a Save() method that will take the instance and serialize it to a file called “__ApplicationSettings” in the root of the app’s isolated storage.

Now if you upgraded your app from Windows Phone Silverlight 8.0 to the Windows Runtime model, you’ll probably want to migrate the settings from the old format to the new one, right?

Problem is that though the class exists in Windows Phone Silverlight apps, it does not in the new Windows Runtime apps, being replaced with ApplicationData.LocalSettings and ApplicationData.RoamingSettings instead.

So the only solution will be doing it ourselves, by reading and deserializing the “old” settings file!

Here’s a sample of the content of an “__ApplicationSettings” file from one of my tests:

PhoneApp1.Address, PhoneApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
<ArrayOfKeyValueOfstringanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"><KeyValueOfstringanyType><Key>Name</Key><Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">John Doe</Value></KeyValueOfstringanyType><KeyValueOfstringanyType><Key>Age</Key><Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:int">20</Value></KeyValueOfstringanyType><KeyValueOfstringanyType><Key>Country</Key><Value xmlns:d3p1="http://schemas.datacontract.org/2004/07/PhoneApp1" i:type="d3p1:Address"><d3p1:Code>UK</d3p1:Code><d3p1:Name>United Kingdom</d3p1:Name></Value></KeyValueOfstringanyType></ArrayOfKeyValueOfstringanyType>

By looking at the contents of some samples of settings file like the one above, here’s what we can learn:

  • the file has always two lines (second line in the above sample is auto-wrapped to fit the post!)
  • the first line has the known types full names that should be loaded and passed on to the DataContractSerializer constructor, each properly separated by a null char
  • if only basic types are used, the first line will be empty
  • the second line is the serialized xml data

So I wrote the following code snippet to read and deserialize the values from “__ApplicationSetting” to an IEnumerable<KeyValuePair<string, object>>:

public async Task<IEnumerable<KeyValuePair<string, object>>> GetValuesAsync()
{
    try
    {
        using (var fileStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync("__ApplicationSettings"))
        {
            using (var streamReader = new StreamReader(fileStream))
            {
                var line = streamReader.ReadLine() ?? string.Empty;

                var knownTypes = line.Split('\0')
                    .Where(x => !string.IsNullOrEmpty(x))
                    .Select(Type.GetType)
                    .ToArray();

                fileStream.Position = line.Length + Environment.NewLine.Length;

                var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), knownTypes);

                return (Dictionary<string, object>)serializer.ReadObject(fileStream);
            }
        }
    }
    catch
    {
        return new Dictionary<string, object>();
    }
}

So all you now have to do is call the GetValuesAsync() method above and load those values to one of the new Settings repositories!

The Cimbalino Toolkit way

Starting in Cimbalino Toolkit 1.2.0, you’ll be able to use the new IApplicationSettingsService to access Local, Roaming, and Legacy app settings.

In case that wasn’t clear from the names, the Legacy settings will allow you to get the values on the “__ApplicationSettings” file (do note that only the Values property is implemented, so it’s read-only).

Here are the platform rules for the ISettingsService:

  • Local
    • Supported in all platforms
  • Roaming
    • Supported in all platforms except Windows Phone Silverlight 8.0
  • Legacy
    • Only supported in Windows Phone

One last suggestion: after migrating the legacy settings remember to delete the “__ApplicationSettings” file as it won’t be needed again! ;)

Cimbalino Toolkit 1.0.0

Cimbalino.ToolkitIn case you missed it, there is a new and improved Cimbalino Toolkit now available, supporting the following platforms:

  • Windows Phone Silverlight 8.0 and 8.1 apps (WP8)
  • Windows Phone 8.1 apps (WPA81)
  • Windows Store 8.1 apps (Win81)

The long story

About 3 years ago, the first version of Cimbalino Windows Phone Toolkit was released as a NuGet package with full source code hosted in GitHub to help every on the development of Windows Phone apps!

Back then, Windows Phone 7.0 was the only version available, and that meant that some technical decisions had to be made that influenced the toolkit architecture!

The main one was that WP7 apps Marketplace ingestion would automatically detect every component used in a particular app, and add the required Capabilities for them; so if the toolkit was a single assembly, you’d get your app with the full Capabilities list in the requirements, even if your app didn’t actually use them…

There was also some limitations on the available API’s for Background Agents and once again, the Marketplace ingestion of an app would basically fail if it detected one of those forbidden API’s.

So the toolkit ended up divided like so:

Cimbalino Windows Phone Toolkit

In light blue are the components that may be used with Background Agents. The rest of the components are divided by Capabilities or 3rd party components requirements.

Then came Windows 8.0 and Windows Phone 8.0, and Microsoft removed the Marketplace Capabilities auto-detection feature (the developer has to declare them manually in the app manifest), so we can now have drop that specific component division requirement! :)

This small change allowed to reduce the create a new Cimbalino Toolkit with just 2 NuGet packages!

There is still a lot of work to be done to port everything from the old toolkit to the new one, but here’s some of the things already working:

  • ApplicationBarBehavior, MultiApplicationBarBehavior, MultiBindingBehavior
  • StorageService, EmailComposeService, MessageBoxService, NavigationService, and others…
  • Most of the extension methods have already been ported, including the PNG support ones
  • Most of the value converters

Also, there is the need to write some new samples and documentation, so if you can I could surely use the help!!! ;)

TL;DR

Here are the new Cimbalino Toolkit NuGet packages:

Please check back soon to read about what’s new and what changed! :)

Bye Nokia… Hello Microsoft!

MicrosoftThe deal to transfer substantially all of the Nokia Devices & Services business to Microsoft has now officially been closed.

With it, I proudly become a Microsoft employee! :)

I will always cherish the moment I decided in moving to the UK to work for Nokia (even if that stopped any chance of receiving the Microsoft MVP award, but that’s another story!).

Nokia made me feel that I could actually make a difference with my work, and I truly appreciate the company for the opportunity!

I’ve been working with Microsoft technologies for more time than I can remember, both as a user and also as an IT professional, and I consider getting the “blue badge” as a giant career step for me!

In the present moment this doesn’t bring any significant changes: I’ll carry on working in the MixRadio apps here in Bristol, as I did until today!

Thank you Nokia, it’s been really fun… Hello Microsoft! :)

Cimbalino Windows Phone Toolkit Updated to v3.2.3

Cimbalino Windows Phone ToolkitVersion 3.2.3 of Cimbalino Windows Phone Toolkit is now available!

As previously indicated, this will probably be the last version still supporting Windows Phone 7…

Here’s the change log starting from version 3.2.0 to the current 3.2.3:

  • v3.2.1
    • New WebRequestExtensions
    • Ensured that MarketplaceInformationService doesn’t cache the results
  • v3.2.2
    • New EventHandlerExtensions
    • Improved the MultiBindingBehavior by adding the missing Mode property
    • Improved the ShellTileServiceTile to enable tiles update with XML data
    • Fixed a couple of issues on MarketplaceInformationService related to “beta apps”
  • v3.2.3
    • New SaveRingtoneService
    • New ScreenCaptureBehavior
    • New FrameworkElementExtensions
    • DeviceInfo, Location, and UserInfo components can now be used inside Background Agents
    • Improved ShellToastService to add the custom sound support

There are other improvements and bug fixes not stated here, but also quite important too! :)