Nico's digital footprint

I grew up in the nineties, that makes me awesome by default

A practical guide to MVVM (Light)–Part 2

by Nico

A practical guide to MVVM (Light) – Part 1

In part 1 I’ve shown you how to setup a new Windows Phone project with MVVM Light, how to hookup everything and we’ve seen what databinding is and how it works. In this part we’re going to build on that same project, delving a bit deeper into MVVM in a practical way.

Intro

In part 2 we’ll have a look at how to navigate from a list page, like the one we’ve created in part 1, to a detail page. We’ll need to inform the viewmodel on what item was clicked so that it can fetch more detailed information from the datastore. We’ll also have a look at value converters, a feature not really MVVM related but one that’s really important so I’m including it here anyway.

Navigation

There are a few ways to get navigation done in a Windows Phone app. You can use a NavigationService class for example. A class that can get injected via SimpleIoc and that has a .Navigate function, the Cimbalino Toolkit has one build-in for example. One other way to do navigation without delving into code-behind code in the view is by using Behaviors and Actions in XAML. Don’t worry, you don’t need to remember the exact syntax as long as you have Blend.

Open up the MainPage.xaml of our Part 1 project in Blend and have a look at the Assets Tab. (Quick tip: if you want to open a certain page in Blend, right-click it in Visual Studio and select “Open in Blend”, this also works for opening a page from Blend in Visual Studio).

In the Behaviors section you’ll find a bunch of Actions and Behaviors. An interesting one here is the NavigateToPageAction, drag and drop that one onto the ListBox. You’ll notice that the Action has attached itself to the ListBox if you have a look at the Objects & Timeline pane.

Before we can navigate we need to create a new page, add a page called DetailPage.xaml to the View folder of the project. Creating the page can be done from either Blend or Visual Studio. After creating the DetailPage, go back to MainPage in Blend and select the NavigateToPageAction that’s attached to the Listbox in the Objects & Timeline pane. Go to the properties.

You’ll see here that the action contains a trigger. There we can select what event from the Listbox will trigger the action, set this to SelectionChanged. In the dropdown for TargetPage you should see MainPage and DetailPage (and any other pages you might have created), set it to DetailPage and run the app. Click on an item and you’ll see that the app navigates to the detailpage. This is what the action looks like in XAML.

Code Snippet
  1. <ListBox ItemTemplate="{StaticResource PersonTemplate}" ItemsSource="{Binding Persons}">
  2.     <i:Interaction.Triggers>
  3.         <i:EventTrigger EventName="SelectionChanged">
  4.             <ec:NavigateToPageAction TargetPage="/View/DetailPage.xaml" />
  5.         </i:EventTrigger>
  6.     </i:Interaction.Triggers>
  7. </ListBox>

Loading detailed data for clicked item

When we select an item we navigate to a detail page. It would be nice to effectively show all the details. When using a ListBox this is pretty easy. We can just define a property on the viewmodel and bind the ListBox’s SelectedItem property to the property on the viewmodel. The property could look something like this

Code Snippet
  1. public Person SelectedPerson
  2. {
  3.     get { return _selectedPerson; }
  4.     set
  5.     {
  6.         if (_selectedPerson == value) return;
  7.         _selectedPerson = value;
  8.         RaisePropertyChanged(() => SelectedPerson);
  9.         LoadDetails();
  10.     }
  11. }

The binding on the ListBox would look like this

Code Snippet
  1. <ListBox ItemTemplate="{StaticResource PersonTemplate}
  2.          ItemsSource="{Binding Persons}"
  3.          SelectedItem="{Binding SelectedPerson,
  4.                                 Mode=TwoWay}">

Notice that we have to specify that this is a two-way binding. If we don’t, the property will not get updated from the view. Databinding by default is OneWay, from the viewmodel to the view.

While this is a valid way of working, it has some issues.

  • LongListSelector doesn’t support binding to SelectedItem (I described workarounds for this here and here)
  • The DetailPage needs to have MainViewModel as datacontext, which is possible and allowed but often this means that a viewmodel turns into a superclass that handles the datacontext for every view.

On to the next possibility we go!

EventToCommand

The way of passing the selecteditem from the view to the viewmodel and to the next viewmodel I’m about to describe takes a bit more setup than the previous part. However, while it is a bit more work, it’s my preferred way of working. To me this feels like the “MVVM way” but use whatever feels most comfortable for you.

Go into Blend and delete the NavigateToPageAction that is still attached to the ListBox. Go back to the Assets pane, to the list of Behaviors. You’ll find that in the list is an EventToCommand behavior. This allows us to hook up events fired by controls in the view to trigger certain actions on the viewmodel. Drag & drop the EventToCommand onto the ListBox.

Before specifying the target command for the behavior, we’ll have to add one to the viewmodel first. Windows Phone has an interface called ICommand that we can use for binding. MVVM Light comes with two implementations of ICommand called RelayCommand and RelayCommand<T>. We’re going to use the generic version RelayCommand<T> because this way we can get the event arguments into our viewmodel.

Code Snippet
  1. private RelayCommand<SelectionChangedEventArgs> _selectionChangedCommand;
  2.  
  3. public RelayCommand<SelectionChangedEventArgs> SelectionChangedCommand
  4. {
  5.     get
  6.     {
  7.         return _selectionChangedCommand ??
  8.                (_selectionChangedCommand = new RelayCommand<SelectionChangedEventArgs>(OnSelectionChanged));
  9.     }
  10. }

When using the generic version of RelayCommand we specify the type of T as the type of eventargs we’re expecting. Note that this can also be a string that’s passed in as commandparameter for example when binding to a button’s command property.

SIDENOTE – the ?? operator: If you’ve never seen the ?? operator before, it checks if whatever’s on its leftside is not null, if it is it executes whatever’s on its rightside. In this case the rightside will only get executed the very first time the command is called, that’s when the private field is instantiated.

the parameter passed into the RelayCommand<T> constructor is the action that we’ll be executing when the command is called.

Code Snippet
  1. private void OnSelectionChanged(SelectionChangedEventArgs args)
  2. {
  3.     throw new System.NotImplementedException();
  4. }

We’ll complete this in a minute, just leave it like this to make the application compile.

Bind the EventToCommand Command property to the RelayCommand either through Blend or in XAML. Make sure to check the PassEventArgsToCommand checkbox when going via Blend. This is what the XAML should look like.

Code Snippet
  1. <ListBox ItemTemplate="{StaticResource PersonTemplate}"
  2.     ItemsSource="{Binding Persons}">
  3.     <i:Interaction.Triggers>
  4.         <i:EventTrigger EventName="SelectionChanged">
  5.             <Command:EventToCommand PassEventArgsToCommand="True" Command="{Binding SelectionChangedCommand, Mode=OneWay}"/>
  6.         </i:EventTrigger>
  7.     </i:Interaction.Triggers>
  8. </ListBox>

No more SelectedItem binding. If we place a breakpoint in the OnSelectionChanged method and check the parameter you should see the selected item in there.

So far, we’re using the controls their events, using a behavior to pass the eventhandler to a command on our ViewModel. No code behind required, clean MVVM setup. The next step is to navigate to another page and pass the selected item to another viewmodel. Let’s start by navigating.

Navigating via the ViewModel

I’ve mentioned before that navigating from within the viewmodel can be done by using a NavigationService. It’s time to do just that. A NavigationService is not included in Windows Phone so we’ll either need to write one or use an existing one. I’m going to do the latter and use an existing one.

Use either NuGet or the Package manager console to add the Cimbalino Windows Phone toolkit to the project

Install-Package Cimbalino.Phone.Toolkit

Now it’s time to revisit the ViewModelLocator. Remember SimpleIoc? We used the ViewModelLocator to register services and use constructor injection to inject those services into our viewmodels. First add a using statement to the ViewModelLocator

Code Snippet
  1. using Cimbalino.Phone.Toolkit.Services;

Next, register the NavigationService in SimpleIoc. (line 14)

Code Snippet
  1. public ViewModelLocator()
  2. {
  3.     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  4.  
  5.     if (ViewModelBase.IsInDesignModeStatic)
  6.     {
  7.         // Create design time view services and models
  8.         SimpleIoc.Default.Register<IDataService, DesignDataService>();
  9.     }
  10.     else
  11.     {
  12.         // Create run time view services and models
  13.         SimpleIoc.Default.Register<IDataService, DataService>();
  14.         SimpleIoc.Default.Register<INavigationService, NavigationService>();
  15.     }
  16.  
  17.     SimpleIoc.Default.Register<MainViewModel>();
  18. }

Back to the MainViewModel, we add a new parameter to its constructor.

Code Snippet
  1. private INavigationService _navigationService;
  2. public MainViewModel(IDataService dataService, INavigationService navigationService)
  3. {
  4.      _navigationService = navigationService;

Using the NavigationService is pretty easy.

Code Snippet
  1. private void OnSelectionChanged(SelectionChangedEventArgs args)
  2. {
  3.     _navigationService.NavigateTo("/View/DetailPage.xaml");
  4. }

Do be careful with the path to the page, it’s a string so no intellisense. If the page is in a folder make sure to start with “/”. Run the app, click an item. The app should navigate to the DetailPage, just like we had before. Time to add the PersonViewModel. Add a class named PersonViewModel and make it inherit ViewModelBase, that’s enough for now.

Every new viewmodel in an MVVM Light application needs to be added to the ViewModelLocator. We need to register the viewmodel in SimpleIoc and create a property to allow databinding. First register the viewmodel in the ViewModelLocator’s constructor

Code Snippet
  1. SimpleIoc.Default.Register<PersonViewModel>();

Next is the property

Code Snippet
  1. public PersonViewModel Person
  2. {
  3.     get
  4.     {
  5.         return ServiceLocator.Current.GetInstance<PersonViewModel>();
  6.     }
  7. }

Now we can set the DetailPage’s datacontext to the PersonViewModel by adding this to the opening tag of the page.

Code Snippet
  1. DataContext="{Binding Person,
  2.                       Source={StaticResource Locator}}"

For your reference, here’s the complete tag

Code Snippet
  1. <phone:PhoneApplicationPage x:Class="MvvmDemo.View.DetailPage"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  7. xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
  8. DataContext="{Binding Person,
  9.                       Source={StaticResource Locator}}"
  10. FontFamily="{StaticResource PhoneFontFamilyNormal}"
  11. FontSize="{StaticResource PhoneFontSizeNormal}"
  12. Foreground="{StaticResource PhoneForegroundBrush}"
  13. Orientation="Portrait"
  14. SupportedOrientations="Portrait"
  15. shell:SystemTray.IsVisible="True"
  16. mc:Ignorable="d">

Messaging

Now that we have two viewmodels, we need to setup a form of communication between them. Luckily for us, MVVM Light has something in place for this called the Messenger. The Messenger is a class that receives and delivers messages. One viewmodel subscribes for a certain message, the other viewmodel sends a message and the messenger makes sure it gets delivered nicely. The messenger can take any type and send it as a message, we could for example send an entire person, or the ID of a person and send it as an integer. But in a bigger app this could get complicated, imagine if 5 viewmodels start listening for integers but one is expecting the id of a product, another one expects the id of a person while a third one expects a result of some sorts. It would be a lot of work to get the subscribe / unsubscribe just right. That’s why I advice you to make it a habit to encapsulate the data in a special message class. Like for example to send our selected person over to the PersonViewModel.

Code Snippet
  1. public class PersonSelectedMessage : MessageBase
  2. {
  3.     public Person SelectedPerson { get; set; }
  4.     public PersonSelectedMessage(Person selectedPerson)
  5.     {
  6.         SelectedPerson = selectedPerson;
  7.     }
  8. }

As you can see, this is a really simple class with only one purpose: encapsulate a Person instance. The MessageBase baseclass is an MVVM Light class that contains some info about the sender and the target but I use this mainly to make the classes easier to recognize as MVVM Light messages. I also place all those message classes in a Messages folder in my project.

Let’s subscribe to this type of message from the PersonViewModel. First add a Person property to the PersonViewModel that we can bind to.

Code Snippet
  1. private Person _selectedPerson;
  2.  
  3. public Person SelectedPerson
  4. {
  5.     get { return _selectedPerson; }
  6.     set
  7.     {
  8.         if (_selectedPerson == value) return;
  9.  
  10.         _selectedPerson = value;
  11.         RaisePropertyChanged(() => SelectedPerson);
  12.     }
  13. }

Then add this in the PersonViewModel constructor.

Code Snippet
  1. public PersonViewModel()
  2. {
  3.     Messenger.Default.Register<PersonSelectedMessage>(this, msg =>
  4.     {
  5.         SelectedPerson = msg.SelectedPerson;
  6.     });
  7. }

This registers our current instance of PersonViewModel to receive messages of the PersonSelectedMessage type. We will send this message from the MainViewModel in the OnSelectionChanged method that fires when selecting a person in the ListBox.

Code Snippet
  1. private void OnSelectionChanged(SelectionChangedEventArgs args)
  2. {
  3.     _navigationService.NavigateTo("/View/DetailPage.xaml");
  4.     Messenger.Default.Send(new PersonSelectedMessage(args.AddedItems[0] as Person));
  5. }

If you set a breakpoint in the action that fires when a message arrives and try to select a person the first time it will probably fail. This is because the message departs before the PersonViewModel has had a chance to initialize and register for the message, it will be sent but it will never arrive. If you hit the back key back to the MainPage and select another person it will arrive because the PersonViewModel instance already exists and is listening to the message. The quickest (and easiest) way to fix this is to make sure that PersonViewModel is initialized when the app launches. We can use an overload of SimpleIoc’s register method for this.

In the ViewModelLocator, add true as a parameter to the registration

Code Snippet
  1. SimpleIoc.Default.Register<PersonViewModel>(true);

This will initialize the class at the moment of registration and it will register itself as a subscriber for the PersonSelectedMessage. After binding the page title to SelectedPerson.Name and running the app this is the result:

If this was a real application you would use the action of the messenger to fetch the detailed information of the selected item. DataBinding takes care of displaying the data on screen.

Conclusion

In this second part of my practical guide to MVVM Light I’ve discusses the way I usually work to select an item from a list, navigate to a detail page and fetch / show detailed information.

Some more MVVM related articles:

Some more in depth IOC/DI articles:

Feel free to ping me on Twitter (@NicoVermeir) should you have any questions.

The code for this second part can be found on OneDrive.


Tags:

.Net | Binding | MVVM Light | Metro | Silverlight | WP7 | WP8 | WPF | WinRT | Windows 8 | XAML

IIS Express and the Windows Phone 8 emulator

by Nico

As an app developer you’re bound to run into a situation where you’re building both an app and a mobile website or REST based service. That means that you’re testing the ASP.net project in IIS Express while using the Windows Phone 8 emulator, since the emulator behaves like a separate device on the network you can’t use localhost to contact your IIS Express server.

There are a few ways to tackle this problem, you can finish the web project first and deploy it to a webserver. If your WP8 emulator is configured correctly it should have internet access and will be able to connect to your server just fine. A second option is to install an IIS server in your network and deploy to there from Visual Studio. But the most easy option would be to use the IIS Express server that comes with Visual Studio. That’s certainly an option but requires some (small) configuration tweaks.

First things first

We’ll need a webproject of course to test this. I’ll create a very very basic ASP.net WebAPI project and a very basic Windows Phone 8 app that will run in the emulator. I could have made my point with a simple hello world website and the mobile browser but that’s just boring.

Visual Studio 2012 ships with ASP.net MVC WebAPI, think REST services made ridiculously easy, to start a project select the MVC4 web template in Visual Studio 2012 and give it a name.

 

Once you click OK a second dialog will show up and that one holds the option to start a WebAPI project.

What this gives you is an MVC project with an API controller. This behaves much like the normal controller that you’re used to from MVC but instead of returning a view it returns data in a JSON format (serializing happens with JSON.net by the way, not with the .net serializer). I’m not going to dive very deep in WebAPI, there are a lot of bloggers out there that know way more about this stuff than I do. We’ll be using the default GET method from the ValuesController.

Code Snippet
  1. // GET api/values
  2. publicIEnumerable<string> Get()
  3. {
  4.     returnnewstring[] { "value1", "value2" };
  5. }

This just returns a collection of two strings.

Next step is adding a Windows Phone 8 project to the solution (a simple basic project started from the normal template). Now we have two projects in one solution that both need to start up. We could launch the api without debugging and launch the WP8 app in debug mode or we can set them both to launch at debug by selecting multiple startup projects in the solution properties.

You can easily see that the settings have applied successfully if no project in the solution is bold anymore.

Okay, time to hook them up. We’ll need two things, the IP address of the pc running IIS Express and the port that the ASP.net project will use. Getting the IP address should be easy, just enter ipconfig in a command prompt. To find out the port, navigate to the properties of the ASP.net project.

In the Web tab of the properties you can see the project url for the website, that url contains the port that will be used.

Time for some coding, in the Windows Phone app, add a constant that holds the url to the website.

Code Snippet
  1. privateconststring Url = "http://192.168.0.116:7145/";

And the code to fetch the REST data

Code Snippet
  1. privatevoid FetchData()
  2. {
  3.     WebClient client = newWebClient();
  4.  
  5.     client.DownloadStringCompleted += ClientOnDownloadStringCompleted;
  6.  
  7.     client.DownloadStringAsync(newUri(Url + "api/values"));
  8. }

The callback will use Json.net (added through NuGet) to deserialize the values into a List<string> that is then set as the ItemsSource of a LongListSelector.

Code Snippet
  1. privatevoid ClientOnDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs downloadStringCompletedEventArgs)
  2. {
  3.     if (downloadStringCompletedEventArgs.Error == null)
  4.     {
  5.         var values = JsonConvert.DeserializeObject<List<string>>(downloadStringCompletedEventArgs.Result);
  6.  
  7.         ValueList.ItemsSource = values;
  8.     }
  9. }

All in all pretty easy but this won’t work because IIS Express is bound to localhost only by default, we’ll need to change the config to allow external connections.

The configuration of IIS Express can be found in the applicationhost.config xml file found in %userprofile%\documents\IISExpress\config (just copy-paste this path into the Windows 8 start screen and press enter)

Open the XML file and search for the name of your ASP.net project. It should look something like this

Code Snippet
  1. <site name="IisExpressDemo" id="13">
  2.     <application path="/" applicationPool="Clr4IntegratedAppPool">
  3.         <virtualDirectory path="/" physicalPath="c:\users\nico\documents\visual studio 2012\Projects\IisExpressDemo\IisExpressDemo" />
  4.     </application>
  5.     <bindings>
  6.         <binding protocol="http" bindingInformation="*:7145:localhost" />
  7.     </bindings>
  8. </site>

Line 6 contains the binding, copy this line and paste it underneath, change localhost with the IP address of your pc, like this

Code Snippet
  1. <site name="IisExpressDemo" id="13">
  2.     <application path="/" applicationPool="Clr4IntegratedAppPool">
  3.         <virtualDirectory path="/" physicalPath="c:\users\nico\documents\visual studio 2012\Projects\IisExpressDemo\IisExpressDemo" />
  4.     </application>
  5.     <bindings>
  6.         <binding protocol="http" bindingInformation="*:7145:localhost" />
  7.         <binding protocol="http" bindingInformation="*:7145:192.168.0.116" />
  8.     </bindings>
  9. </site>

Close the IIS Express server if it’s still running and run the project.

Now there’s a pretty big chance that you’ll see this.

Visual Studio 2012 needs to be started as administrator to allow IIS Express to create bindings for external connections, so if you get this error, close and restart Visual Studio 2012 as an administrator.

Run the project again and the Windows Phone application should be able to fetch the data from the API.

 

Conclusion

In this post I’ve talked about opening up your IIS Express development server to allow external connections. This is needed to allow the Windows Phone 8 emulator to connect to websites or APIs hosted locally. It’s basically two steps

  • Add the IP address of your pc to the IIS config
  • Launch Visual Studio as administrator to be able to set the binding

 


Tags:

.Net | Devices | IIS | Metro | Web development | WP8

Porting a real win8 app to WP8–part 3

by Nico

It’s been a good while since I last worked on porting Comic Cloud from Windows 8 to Windows Phone. If you can still remember, the goal was to maximize code reuse by using PCL wherever possible.

Part 3 will be the last part in this series, I’m currently holding a fully functional Windows Store app and a Windows Phone 8 app that can navigate pages and sent a search query to the api using a shared service layer. Theoretically everything is shared between the two platforms except the views, which makes sense. But it still required quite a lot of tinkering to get it to work.

PCL is improving

Microsoft is working hard on bringing as many libraries to PCL as they possibly can. In part 2 of the series I already mentioned the portable HttpClient, that library finally gave us a uniform way of doing HTTP requests on multiple platforms. Between part 2 and this part Microsoft has released the PCL version of their Azure Mobile Services SDK (beware! this one has breaking changes if you’re coming over from the platform specific SDK).

Changes in my project

I decided not to use the PCL version of WAMS yet because it has breaking changes and it doesn’t help me get rid of some platform specific projects, so no real use there yet.

What I wanted to achieve for demoing purpose was to get the search functionality working on the phone. The search function on the Windows Store app uses a BlockingCollection (MSDN link) This is a thread safe collection, meaning I can safely prefetch data from one thread while loading data on the other thread. My entire search service is relying on this class (it’s an implementation of the consumer/producer pattern by the way), only problem: Windows Phone doesn’t have the BlockingCollection class. So I could either abstract the search service, change it entirely or implement my own version of the BlockingCollection. The last option seemed like the hardest one to do so I went for it. I’m not entirely sure if I got the exact same functionality of the real BlockingCollection (it does lack some methods and properties, I only implemented what I needed for my app) but here it is

Code Snippet
  1. public class BlockingCollection<T> : Queue<T>
  2. {
  3.     private readonly object _locker = new object();
  4.     private readonly Queue<T> _itemQ;
  5.     private bool _canAddItems;
  6.  
  7.     public BlockingCollection()
  8.     {
  9.         _itemQ = new Queue<T>();
  10.         _canAddItems = true;
  11.     }
  12.  
  13.     public void EnqueueItem(T item)
  14.     {
  15.         lock (_locker)
  16.         {
  17.             _itemQ.Enqueue(item); // We must pulse because we're
  18.             Monitor.Pulse(_locker); // changing a blocking condition.
  19.         }
  20.     }
  21.  
  22.     public bool TryTake(out T item, int millisecondsTimeout, CancellationToken cancellationToken)
  23.     {
  24.         cancellationToken.ThrowIfCancellationRequested();
  25.  
  26.         if (_canAddItems)
  27.         {
  28.             lock (this)
  29.             {
  30.                 try
  31.                 {
  32.                     item = Dequeue();
  33.                     return true;
  34.                 }
  35.                 catch (Exception)
  36.                 {
  37.                     item = default(T);
  38.                     return false;
  39.                 }
  40.             }
  41.         }
  42.  
  43.         item = default(T);
  44.         return false;
  45.     }
  46.  
  47.     public bool TryAdd(T item, int millisecondsTimeout, CancellationToken cancellationToken)
  48.     {
  49.         cancellationToken.ThrowIfCancellationRequested();
  50.  
  51.         if (_canAddItems)
  52.         {
  53.             lock (this)
  54.             {
  55.                 try
  56.                 {
  57.                     Enqueue(item);
  58.                     return true;
  59.                 }
  60.                 catch (Exception)
  61.                 {
  62.                     return false;
  63.                 }
  64.             }
  65.         }
  66.  
  67.         return false;
  68.     }
  69.  
  70.     public void CompleteAdding()
  71.     {
  72.         _canAddItems = false;
  73.     }
  74. }

It’s basically a Queue with some lock statements, it does work for me but I’m not responsible for any accidents that might occur Glimlach

Sharing ViewModels

All my viewmodels are in a PCL library, managed to get that to work in part 1. The ViewModelLocator can’t be made portable since some using statements are different and the WP8 version might need some other classes then the win8 version. I decided to add the Windows Store ViewModelLocator as a link into the Windows Phone 8 project, adding in some pre-processor directives made it work like a charm (I make this sound easy but it did take some time to get it just right).

Code Snippet
  1. using ComicDB.Framework;
  2. using ComicDB.SDKBroker;
  3. using ComicDB.View;
  4. using GalaSoft.MvvmLight;
  5. using GalaSoft.MvvmLight.Ioc;
  6. using Microsoft.Practices.ServiceLocation;
  7.  
  8. #if !WINDOWS_PHONE
  9. using ComicDB.Framework.WinRT;
  10. using ComicDB.SDKBroker.WinRT;
  11. #else
  12. using ComicDB.Framework.WP8;
  13. using ComicDB.SDKBroker.WP8;
  14. #endif
  15.  
  16. namespace ComicDB.ViewModel
  17. {
  18.     public class ViewModelLocator
  19.     {
  20.         public ViewModelLocator()
  21.         {
  22.             ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  23.  
  24.             if (ViewModelBase.IsInDesignModeStatic)
  25.             {
  26.                 // Create design time view services and models
  27.                 //SimpleIoc.Default.Register<IDataService, DesignDataService>();
  28.             }
  29.             else
  30.             {
  31.                 // Create run time view services and models
  32. #if !WINDOWS_PHONE
  33.                 SimpleIoc.Default.Register<ComicDB.Framework.Interface.INavigationService, ComicDB.Framework.WinRT.NavigationService>();
  34. #else
  35.                 SimpleIoc.Default.Register<ComicDB.Framework.Interface.INavigationService, ComicDB.Framework.WP8.NavigationService>();
  36. #endif
  37.                 SimpleIoc.Default.Register<IService, Service>();
  38.                 SimpleIoc.Default.Register<IMessageApi, MessageApi>();
  39.                 SimpleIoc.Default.Register<IFrameworkApi, FrameworkApi>();
  40.                 SimpleIoc.Default.Register<IDispatcher, Dispatcher>();
  41.                 SimpleIoc.Default.Register<INetworkApi, NetworkApi>();
  42.             }
  43.  
  44.             //register views
  45. #if !WINDOWS_PHONE
  46.             SimpleIoc.Default.Register<IMainPage, MainPage>();
  47.             SimpleIoc.Default.Register<IVolumeDetailPage, VolumeDetailPage>();
  48.             SimpleIoc.Default.Register<ICharacterDetailPage, CharacterDetailPage>();
  49.             SimpleIoc.Default.Register<ICollectionPage, CollectionPage>();
  50.             SimpleIoc.Default.Register<IDetailPage, DetailPage>();
  51.             SimpleIoc.Default.Register<IIssueDetailPage, IssueDetailPage>();
  52.             SimpleIoc.Default.Register<ILocationDetailPage, LocationDetailPage>();
  53.             SimpleIoc.Default.Register<INewsFeedPage, NewsFeedPage>();
  54.             SimpleIoc.Default.Register<IPersonDetailPage, PersonDetailPage>();
  55.             SimpleIoc.Default.Register<IStoryArcDetailPage, StoryArcDetailPage>();
  56.             SimpleIoc.Default.Register<ITeamDetailPage, TeamDetailPage>();
  57. #endif
  58.             //register viewmodels
  59.             SimpleIoc.Default.Register<MainViewModel>();
  60.             SimpleIoc.Default.Register<VolumeDetailViewModel>(true);
  61.             SimpleIoc.Default.Register<CharacterDetailViewModel>(true);
  62.             SimpleIoc.Default.Register<TeamDetailViewModel>(true);
  63.             SimpleIoc.Default.Register<IssueDetailViewModel>(true);
  64.             SimpleIoc.Default.Register<SearchViewModel>();
  65.             SimpleIoc.Default.Register<DetailViewModel>(true);
  66.             SimpleIoc.Default.Register<StoryArcDetailViewModel>(true);
  67.             SimpleIoc.Default.Register<LocationDetailViewModel>(true);
  68.             SimpleIoc.Default.Register<PersonDetailViewModel>(true);
  69.             SimpleIoc.Default.Register<CollectionViewModel>();
  70.             SimpleIoc.Default.Register<NewsFeedViewModel>(true);
  71.         }
  72.  
  73.         public MainViewModel Main
  74.         {
  75.             get
  76.             {
  77.                 return ServiceLocator.Current.GetInstance<MainViewModel>();
  78.             }
  79.         }
  80.         //... all other VM properties follow here, left out for demo purpose

The pre-processor directives make the class look a bit dirty but it does get the job done.

At this point the WP8 app started and showed me the mainpage, with the mainviewmodel being its datacontext. Now I wanted to add an appbar with a searchbutton, a few problems there:

  • the default appbar is not bindable (solved with Cimbalino)
  • the mainviewmodel doesn’t have a command to navigate to the searchpage since Windows Store uses the Search charm

I decided to take the quick and dirty solution here so I added a normal appbar with a button and a navigation statement in code behind. The SearchPage has SearchViewModel as datacontext. In Windows Store it was normal for the SearchText property to be immediately holding a value since it came from the Search charm, not the case in WP8. Small change to the viewmodel so that it doesn’t fire its Search function when SearchText is empty or null. This was the result after all my hard work

 

Mission accomplished!

Conclusion

PCL still has a long way to go but it is improving, and for some cases it can actually already be very useful (for example to share model classes over different platforms).

I would however advice against going for maximum code reuse, it all sounds great but the reality is very different. I had to make a lot of decisions, change quite a lot of architecture and even add missing classes (like the BlockingCollection).

My advice if you want to build a multiplatform app: use PCL to share your model, maybe even some small framework with helper classes, but build a custom implementation of service layers and viewmodels for each platform, it will save you a lot of hassle and probably even time. If you do decide to go for maximum code reuse, make sure that you really really think about it when you design your architecture, make sure that every little thing has an abstraction better one interface too many than having to rewrite a class.

Here’s a comparing screenshot between the solution before and after adding the WP8 project and refactoring everything.


Tags:

.Net | Devices | Metro | PCL | Patterns | WP8 | WinRT | Windows 8 | XAML

Porting a real win8 app to WP8–part 2

by Nico

Porting a real win8 app to WP8 – part 1

In part one of my adventure I described the architecture of my app and how I managed to move all viewmodels into a PCL (portable class library) but I didn’t use them yet. The main consensus of part one was that I needed to do quite some refactoring and add a lot of abstractions to the project in order to move over viewmodels to PCL projects. In part 2 I’ll describe how I got the viewmodels to work and how I re-enabled page navigation in the Windows 8 version. And with a bit of luck in part 3 I’ll be talking about the Windows Phone 8 version of this app.

A small note on part 1

I wasn’t very happy with part 1 since I needed to create some extra layers and abstractions. Since then the Microsoft Techdays have come and gone and with that two very interesting sessions that made me rethink some stuff. The session were from Laurent Bugnion (his blog, his Twitter) (the creator of the awesome MVVM Light toolkit) and Gill Cleeren (his blog, his Twitter) (a Belgian Silverlight MVP, RD and Win8 enthusiast). From Laurent I learned some tips and tricks concerning the ViewModelLocator class and specifically how to correctly use it in a portable library (more on that in part 3 since I haven’t implemented it yet). Gill gave a session on advanced MVVM tactics and one sentence kept vibrating in my mind “an extra class doesn’t cost a thing” next to that his demo app was filled with layers of abstractions way beyond the extra layers I needed to add to get the project to build again. After that session I felt reassured that I was going down a pretty good path with the revised architecture I had build in part 1. If you want to take a look at that session yourself, the recording of the SilverlightShow version is available here.

About part 2

The last couple of days I found some spare time to mess around with the project again. I’m now at the stage where the Windows Store app is using the portable ViewModels and the navigation is working properly. Those parts are what I’ll discuss here.

Using the ViewModels

Having the portable ViewModels ready it was time to switch to them. I deleted every viewmodel that was still in my client project, except for the ViewModelLocator, that one will be moved later. I registered the new abstraction layers in the ViewModelLocator, making sure that this only happened at runtime, not at designtime and tried to build the app. I couldn’t believe my eyes when I saw the message “Build succeeded”. I replaced the viewmodels in my client project with the ones in the portable library and it still builds! In case you’re interested, this is what’s getting registered in my ViewModelLocator at this time.

Code Snippet
  1. public ViewModelLocator()
  2. {
  3.     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  4.  
  5.     if (ViewModelBase.IsInDesignModeStatic)
  6.     {
  7.         // Create design time view services and models
  8.         //SimpleIoc.Default.Register<IDataService, DesignDataService>();
  9.     }
  10.     else
  11.     {
  12.         // Create run time view services and models
  13.         SimpleIoc.Default.Register<INavigationService, NavigationService>();
  14.         SimpleIoc.Default.Register<IService, SDKBroker.WinRT.Service>();
  15.         SimpleIoc.Default.Register<IMessageApi, MessageApi>();
  16.         SimpleIoc.Default.Register<IFrameworkApi, FrameworkApi>();
  17.         SimpleIoc.Default.Register<IDispatcher, Dispatcher>();
  18.         SimpleIoc.Default.Register<INetworkApi, NetworkApi>();
  19.     }
  20.  
  21.     //register viewmodels
  22.     SimpleIoc.Default.Register<MainViewModel>();
  23.     SimpleIoc.Default.Register<VolumeDetailViewModel>(true);
  24.     SimpleIoc.Default.Register<CharacterDetailViewModel>(true);
  25.     SimpleIoc.Default.Register<TeamDetailViewModel>(true);
  26.     SimpleIoc.Default.Register<IssueDetailViewModel>(true);
  27.     SimpleIoc.Default.Register<SearchViewModel>();
  28.     SimpleIoc.Default.Register<DetailViewModel>(true);
  29.     SimpleIoc.Default.Register<StoryArcDetailViewModel>(true);
  30.     SimpleIoc.Default.Register<LocationDetailViewModel>(true);
  31.     SimpleIoc.Default.Register<PersonDetailViewModel>(true);
  32.     SimpleIoc.Default.Register<CollectionViewModel>();
  33.     SimpleIoc.Default.Register<NewsFeedViewModel>(true);
  34. }

Everything in the else block gets registered only at runtime. The viewmodels themselves can get registered at designtime just in case I ever want to incorporate designtime test data (something I really should do actually). Notice that some ViewModel registrations get passed a boolean parameter? The Register method of SimpleIoc has an optional parameter stating whether or not the object should get instantiated immediately. Since some viewmodels are listening for messages from the Messenger class in MVVM Light they need their instance right of the bat so they can register as listeners.

I tried to run the app, it started and data was coming in, I could use the button to show the search charm but no navigation was working. That made sense since all navigation commands are now going to ISomePage instead of SomePage and those interfaces weren’t doing anything yet. So I had to make every page implement the correct interface and put together a way to navigate to the correct page from the interface.

Implementing the interface is easy enough (they’re all just empty interfaces). Next problem was that those interfaces are inside of a folder called View in the ViewModel PCL and they need to be known in the Framework.WinRT project (that’s where the NavigationService lives). So I’ve added another PCL called it ComicDB.View and moved all interfaces there. (I couldn’t reference the ViewModel project in the Framework project, it would create a circular dependency). After adding all references everything was building again but still no navigation. To get this to work I changed the Navigate method on the NavigationService from this

Code Snippet
  1. publicvirtualbool Navigate(Type destination, object parameter = null)
  2. {
  3.     try
  4.     {
  5.         _rootFrame.Navigate(destination, parameter);
  6.  
  7.         returntrue;
  8.     }
  9.     catch (Exception e)
  10.     {
  11.         returnfalse;
  12.     }
  13. }

to this

Code Snippet
  1. publicvirtualbool Navigate(Type destination, object parameter = null)
  2. {
  3.     try
  4.     {
  5.         NavigateToPage(destination, parameter);
  6.  
  7.         returntrue;
  8.     }
  9.     catch (Exception e)
  10.     {
  11.         returnfalse;
  12.     }
  13. }
  14.  
  15. privatevoid NavigateToPage(Type destination, object parameter)
  16. {
  17.     try
  18.     {
  19.         //get the implementation for the view
  20.         var instance = SimpleIoc.Default.GetInstance(destination);
  21.         var type = instance.GetType();
  22.  
  23.         _rootFrame.Navigate(type, parameter);
  24.     }
  25.     catch (ActivationException)
  26.     {
  27.         //no registered type found, just navigate to the destination, maybe it's not an interface
  28.         _rootFrame.Navigate(destination, parameter);                                
  29.     }
  30. }

The Navigate method passes everything to the NavigateToPage method that tries to resolve a registered instance of the passed in type, should this fail it throws an ActivationException, in that case just try to navigate. This allows us to navigate to pages that don’t use any interface. Once we get the instance out of the IOC we get its type and pass that into the navigate command of the frame. Obviously, before this starts working we need to register the pages in the IOC and that happens in the ViewModelLocator.

So to finish this part 2 of, here’s the complete constructor of my ViewModelLocator

Code Snippet
  1. public ViewModelLocator()
  2. {
  3.     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  4.  
  5.     if (ViewModelBase.IsInDesignModeStatic)
  6.     {
  7.         // Create design time view services and models
  8.         //SimpleIoc.Default.Register<IDataService, DesignDataService>();
  9.     }
  10.     else
  11.     {
  12.         // Create run time view services and models
  13.         SimpleIoc.Default.Register<INavigationService, NavigationService>();
  14.         SimpleIoc.Default.Register<IService, SDKBroker.WinRT.Service>();
  15.         SimpleIoc.Default.Register<IMessageApi, MessageApi>();
  16.         SimpleIoc.Default.Register<IFrameworkApi, FrameworkApi>();
  17.         SimpleIoc.Default.Register<IDispatcher, Dispatcher>();
  18.         SimpleIoc.Default.Register<INetworkApi, NetworkApi>();
  19.     }
  20.  
  21.     //register views
  22.     SimpleIoc.Default.Register<IMainPage, MainPage>();
  23.     SimpleIoc.Default.Register<IVolumeDetailPage, VolumeDetailPage>();
  24.     SimpleIoc.Default.Register<ICharacterDetailPage, CharacterDetailPage>();
  25.     SimpleIoc.Default.Register<ICollectionPage, CollectionPage>();
  26.     SimpleIoc.Default.Register<IDetailPage, DetailPage>();
  27.     SimpleIoc.Default.Register<IIssueDetailPage, IssueDetailPage>();
  28.     SimpleIoc.Default.Register<ILocationDetailPage, LocationDetailPage>();
  29.     SimpleIoc.Default.Register<INewsFeedPage, NewsFeedPage>();
  30.     SimpleIoc.Default.Register<IPersonDetailPage, PersonDetailPage>();
  31.     SimpleIoc.Default.Register<IStoryArcDetailPage, StoryArcDetailPage>();
  32.     SimpleIoc.Default.Register<ITeamDetailPage, TeamDetailPage>();
  33.  
  34.     //register viewmodels
  35.     SimpleIoc.Default.Register<MainViewModel>();
  36.     SimpleIoc.Default.Register<VolumeDetailViewModel>(true);
  37.     SimpleIoc.Default.Register<CharacterDetailViewModel>(true);
  38.     SimpleIoc.Default.Register<TeamDetailViewModel>(true);
  39.     SimpleIoc.Default.Register<IssueDetailViewModel>(true);
  40.     SimpleIoc.Default.Register<SearchViewModel>();
  41.     SimpleIoc.Default.Register<DetailViewModel>(true);
  42.     SimpleIoc.Default.Register<StoryArcDetailViewModel>(true);
  43.     SimpleIoc.Default.Register<LocationDetailViewModel>(true);
  44.     SimpleIoc.Default.Register<PersonDetailViewModel>(true);
  45.     SimpleIoc.Default.Register<CollectionViewModel>();
  46.     SimpleIoc.Default.Register<NewsFeedViewModel>(true);
  47. }

It registers all my api and service layers, all my views that have an interface and all viewmodels.

Part 2 conclusion

After a rough start in Part 1 it seems that this experiment has forced me to improve my code by making me add some abstractions. This makes for easier reusable code, both on the same platform as on other platforms. The DEV branch of my app project is once again a fully functional Windows Store app that reacts and behaves exactly as the one that’s in the store right now. The next step is to refactor out the ViewModelLocator and then it should be about time to start work on the Windows Phone version. See you in part 3!


Tags:

.Net | Devices | Metro | MVVM Light | PCL | Windows 8 | WinRT | WP8

Porting a real win8 app to WP8–part 1

by Nico

A few weeks ago the first version of my Windows 8 app (finally) hit the store (download it here).  From the start I wanted to port this application to Windows Phone 8 as well but I didn’t keep that in mind when developing the app. Some time ago, the portable HttpClient was released in a beta version and to me that was the perfect time to see how useful the portable class libraries (PCL) really are.

Most of the information available on the internet on sharing code between Windows Store and Windows Phone apps have those really small basic projects, good stuff to get started, but I want to port an entire, finished project to another platform. Perfect content for some blog posts so I’ll be documenting my progress here on my blog, hopefully it will be to some use.

The app

The app is called Comic Cloud and is a continuation of my very first Windows Phone 7 app ever. It allows users to search for anything related to comic books (volumes, issues, artists, characters, locations, …) and provides a whole bunch of information on the topic. The data comes from a community driven website (think Wikipedia for comics) called ComicVine. They have a great REST API with great documentation so that was perfect. On the other hand, and this is new in the Windows 8 version, users can start tracking their own collection of comic books and keep track of which issues in their collection are already read. This data is saved on Azure by using the awesome Azure Mobile Services, authentication happens with the Microsoft Account (single sign-on). So researching and collection are the two keywords of the application. Since the API is REST based, I make extensive use of the HttpClient class to make the API calls.

Architecture

As for architecture, all libraries are Windows Store class libraries and then off course there’s the app itself, written in C# and XAML. This image shows the projects and their dependencies.

(The app was called ComicDB in its begin stages, the namespaces stayed but the app title was changed to Comic Cloud)

The solution exists of five projects, first there’s the app itself using MVVM Light, win8nl for winRT behaviors (written by Joost van Schaik), MarkedUp for analytics, Callisto for settings fly-out, the Live SDK for the User class and the Telerik RAD controls for their controls (obviously).

The Model project contains all classes, there’s the ComicVine classes (thank God for paste JSON as class…) and some classes for RSS feeds and links.

Since I want to limit the amount of data stored in my WAMS database, I only save the userID and the link to the ComicVine API for each item. For that I needed a second version of some classes, that’s what the DTO project is for.

The framework is a project that I can reuse in other projects without changing anything, all classes that are app independent. Things like the RestClient (providing generic CRUD functions), the GroupInfoList for grouped gridviews, navigationservice to navigate between pages and so on. The ComicVineHelper is an extension method that changes the casing of some object to be compatible with the way the ComicVine API works. All these classes are implementing interfaces, so that will be a big plus when I start porting.

The SDKBroker takes all the different services I use and puts them together in one big SDK that’s easy to use from the app.

The idea

So the idea was to take all those libraries, put them in PCL libraries and reference them from both the Windows Store app and the Windows Phone app. Next to that I wanted to use the portable version of MVVM Light to share my viewmodels over both projects as well. Turns out that, as usual, a good idea is stopped by technical limitations.

The problem

The problem is the difference between Windows 8 and Windows Phone, they don’t share their entire codebase. Meaning I can’t reuse all my code in a PCL. Also the Azure Mobile Services SDK has no portable version, so same problem there.

The solution is abstractions, create an interface for every class that isn’t compatible with the PCL projects and implement them in a platform specific library. The PCLs I’m using only target .net 4.5, winRT and WP8 so a lot of problems are already taken care of by not selecting WP7.X compatibility.

The road so far

I wanted to start out by replacing MVVM Light with the PCL version. This turned out to be easier said than done, the initial project was started from the MVVM Light template so I threw out the references to MVVM Light and added the PCL version through NuGet. Visual Studio went quite mad and started throwing all sorts of weird build errors, I eventually found out that the win8nl library also includes the MVVM Light assemblies and those conflicted with the PCL versions. But I needed the win8nl assembly for the eventtocommand behaviors in WinRT so that posed a big problem. Luckily there’s the winRTBehaviors assembly that contains the logic to do behaviors but it doesn’t include the actual eventtocommand one. The solution was to go to the Codeplex site of win8nl and copy the behavior classes from there and put them in my framework project. One problem solved.

The next step was to add a PCL for the Framework and SDKBroker projects, the Model was already a PCL so that one could stay as it was. The PCL libs got named ComicDB.Framework and ComicDB.SDKBroker, they contain a combination of interfaces and classes. Everything that couldn’t be made portable was abstracted into an interface and implemented in platform specific libraries called ComicDB.Framework.WinRT and ComicDB.SDKBroker.WinRT. The classes that needed abstraction were the NavigationService, Network helper, WAMS service class and Service helper. Thanks to the new portable HttpClient assembly I could copy my RestClient class to a PCL without any adjustments.

With some tinkering I got the project to build and run again and I saw that it was good. The time had come to move my ViewModels over to a PCL. I added a new PCL project called ComicDB.ViewModel (same namespace as my VMs already had) and added the portable MVVM Light version. The ViewModelLocator can’t be moved since it needs to register all the correct interface implementations into the IOC container, so I’ll have a separate Locator class for Win8 and WP8. As I started moving ViewModels I quickly ran into a navigational problem, my viewmodels have navigation logic and the pages they are navigating to aren’t known in the PCL. To solve this I’ve created an interface for every page and set that as navigational target, I don’t know if this will work but I’ll find out soon enough and put it in part 2 if this diary.

Navigational problem solved, on to the next one. Two of my viewmodels could show toast notifications, I use the notifications helper classes from MSDN to get this done but the notification classes aren’t portable (and they really don’t need to be since Windows Phone doesn’t support in-app toasts, the C4F toolkit fixes that luckily) so I created an IMessageAPI interface that has a PopToast() method. In FrameWork.WinRT it shows a build-in toast just like the app used to do.

Hey remember that we have to do everything async now and that we can call the Dispatcher to execute something on the UI thread? Not happening in a PCL… MVVM Light contains a DispatcherHelper that checks if an action needs to be executed on the UI thread and actually executes it there when needed, except in the PCL version. So IDispatcher was born.

With that done I got my project to build again and to run but it’s currently still using the old viewmodels, I expect a whole bunch of new problems when I try to change it to the PCL versions, but that will be for part 2.

What’s next

In part 2 I hope to make the app use the PCL version of the viewmodels and I’ll start working on the Windows Phone project.

Conclusion

PCL projects sound very good in theory but in reality they are a great PITA to work with. Portable HttpClient and portable MVVM Light make them useful but you’ll have to right loads of extra code, abstractions and helper classes to get to something that looks like build once run on two platforms. I could’ve given up and just rebuild everything in a separate solution for WP8 but I want to see how far I can take this and document it along the way.

That said, I have no idea when part 2 will be live, that depends on when I can gather the courage to reference the viewmodel project Smile


Tags:

.Net | Devices | Metro | MVVM Light | PCL | Windows 8 | WinRT | WP8

SQLite in Windows Phone 8: The sequel

by Nico

Read the first part: SQLite with a bit of MVVM Light in Windows Phone 8

Last week I’ve blogged about using SQLite in an MVVM scenario in Windows Phone 8. Since, in my opinion, the post was already getting to an epic length I decided to leave out a part for this week.

I’ll try to keep it a bit shorter this time, should be able to. The part I left out was using relationships and foreign keys with SQLite and the sqlite-net library. I’ll be building upon the project of the previous post, so the task schedule thingy. What we’ll be doing is adding the possibility of creating subtasks so that a task can be divided into smaller tasks. Note that this is just a proof of concept (POC) it’s in no way a complete application and it will have some strange things but that’s the whole fun of a POC.

Let’s kick things off with the creation of a new class for holding the SubTasks.

Code Snippet
  1. [Table("SubTask")]
  2. public class SubTask : INotifyPropertyChanged
  3. {
  4.     private int _id;
  5.     private string _title;
  6.     private DateTime _date;
  7.     private int _taskId;
  8.  
  9.     [PrimaryKey, AutoIncrement]
  10.     public int Id
  11.     {
  12.         get { return _id; }
  13.         set
  14.         {
  15.             if (value == _id) return;
  16.             _id = value;
  17.             OnPropertyChanged();
  18.         }
  19.     }
  20.  
  21.     public string Title
  22.     {
  23.         get { return _title; }
  24.         set
  25.         {
  26.             if (value == _title) return;
  27.             _title = value;
  28.             OnPropertyChanged();
  29.         }
  30.     }
  31.  
  32.     public DateTime Date
  33.     {
  34.         get { return _date; }
  35.         set
  36.         {
  37.             if (value.Equals(_date)) return;
  38.             _date = value;
  39.             OnPropertyChanged();
  40.         }
  41.     }
  42.  
  43.     [Indexed]
  44.     public int TaskId
  45.     {
  46.         get { return _taskId; }
  47.         set
  48.         {
  49.             if (value == _taskId) return;
  50.             _taskId = value;
  51.             OnPropertyChanged();
  52.         }
  53.     }
  54.  
  55.     public event PropertyChangedEventHandler PropertyChanged;
  56.  
  57.     [NotifyPropertyChangedInvocator]
  58.     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  59.     {
  60.         PropertyChangedEventHandler handler = PropertyChanged;
  61.         if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
  62.     }
  63. }

By using attributes we define this class as being a column in the SQLite database and the property Id being a primary key with auto increment. This is all explained in more detail in the previous post. A new attribute here is Indexed on the TaskId property. That attribute states that that property will be an index, it will hold the primary key of the Task table.

Remember that the database was created in the App.xaml.cs? We’ll need to add a line there to create the SubTask table as well. If you haven’t shut down the emulator between the previous post and this one, or you’re testing on an actual device, you’ll need to remove the app so that the database is destroyed or the new table won’t get generated.

Code Snippet
  1. private async void Application_Launching(object sender, LaunchingEventArgs e)
  2. {
  3.     try
  4.     {
  5.         await ApplicationData.Current.LocalFolder.GetFileAsync("taskDB.db");
  6.         Connection = new SQLiteAsyncConnection("taskDB.db");
  7.     }
  8.     catch (FileNotFoundException)
  9.     {
  10.         CreateDB();
  11.     }
  12. }
  13.  
  14. private async void CreateDB()
  15. {
  16.     Connection = new SQLiteAsyncConnection("taskDB.db");
  17.  
  18.     await Connection.CreateTableAsync<Task>();
  19.     await Connection.CreateTableAsync<SubTask>();
  20. }

I’ve added the complete snippet as reference, line 19 is the new one.

Next up is the view, this will be quite similar to the Mainpage, a pivot with two pages. One containing a form for adding a new subtask and one containing a list of all subtasks.

Code Snippet
  1. <phone:PhoneApplicationPage.Resources>
  2.     <DataTemplate x:Key="TaskListItemTemplate">
  3.         <StackPanel>
  4.             <TextBlock x:Name="Title"
  5.                         Style="{StaticResource JumpListAlphabetStyle}"
  6.                         Text="{Binding Title}"
  7.                         TextWrapping="Wrap" />
  8.             <TextBlock x:Name="Date"
  9.                         Margin="12,0,0,0"
  10.                         Text="{Binding Date}"
  11.                         TextWrapping="Wrap" />
  12.             <TextBlock Text="Main task ID" TextWrapping="Wrap" />
  13.             <TextBlock Text="{Binding TaskId}" />
  14.  
  15.         </StackPanel>
  16.     </DataTemplate>
  17. </phone:PhoneApplicationPage.Resources>
  18.  
  19.  
  20. <!--  Buttons are defined using the behaviors in the Cimbalino toolkit to allow a bindable appbar  -->
  21. <phone:PhoneApplicationPage.ApplicationBar>
  22.     <shell:ApplicationBar IsMenuEnabled="True" IsVisible="True" />
  23. </phone:PhoneApplicationPage.ApplicationBar>
  24.  
  25.  
  26. <!--  LayoutRoot is the root grid where all page content is placed  -->
  27. <Grid x:Name="LayoutRoot" Background="Transparent">
  28.     <!--  Bindable Appbar buttons  -->
  29.     <i:Interaction.Behaviors>
  30.         <behaviors:ApplicationBarBehavior>
  31.             <behaviors:ApplicationBarIconButton Command="{Binding SaveNewSubTaskCommand,
  32.                                                                     Mode=OneTime}"
  33.                                                 IconUri="/Assets/AppBar/save.png"
  34.                                                 Text="Save Task" />
  35.         </behaviors:ApplicationBarBehavior>
  36.     </i:Interaction.Behaviors>
  37.  
  38.     <Grid.RowDefinitions>
  39.         <RowDefinition Height="Auto" />
  40.         <RowDefinition Height="*" />
  41.     </Grid.RowDefinitions>
  42.     <phone:Pivot Title="SQLite POC" Grid.Row="1">
  43.         <phone:PivotItem x:Name="NewTask"
  44.                             CacheMode="{x:Null}"
  45.                             Header="new subtask">
  46.             <StackPanel>
  47.                 <TextBlock Text="Main task" />
  48.                 <toolkit:ListPicker ItemsSource="{Binding Tasks}" SelectedItem="{Binding SelectedTask, Mode=TwoWay}">
  49.                     <toolkit:ListPicker.ItemTemplate>
  50.                         <DataTemplate>
  51.                             <TextBlock Text="{Binding Title}" />
  52.                         </DataTemplate>
  53.                     </toolkit:ListPicker.ItemTemplate>
  54.                 </toolkit:ListPicker>
  55.                 <TextBlock Text="Title" TextWrapping="Wrap" />
  56.                 <TextBox x:Name="TextBoxTitle"
  57.                             Height="72"
  58.                             Text="{Binding NewSubTask.Title,
  59.                                         Mode=TwoWay}"
  60.                             TextWrapping="Wrap" />
  61.                 <TextBlock Text="Complete by" TextWrapping="Wrap" />
  62.                 <toolkit:DatePicker Value="{Binding NewSubTask.Date, Mode=TwoWay}" />
  63.             </StackPanel>
  64.         </phone:PivotItem>
  65.         <phone:PivotItem x:Name="AllTasks"
  66.                             CacheMode="{x:Null}"
  67.                             Header="all subtasks">
  68.             <phone:LongListSelector ItemTemplate="{StaticResource TaskListItemTemplate}" ItemsSource="{Binding SubTasks}" />
  69.         </phone:PivotItem>
  70.     </phone:Pivot>
  71. </Grid>

The only new thing here is the ListPicker, it’s a control in the Windows Phone Toolkit (get it from NuGet) and it’s kind of like Windows Phone’s version of a combobox. The ItemTemplate is a TextBlock containing the Title of the Task.

If you want details on the bindings, read the previous post. The DataContext for this page binds to a SubTaskViewModel through the ViewModelLocator

Code Snippet
  1. DataContext="{Binding SubTask, Source={StaticResource Locator}}"

And here’s the SubTaskViewModel

Code Snippet
  1. public class SubTaskViewModel : ViewModelBase
  2. {
  3.     private readonly IDataService _dataService;
  4.     private readonly INavigationService _navigationService;
  5.  
  6.     private IList<SubTask> _subTasks;
  7.     public IList<SubTask> SubTasks
  8.     {
  9.         get
  10.         {
  11.             return _subTasks;
  12.         }
  13.  
  14.         set
  15.         {
  16.             if (Equals(_subTasks, value))
  17.             {
  18.                 return;
  19.             }
  20.  
  21.             _subTasks = value;
  22.             RaisePropertyChanged(() => SubTasks);
  23.         }
  24.     }
  25.  
  26.     private SubTask _newSubTask;
  27.     private IList<Task> _tasks;
  28.     private Task _selectedTask;
  29.  
  30.     public SubTask NewSubTask
  31.     {
  32.         get
  33.         {
  34.             return _newSubTask;
  35.         }
  36.  
  37.         set
  38.         {
  39.             if (_newSubTask == value)
  40.             {
  41.                 return;
  42.             }
  43.  
  44.             _newSubTask = value;
  45.             RaisePropertyChanged(() => NewSubTask);
  46.         }
  47.     }
  48.  
  49.     public RelayCommand SaveNewSubTaskCommand
  50.     {
  51.         get
  52.         {
  53.             return new RelayCommand(async () =>
  54.                                                 {
  55.                                                     NewSubTask.TaskId = SelectedTask.Id;
  56.                                                     await _dataService.Save(NewSubTask);
  57.                                                     SubTasks.Add(NewSubTask);
  58.                                                     NewSubTask = new SubTask { Date = DateTime.Today };
  59.                                                 });
  60.         }
  61.     }
  62.  
  63.     public IList<Task> Tasks
  64.     {
  65.         get { return _tasks; }
  66.         set
  67.         {
  68.             if (Equals(_tasks, value))
  69.             {
  70.                 return;
  71.             }
  72.  
  73.             _tasks = value;
  74.             RaisePropertyChanged(() => Tasks);
  75.         }
  76.     }
  77.  
  78.     public Model.Task SelectedTask
  79.     {
  80.         get { return _selectedTask; }
  81.         set
  82.         {
  83.             if (Equals(_selectedTask, value))
  84.             {
  85.                 return;
  86.             }
  87.  
  88.             _selectedTask = value;
  89.             RaisePropertyChanged(() => SelectedTask);
  90.         }
  91.     }
  92.  
  93.     public SubTaskViewModel(INavigationService navigationService, IDataService dataService)
  94.     {
  95.         _navigationService = navigationService;
  96.         _dataService = dataService;
  97.         SubTasks = new List<SubTask>();
  98.  
  99.         NewSubTask = new SubTask { Date = DateTime.Today };
  100.         GetData();
  101.     }
  102.  
  103.     private async void GetData()
  104.     {
  105.         Tasks = await _dataService.LoadTasks();
  106.         SubTasks = await _dataService.LoadSubTasks();
  107.     }
  108. }

In this viewmodel we’ll have a list of both the Tasks and the SubTasks because we’ll have to select a Task to attach a SubTask to. The constructor loads in the NavigationService and the DataService from the Ioc container, Tasks and SubTasks get loaded and we’re good to go. Now the navigation isn’t really what it should be in this POC, because you have to go to a Task edit page, click the Add Subtask button and then select the Task you want to create a subtask for, it’s a bit of double work but I don’t care Smile.

Remember the DataService? It’s the class that takes care of all the CRUD operations in our app, it’ll need to do the same for the subtasks. I’m a bit lazy, so I’ve only did the insert and read part. Here’s the read snippet

Code Snippet
  1. public async Task<IList<SubTask>> LoadSubTasks()
  2. {
  3.     return await App.Connection.Table<SubTask>().ToListAsync();
  4. }

Exactly the same as for reading out the Tasks. Now, for saving I altered the SaveTask function to be generic.

Code Snippet
  1. public async Task Save<T>(T newTask)
  2. {
  3.     await App.Connection.InsertAsync(newTask);
  4. }

This function takes in basically anything and saves it in the DB, if you pass something in of a type that doesn’t have a table in the DB the app will crash, hard. So be careful how you use this and you might think of adding some error handling.

And there we are, a working SQLite proof of concept with relationships and everything. Since a picture says more than a thousand words, here are some screenshots.

The Edit Task screen with the Add subtask button

The Add SubTask screen with all the Tasks in a listpicker

List of SubTasks with the Task ID

The entire project can be downloaded in a zip file here (Link to my SkyDrive).


Tags:

.Net | MVVM Light | Metro | WP8 | sqlite

SQLite with a bit of MVVM Light in Windows Phone 8

by Nico

While SQLce is still a viable solution in Windows Phone 8 to have some form of local database we also have an official SQLite implementation available. So why use SQLite when we can just keep using SQLce? Because Windows 8 only support SQLite and if you ever want to port over your app it would be nice not to have two versions of local databases to maintain. In this post I’ll explain how to implement a SQLite database into an MVVM Light Windows Phone 8 project (there is an unofficial Windows Phone 7 SQLite version as well but I have no idea how stable / buggy that is). I’ll be using Tim Heuer’s SQLite .net wrapper so we can use LINQ to SQLite instead of writing SQL queries manually (hooray for intellisense Smile). Let’s kick things off by creating an empty Windows Phone 8 app.

SQLite

Before we can use SQLite, we’ll need to install the SDK. Click here (official SQLite download page) to download the VSIX file and install it into Visual Studio.

NuGet fun

Before we can write any code we’ll need some NuGet packages. Use these commands in the Package Manager Console.

Install-Package MvvmLight

Install-Package sqlite-net

Install-Package WPtoolkit

Install-Package Cimbalino.Phone.Toolkit

Changing target platform

SQLite is a C++ library, meaning that it should be compiled against the architecture that the app will be running on. On Windows 8 that means creating separate packages for ARM and x86. On Windows Phone 8 that means switching from Any CPU to ARM when running on a device or when creating your XAP. When you’re running your app on the emulator the target platform needs to be set to x86.

Moving files around

When you  install the MVVM Light package it will add some folder structure and some files. I like to adjust this a bit more by adding a View folder and moving the MainPage into that view. That means that the startup page has to change as well. Open up the WMAppManifest.xml and change it like on the screenshot.

At this stage I couldn’t build the project because of a whole bunch of compile errors in the sqlite-net files. If you get the same problem (by the time you read this, it might be fixed), download the sqlite-net source from GitHub and from your project, add a reference to your local sqlite-net repo/lib/wp7/Community.CsharpSqlite.WinPhone.dll and that should fix it right up. Also, add a folder “Model” to the project so that our MVVM folder structure is complete.

The demo app

The app that we’ll be creating today is an app to keep track of tasks, which seems to be the new “Hello, World!”. We’ll start with the model, and work our way up to the view from there. Our class is called “Task” that means we’ll have to be careful that we use Model.Task instead of System.Threading.Task but we’ll manage.

Code Snippet
  1. [Table("Tasks")]
  2. public class Task : INotifyPropertyChanged
  3. {
  4.     private int _id;
  5.     private string _title;
  6.     private DateTime _date;
  7.  
  8.     [PrimaryKey, AutoIncrement]
  9.     public int Id
  10.     {
  11.         get { return _id; }
  12.         set
  13.         {
  14.             if (value == _id) return;
  15.             _id = value;
  16.             OnPropertyChanged("Id");
  17.         }
  18.     }
  19.  
  20.     public string Title
  21.     {
  22.         get { return _title; }
  23.         set
  24.         {
  25.             if (value == _title) return;
  26.             _title = value;
  27.             OnPropertyChanged("Title");
  28.         }
  29.     }
  30.  
  31.     public DateTime Date
  32.     {
  33.         get { return _date; }
  34.         set
  35.         {
  36.             if (value.Equals(_date)) return;
  37.             _date = value;
  38.             OnPropertyChanged("Date");
  39.         }
  40.     }
  41.  
  42.     public event PropertyChangedEventHandler PropertyChanged;
  43.     protected virtual void OnPropertyChanged(string propertyName = null)
  44.     {
  45.         PropertyChangedEventHandler handler = PropertyChanged;
  46.         if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
  47.     }
  48. }

The “Task” class implements INotifyPropertyChanged so that controls that are bound to its properties get updated like good citizens. Now for the annotations, those come from sqlite-net and mark this class as a table in the database. The same goes for the annotations on the Id property, that property is marked as being the primarykey and being an autoincremented value. If you have a property that you don’t want in the database, add the [Ignore] attribute and there won’t be any column generated for it. Now that we have a model we can start working on the service, the class that will do all the SQLite communication. (Yes we could do all this in the viewmodel but it’s called seperation of concerns Smile). And to do this the right way we’ll start by creating an interface for the service.

Code Snippet
  1. public interface IDataService
  2. {
  3.     Task SaveTask(Model.Task newTask);
  4.     Task<IList<Model.Task>> LoadTasks();
  5.     Task UpdateTask(Model.Task selectedTask);
  6.     Task DeleteTask(Model.Task selectedTask);
  7. }

Those are all the basic CRUD (Create, Read, Update, Delete) that we can (should be able to) perform on any datacontainer. Here’s the implementation

Code Snippet
  1. public class DataService : IDataService
  2. {
  3.     public async Task SaveTask(Model.Task newTask)
  4.     {
  5.         await App.Connection.InsertAsync(newTask);
  6.     }
  7.  
  8.     public async Task<IList<Model.Task>> LoadTasks()
  9.     {
  10.         return await App.Connection.Table<Model.Task>().ToListAsync();
  11.     }
  12.  
  13.     public async Task UpdateTask(Model.Task selectedTask)
  14.     {
  15.         await App.Connection.UpdateAsync(selectedTask);
  16.     }
  17.  
  18.     public async Task DeleteTask(Model.Task selectedTask)
  19.     {
  20.         await App.Connection.DeleteAsync(selectedTask);
  21.     }
  22.  
  23.     public async Task<IList<SubTask>> LoadSubTasks()
  24.     {
  25.         return await App.Connection.Table<SubTask>().ToListAsync();
  26.     }
  27. }

Hmm looks like I forgot to mention something, go to App.xaml.cs and add this property

Code Snippet
  1. public static SQLiteAsyncConnection Connection { get; set; }

Keep App.xaml.cs open, we’ll need it in a minute. In the DataService class we’re calling all the CRUD methods provided to us by sqlite-net. We can get a list of all records in a table by calling .Table<T>().ToListAsync() or do any of the other CRUD operations by just calling the function and passing in the modified POCO. Really easy and quite powerful.

Let’s jump back to App.xaml.cs, there should be an empty function called Application_Launching. In this function we’ll need to check if the database exists, open a connection to it if it exists or create it first and then open the connection.

Code Snippet
  1. private async void Application_Launching(object sender, LaunchingEventArgs e)
  2. {
  3.     try
  4.     {
  5.         await ApplicationData.Current.LocalFolder.GetFileAsync("taskDB.db");
  6.         Connection = new SQLiteAsyncConnection("taskDB.db");
  7.     }
  8.     catch (FileNotFoundException)
  9.     {
  10.         CreateDB();
  11.     }
  12. }

Unfortunately, there is no DataBaseExists() function like in SQLce so I choose to do it the quick and dirty way. I try to get the database, which is basically a file in the ApplicationData, if the file doesn’t exist it will throw a FileNotFoundException and that’s where I call the CreateDB() method.

Code Snippet
  1. private async void CreateDB()
  2. {
  3.     Connection = new SQLiteAsyncConnection("taskDB.db");
  4.  
  5.     await Connection.CreateTableAsync<Task>();
  6. }

Line 3 creates the database while line 5 creates the Task table in the database. When all that’s in place, we’re ready to move to the viewmodels.

ViewModel

Not much to say here, we all know what a viewmodel is, so here is the MainViewModel.

Code Snippet
  1. public class MainViewModel : ViewModelBase
  2. {
  3.     private readonly IDataService _dataService;
  4.     private readonly INavigationService _navigationService;
  5.  
  6.     /// <summary>
  7.     /// The <see cref="Tasks" /> property's name.
  8.     /// </summary>
  9.     public const string TasksPropertyName = "Tasks";
  10.  
  11.     private IList<Task> _tasks;
  12.  
  13.     /// <summary>
  14.     /// Sets and gets the Tasks property.
  15.     /// Changes to that property's value raise the PropertyChanged event.
  16.     /// </summary>
  17.     public IList<Task> Tasks
  18.     {
  19.         get
  20.         {
  21.             return _tasks;
  22.         }
  23.  
  24.         set
  25.         {
  26.             if (Equals(_tasks, value))
  27.             {
  28.                 return;
  29.             }
  30.  
  31.             RaisePropertyChanging(TasksPropertyName);
  32.             _tasks = value;
  33.             RaisePropertyChanged(TasksPropertyName);
  34.         }
  35.     }
  36.        
  37.     /// <summary>
  38.     /// The <see cref="NewTask" /> property's name.
  39.     /// </summary>
  40.     public const string NewTaskPropertyName = "NewTask";
  41.  
  42.     private Task _newTask;
  43.  
  44.     /// <summary>
  45.     /// Sets and gets the NewTask property.
  46.     /// Changes to that property's value raise the PropertyChanged event.
  47.     /// </summary>
  48.     public Task NewTask
  49.     {
  50.         get
  51.         {
  52.             return _newTask;
  53.         }
  54.  
  55.         set
  56.         {
  57.             if (_newTask == value)
  58.             {
  59.                 return;
  60.             }
  61.  
  62.             RaisePropertyChanging(NewTaskPropertyName);
  63.             _newTask = value;
  64.             RaisePropertyChanged(NewTaskPropertyName);
  65.         }
  66.     }
  67.  
  68.     public RelayCommand SaveNewTaskCommand
  69.     {
  70.         get { return new RelayCommand(SaveNewTask); }
  71.     }
  72.  
  73.     public RelayCommand<SelectionChangedEventArgs> SelectionChangedCommand
  74.     {
  75.         get { return new RelayCommand<SelectionChangedEventArgs>(SelectionChanged);}
  76.     }
  77.  
  78.     /// <summary>
  79.     /// Initializes a new instance of the MainViewModel class.
  80.     /// </summary>
  81.     public MainViewModel(IDataService dataService, INavigationService navigationService)
  82.     {
  83.         _dataService = dataService;
  84.         _navigationService = navigationService;
  85.         NewTask = new Task { Date = DateTime.Today };
  86.  
  87.         LoadTasks();
  88.     }
  89.  
  90.     private async void LoadTasks()
  91.     {
  92.         Tasks = await _dataService.LoadTasks();
  93.     }
  94.  
  95.     private async void SaveNewTask()
  96.     {
  97.         await _dataService.SaveTask(NewTask);
  98.         Tasks.Add(NewTask);
  99.         NewTask = new Task { Date = DateTime.Today };
  100.     }
  101.  
  102.     private void SelectionChanged(SelectionChangedEventArgs args)
  103.     {
  104.         if (args.AddedItems.Count > 0)
  105.         {
  106.             Messenger.Default.Send(new TaskSelectedMessage(args.AddedItems[0] as Task));
  107.             _navigationService.NavigateTo(new Uri(@"/View/EditPage.xaml", UriKind.Relative));
  108.         }
  109.     }
  110. }

The IDataService field is what we’ve defined just a minute ago, it gets instantiated through the constructor. INavigationService comes from the Cimbalino toolkit, it allows us to do page to page navigation from within the viewmodels. There’s a property of IList<Task> that one will hold all the available tasks, they are loaded at startup, also newly added tasks will be put in that list. There’s a property of type Task, his properties will be bound to the input fields on the new task form, when the user clicks save the property will be pushed to the dataservice to save it in the database. Talking about the save button, there are two RelayCommands (MVVM Light’s implementation of ICommand). One is for saving a new property and the second one is for navigating to the detail page when a task is selected. In the constructor both fields are set and the Task property is initialized, setting the date to today. Since our datepicker will be bound to this property it will automatically be set to today’s date. Loading all the tasks needs to be done asynchronous, since the constructor can’t be marked as async we’ll put the service call in a synchronous method and call that one from the constructor, that way we can use the async / await keywords. Saving a task is as easy as calling the SaveTask function on IDataService and adding the new task to the list, and reinitializing it afterwards to clear all the fields. You might want to think about adding some check here in case something goes wrong while saving to the DB (have it return a boolean for example), I’ll just be living on the edge here and assume this never fails Smile. For navigating to the detail page we’ll add a command to the SelectionChanged event of our LongListSelector. We use the MVVM Light messenger, some sort of implementation of the Observer pattern, to send over the selected item to anyone registered to listen to a message of type TaskSelectedMessage. The TaskSelectedMessage class is pretty basic.

Code Snippet
  1. public class TaskSelectedMessage : MessageBase
  2. {
  3.     public Model.Task Task { get; set; }
  4.  
  5.     public TaskSelectedMessage(Model.Task task)
  6.     {
  7.         Task = task;
  8.     }
  9. }

The class inherits from MessageBase, which is a class in the MVVM Light library, it has one property that is set in the constructor (that’s just to make life a bit easier).

In the MainViewModel, when the SelectionChanged event fires we send a message of this type containing the selected item, once the message is on its way we use the INavigationService to navigate to the detail page.

Here’s the  viewmodel for the editpage.

Code Snippet
  1. public class EditViewModel : ViewModelBase
  2. {
  3.     private readonly IDataService _dataService;
  4.     private readonly INavigationService _navigationService;
  5.  
  6.     /// <summary>
  7.     /// The <see cref="SelectedTask" /> property's name.
  8.     /// </summary>
  9.     public const string SelectedTaskPropertyName = "SelectedTask";
  10.  
  11.     private Task _selectedTask;
  12.  
  13.     /// <summary>
  14.     /// Sets and gets the SelectedTask property.
  15.     /// Changes to that property's value raise the PropertyChanged event.
  16.     /// </summary>
  17.     public Task SelectedTask
  18.     {
  19.         get
  20.         {
  21.             return _selectedTask;
  22.         }
  23.  
  24.         set
  25.         {
  26.             if (_selectedTask == value)
  27.             {
  28.                 return;
  29.             }
  30.  
  31.             RaisePropertyChanging(SelectedTaskPropertyName);
  32.             _selectedTask = value;
  33.             RaisePropertyChanged(SelectedTaskPropertyName);
  34.         }
  35.     }
  36.  
  37.     public RelayCommand UpdateTaskCommand
  38.     {
  39.         get { return new RelayCommand(UpdateTask); }
  40.     }
  41.  
  42.     public RelayCommand DeleteTaskCommand
  43.     {
  44.         get { return new RelayCommand(DeleteTask); }
  45.     }
  46.  
  47.     public EditViewModel(IDataService dataService, INavigationService navigationService)
  48.     {
  49.         _dataService = dataService;
  50.         _navigationService = navigationService;
  51.  
  52.         Messenger.Default.Register<TaskSelectedMessage>(this, msg => SelectedTask = msg.Task);
  53.     }
  54.  
  55.     private void UpdateTask()
  56.     {
  57.         _dataService.UpdateTask(SelectedTask);
  58.     }
  59.  
  60.     private void DeleteTask()
  61.     {
  62.         _dataService.DeleteTask(SelectedTask);
  63.     }
  64. }

The same fields can be found here (I could put them in a base class, would be cleaner but who cares about clean code anyway? – well you should all care!). One property in this viewmodel, to hold the selected task and bind its properties to the view. A few commands for update and delete, they just call their respective functions on the DataService passing in the selected Task. The interesting part here is in the constructor. The fields get set and we register the viewmodel to listen if the messenger has a message of type TaskSelectedMessage, if it does set the task in the message to the property. However, the viewmodel by default gets instantiated when we navigate to the view meaning that the message has left the building before the receiver has registered as a receiver so it won’t arrive. Let’s fix that shall we? When you’ve added the MVVM Light libraries through NuGet (or you used the MVVM Light project templates) there should be a ViewModelLocator class in your ViewModel folder. This class registers your viewmodels in the TinyIoc container. Registering those viewmodels has an overload that, when set to True, creates an instance of each viewmodel at application launch, meaning that the viewmodels register themselves on the messenger before any message can be send. Here are my viewmodel registrations (from the ViewModelLocator constructor).

Code Snippet
  1. SimpleIoc.Default.Register<MainViewModel>();
  2. SimpleIoc.Default.Register<EditViewModel>(true);

MainViewModel won’t get instantiated at registration but EditViewModel will. So that’s a problem solved. Next piece of the puzzle are those constructor parameters in the viewmodels. They get resolved by dependency injection, we register the correct types here in the ViewModelLocator and when the viewmodel constructor is called, the correct instances will get injected automagically.

Code Snippet
  1. if (ViewModelBase.IsInDesignModeStatic)
  2. {
  3.     // Create design time view services and models
  4.     SimpleIoc.Default.Register<IDataService, DesignService>();
  5. }
  6. else
  7. {
  8.     // Create run time view services and models
  9.     SimpleIoc.Default.Register<IDataService, DataService>();
  10.     SimpleIoc.Default.Register<INavigationService, NavigationService>();
  11. }

Take this for example, when we are in design mode (Blend for example) we can load an IDataService implementation that returns dummy data so that we can style our views very easily (code gets executed when running at designtime so even when you’re not using dummy data it’s a good idea to register these types in an if-block to prevent design time errors).

What everything in place, let’s have a look at the xaml and hook everything up. We’ll start with the MainPage.xaml and since XAML has a tendency of growing quite large, I’ll chop it in pieces. First thing a page needs in an MVVM scenario is a DataContext, meaning our ViewModel. This can be set from code behind (DataContext = new MainViewModel()) but that would just null out every use of the ViewModelLocator. We’ll set the datacontext from XAML.

Code Snippet
  1. <phone:PhoneApplicationPage x:Class="SqLitePoc.View.MainPage"
  2.                             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.                             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.                             xmlns:command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8"
  5.                             xmlns:behaviors="clr-namespace:Cimbalino.Phone.Toolkit.Behaviors;assembly=Cimbalino.Phone.Toolkit"
  6.                             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  7.                             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
  8.                             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  9.                             xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  10.                             xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
  11.                             xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
  12.                             DataContext="{Binding Main,
  13.                                                   Source={StaticResource Locator}}"
  14.                             FontFamily="{StaticResource PhoneFontFamilyNormal}"
  15.                             FontSize="{StaticResource PhoneFontSizeNormal}"
  16.                             Foreground="{StaticResource PhoneForegroundBrush}"
  17.                             Orientation="Portrait"
  18.                             SupportedOrientations="Portrait"
  19.                             shell:SystemTray.IsVisible="True"
  20.                             mc:Ignorable="d">

The key here is DataContext="{Binding Main, Source={StaticResource Locator}}" this says to the view that its datacontext is bound to a property called Main and that property lives in a resource called Locator (that resource is defined in App.xaml). Now for the page itself, the page consists of a pivot control with two pivot pages, one for entering new tasks and one for viewing a list of all the tasks that have been created so far.

Code Snippet
  1. <!--  LayoutRoot is the root grid where all page content is placed  -->
  2. <Grid x:Name="LayoutRoot" Background="Transparent">
  3.     <!--  Bindable Appbar buttons  -->
  4.     <i:Interaction.Behaviors>
  5.         <behaviors:ApplicationBarBehavior>
  6.             <behaviors:ApplicationBarIconButton Command="{Binding SaveNewTaskCommand, Mode=OneTime}" IconUri="/Assets/AppBar/save.png" Text="Save Task" />
  7.         </behaviors:ApplicationBarBehavior>
  8.     </i:Interaction.Behaviors>
  9.  
  10.     <Grid.RowDefinitions>
  11.         <RowDefinition Height="Auto" />
  12.         <RowDefinition Height="*" />
  13.     </Grid.RowDefinitions>
  14.     <phone:Pivot Title="SQLite POC" Grid.Row="1">
  15.         <phone:PivotItem x:Name="NewTask" CacheMode="{x:Null}" Header="new task">
  16.             <StackPanel>
  17.                 <TextBlock Text="Title" TextWrapping="Wrap" />
  18.                 <TextBox x:Name="TextBoxTitle"
  19.                             Height="72"
  20.                             Text="{Binding NewTask.Title, Mode=TwoWay}"
  21.                             TextWrapping="Wrap" />
  22.                 <TextBlock Text="Complete by" TextWrapping="Wrap" />
  23.                 <toolkit:DatePicker Value="{Binding NewTask.Date, Mode=TwoWay}" />
  24.             </StackPanel>
  25.         </phone:PivotItem>
  26.         <phone:PivotItem x:Name="AllTasks" CacheMode="{x:Null}" Header="all tasks">
  27.             <phone:LongListSelector ItemTemplate="{StaticResource TaskListItemTemplate}" ItemsSource="{Binding Tasks}">
  28.                 <i:Interaction.Triggers>
  29.                     <i:EventTrigger EventName="SelectionChanged">
  30.                         <command:EventToCommand Command="{Binding SelectionChangedCommand}" PassEventArgsToCommand="True" />
  31.                     </i:EventTrigger>
  32.                 </i:Interaction.Triggers>
  33.             </phone:LongListSelector>
  34.         </phone:PivotItem>
  35.     </phone:Pivot>
  36. </Grid>

First thing in this snippet is a behavior for a bindable appbar button. The default appbar is not bindable, meaning that you can’t bind the buttons Command property to an ICommand on your viewmodel. This wasn’t the case in WP7 and it still isn’t in WP8, bit of a pain. Luckily, Cimbalino toolkit gives us an ApplicationBarBehavior, allowing us to bind our ICommands to the appbar, the only trade off we need to make is that the appbar buttons won’t be visible at design time but that’s a small trade-off in my opinion. We’ll add one button in the appbar, bind it to the SaveNewTaskCommand RelayCommand in MainViewModel and appoint it the save icon. Then there’s the pivot control, first pivotitem contains a stackpanel with a textbox for entering a task title and a datepicker (courtesy of the Windows Phone Toolkit) both are bound to properties of the NewTask property on the MainViewModel. Don’t forget to set the bind mode to TwoWay so that we can update the properties from our view. The second pivot item contains a list of all the tasks. Now, in WP8 they advice us to use the LongListSelector instead of the listbox that’s all great but at least make it behave more like a listbox and not some crippled dependency property missing piece of ****. The problem lies in the SelectedItem property, myself and many other XAML devs usually create a SelectedTask property and bind it to the SelectedItem property of the ListBox, the setter of that SelectedTask property would then be used to navigate to the detailspage. That was a clean, fast solution but the LongListSelector’s SelectedItem property is not a dependency property, meaning it cannot be bound so that’s not a viable solution anymore. Second option would be to bind an ICommand to the SelectionChanged event, again a no-go. There are some implementations of the LongListSelector floating around on the internet that has a bindable SelectedItem property so that would be a solution, another one is to add an EventToCommand behavior and binding the SelectionChanged event to the MainViewModel in the behavior (that’s right Windows 8 devs, we Windows Phone devs still get behaviors out of the box). I’m going with the EventToCommand solution, only thing I haven’t solved here is that when we navigate to the detail page, navigate back to the mainpage and click the same task again it won’t do anything anymore since that item still is the selected item so the selection doesn’t change and the event doesn’t fire. A solution here would be to use the messenger to send a message to the code behind of the view to set the SelectedItem property of the LongListSelector to null.

tl;dr version: LongListSelector kind off sucks but it can be solved.

The LongListSelector is bound to the Tasks collection, the ItemTemplate is defined in the resources part of the page

Code Snippet
  1. <phone:PhoneApplicationPage.Resources>
  2.     <DataTemplate x:Key="TaskListItemTemplate">
  3.         <StackPanel>
  4.             <TextBlock x:Name="Title"
  5.                        Style="{StaticResource JumpListAlphabetStyle}"
  6.                        Text="{Binding Title}"
  7.                        TextWrapping="Wrap" />
  8.             <TextBlock x:Name="Date"
  9.                        Margin="12,0,0,0"
  10.                        Text="{Binding Date}"
  11.                        TextWrapping="Wrap">
  12.                 <Run />
  13.                 <LineBreak />
  14.                 <Run />
  15.             </TextBlock>
  16.         </StackPanel>
  17.     </DataTemplate>
  18. </phone:PhoneApplicationPage.Resources>

That gives the list a nice look (as far as I can tell that is, I really really suck at designing apps…)

Last part on this page is the appbar itself, the button are defined using the Cimbalino toolkit but we need to actually put an appbar on the page, this sits between the resources and the LayoutRoot grid.

Code Snippet
  1. <!--  Buttons are defined using the behaviors in the Cimbalino toolkit to allow a bindable appbar  -->
  2. <phone:PhoneApplicationPage.ApplicationBar>
  3.     <shell:ApplicationBar IsMenuEnabled="True" IsVisible="True" />
  4. </phone:PhoneApplicationPage.ApplicationBar>

And that’s it for the MainPage, on to the final part of this post, the EditPage.xaml

First, the datacontext

Code Snippet
  1. DataContext="{Binding Edit, Source={StaticResource Locator}}"

Then the appbar buttons, again using Cimbalino (these need to sit in the LayoutRoot grid)

Code Snippet
  1. <!--  Bindable Appbar buttons  -->
  2. <i:Interaction.Behaviors>
  3.     <behaviors:ApplicationBarBehavior>
  4.         <behaviors:ApplicationBarIconButton Command="{Binding UpdateTaskCommand, Mode=OneTime}" IconUri="/Assets/AppBar/save.png" Text="Save Task" />
  5.         <behaviors:ApplicationBarIconButton Command="{Binding DeleteTaskCommand, Mode=OneTime}" IconUri="/Toolkit.Content/ApplicationBar.Delete.png" Text="Save Task" />
  6.     </behaviors:ApplicationBarBehavior>
  7. </i:Interaction.Behaviors>

And then there’s the controls

Code Snippet
  1. <!--  TitlePanel contains the name of the application and page title  -->
  2. <StackPanel Grid.Row="0" Margin="12,17,0,28">
  3.     <TextBlock Style="{StaticResource PhoneTextNormalStyle}" Text="SQLite POC" />
  4.     <TextBlock Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" Text="Edit Task" />
  5. </StackPanel>
  6.  
  7. <!--  ContentPanel - place additional content here  -->
  8. <Grid x:Name="ContentPanel"
  9.       Grid.Row="1"
  10.       Margin="12,0,12,0">
  11.     <StackPanel Margin="0,0,0,76">
  12.         <TextBlock Text="Title" TextWrapping="Wrap" />
  13.         <TextBox x:Name="TextBoxTitle" Height="72" Text="{Binding SelectedTask.Title, Mode=TwoWay}" TextWrapping="Wrap" />
  14.         <TextBlock Text="Complete by" TextWrapping="Wrap" />
  15.         <toolkit:DatePicker Value="{Binding SelectedTask.Date, Mode=TwoWay}" />
  16.     </StackPanel>
  17. </Grid>

That’s all pretty much the same as in the MainPage. And with that our small SQLite POC is finished.

Conclusion

In this post I’ve discussed SQLite in a Windows Phone 8 app. What you should take away from this is that as of Windows Phone 8 SQLite is a first class citizen, even more so when using the excellent sqlite-net library. Don’t forget to switch the platform when running on emulator or on a device, this is necessary because SQLite is a C++ library. I’ve also talked a bit about MVVM Light and the way I use it, I don’t claim that this is the best / only way to use the excellent MVVM implementation by Laurent Bugnion but it is one I feel comfortable with and that gives me great results. If you have any questions / remarks, feel free to drop a comment!

 

UPDATE:

for the LongListSelector, you can also use an extension of the control instead of defining a trigger, see http://stackoverflow.com/questions/14586521/bind-viewmodel-to-item-from-longlistselector-in-datatemplate/14600157#14600157 for more detail.
thanks for the tip Glenn (link to Glenn’s Twitter)!


Tags:

.Net | Binding | MVVM Light | Metro | Patterns | WP8 | WP7 | XAML

Copying Nokia’s Photobeamer with SignalR and WP8

by Nico

Some time ago Nokia launched a pretty impressive, almost magical app called “Photobeamer” (exclusive for the Nokia Lumia range). This is one of those apps that look very impressive and magical at first but when you start to think about it it’s not really that hard to figure out how this works. I thought about it and decided to hack together a copy of this.

If you have no clue what Photobeamer is all about, check out this video from Pocketnow

Disclaimer

Small remark about this video before we get started. The Nokia Photobeamer caches every image for about 30 days, meaning that if you select the same picture again it appears almost instantly, that’s what happens in this video. We will get nowhere near that performance since my concept here doesn’t do any caching. Also, they are streaming the image to the server (hence the fact that the picture is blurry at first and sharpens up later) we will just send over the entire image at once.

Puzzle pieces

All right, let’s get started. We need a few pieces to complete this puzzle. We need a Windows Phone app, we’ll need a service that takes care of sending the right picture to the right client and we’ll need a web client to display the QR code and the picture.

This schematic shows the pieces and their roles

The steps are:

  • webclient generates unique ID (guid)
  • webclient registers a group on the server with that ID
  • webclients uses ID to generate QR code
  • user launches Windows Phone app
  • user selects picture
  • user scans QR code to get the generated ID
  • phone app joins the group with the ID
  • phone app deserializes the picture
  • phone app sends the picture to the other group members
  • webclient receives picture, serializes it again and shows it

Lots of steps but it’s easier to build as you might think. We’ll start with the service as that’s the glue to hold everything together.

SignalR

Since we need some form of real-time communication I’ve decided to use SignalR. A snippet from the SignalR page that describes its functionality (http://signalr.net/):

ASP.NET SignalR is a new library for ASP.NET developers that makes it incredibly simple to add real-time web functionality to your applications. What is "real-time web" functionality? It's the ability to have your server-side code push content to the connected clients as it happens, in real-time.

You may have heard of WebSockets, a new HTML5 API that enables bi-directional communication between the browser and server. SignalR will use WebSockets under the covers when it's available, and gracefully fallback to other techniques and technologies when it isn't, while your application code stays the same.

All we need to get started is an empty web project and a nuget package use the package manager or the GUI

Code Snippet
  1. Install-Package Microsoft.AspNet.SignalR -Pre

SignalR, at the time of writing, is in Release Candidate, so we need to include prerelease versions in Nuget or you won’t find signalR at all. (although it’s prerelease, SignalR is working really well so no worries)

Before we start building the service we need to add some method calls in Global.asax.cs in the Application_Start method.

Code Snippet
  1. void Application_Start(object sender, EventArgs e)
  2. {
  3.     // Code that runs on application startup
  4.     AuthConfig.RegisterOpenAuth();
  5.  
  6.     GlobalHost.HubPipeline.EnableAutoRejoiningGroups();
  7.  
  8.     // Register the default hubs route: ~/signalr/hubs
  9.     RouteTable.Routes.MapHubs();
  10. }

The MapHubs() makes sure that the service calls are rerouted to the correct functions. The EnableAutoRejoiningGroups() is something that we need to do in this RC2 version but it will go away in RTM, see my StackOverflow question for more information.

SignalR uses the concept of Hubs, a hub is a class that contains all the service calls. Add a class called ImgHub to a folder called Hubs in the empty web project.

Code Snippet
  1. publicclassImgHub : Hub
  2. {
  3.     publicvoid Create(string guid)
  4.     {
  5.         Groups.Add(Context.ConnectionId, guid);
  6.     }
  7.     
  8.     publicvoid ShareImage(byte[] image, string guid)
  9.     {
  10.         Clients.OthersInGroup(guid).ReceiveImage(image);
  11.     }
  12.  
  13.     publicvoid Leave(string guid)
  14.     {
  15.         Groups.Remove(Context.ConnectionId, guid);
  16.     }
  17. }

That’s really not a lot of code for a service. First, every hub in a SignalR project needs to inherit from Microsoft.AspNet.SignalR.Hub. Next to that, every public method we declare in this class will be callable from the clients. First method is Create(), this takes in the unique ID that will be generated by the webclient in a minute. That ID is used to create a group. SignalR tries to add the connectionId from the client to a group with the guid as groupname. If that group doesn’t exist yet it will create it. The second method is ShareImage. This will take in the deserialized image (as a byte array) and that same guid again. Now we need to send that byte array to other clients so we call Clients.OthersInGroup, other options are Clients.All, Clients.Groups, Clients.Others, Clients.Caller, Clients.AllExcept. Plenty of choices but OthersInGroup suits our needs the best. The OthersInGroup returns a dynamic object, we can attach anything we want here. We want to call ReceiveImage() on the client, that method isn’t declared anywhere but since the object is dynamic the compiler won’t give us any trouble. And finally there’s a Leave() method allowing us to leave a group should it be needed.

The SignalR project can be hosted on any webhost that supports .net, for this demo I’ve used Windows Azure Websites.

Webclient

1/3th done, the second part is the webclient. This is a normal website using asp.net webforms. It’s responsible for generating the ID, passing it to SignalR to create the group, get a QR code and receive the image.

First thing we need is the project, second is a SignalR client and the SignalR Javascript library (yes we’ll be needing Javascript and no I’m not proud of this…)

First some HTML code, the Default.aspx page is nothing fancy, it will only show the QR code.

Code Snippet
  1. <body>
  2.     <formid="form1"method="post"action="ImagePage.aspx">
  3.         <inputtype="hidden"id="hiddenByteArray"name="hiddenByteArray"/>
  4.         <div>
  5.             <imgsrc="/imagehandler.ashx"style="text-align: center"/>
  6.         </div>
  7.     </form>
  8. </body>

Notice the imagehandler.ashx reference? That’s a generic handler that will take care of generating the QR code and passing it into this img tag. Generic handler is a file type that you can add through Visual Studio, here’s the code for imagehandler.ashx.

Code Snippet
  1. publicclassImageHandler : IHttpHandler, IRequiresSessionState
  2. {
  3.     publicvoid ProcessRequest(HttpContext context)
  4.     {
  5.         var guid = HttpContext.Current.Session["InstanceGuid"];
  6.  
  7.         string url = string.Format(@"http://api.qrserver.com/v1/create-qr-code/?size=300x300&data={0}", guid);
  8.  
  9.         WebClient client = newWebClient();
  10.         var bytes = client.DownloadData(newUri(url));
  11.  
  12.         context.Response.OutputStream.Write(bytes, 0, bytes.Length);
  13.         context.Response.ContentType = "image/JPEG";
  14.     }
  15.  
  16.     publicbool IsReusable
  17.     {
  18.         get
  19.         {
  20.             returnfalse;
  21.         }
  22.     }
  23. }

We’re getting our guid from the session object (how it got there, we’ll see in a minute) that’s why we need the IRequiresSessionState interface. The ProcessRequest method we get from IHttpHandler and will get executed when the handler is called. So we first get the guid from the session, then we’ll build a url to qpi.qrserver.com, an api that takes in a value and generates a QR code from that value. We use WebClient to get the data from that url, the byte array that we receive from it will be our generated QR code, we write it to the outputstream of the page’s context and set the type to be an image/JPEG. There should be some error handling here if you’re using this for production code (sometimes the qrserver API takes to long and times out).

Next, we’ll have a look at Default.aspx.cs.

Code Snippet
  1. protectedvoid Page_Load(object sender, EventArgs e)
  2. {
  3.     var guid = Guid.NewGuid();
  4.     HttpContext.Current.Session["InstanceGuid"] = guid.ToString();
  5. }

Not much going on, we generate a new Guid and set it to the current session object.

Now, let’s have a look at connection the webclient to the signalR server and getting ready to receive the image.

Warning: the next part contains javascript code…

In Default.aspx we add this script

Code Snippet
  1. <scriptsrc="Scripts/jquery-1.7.1.min.js"></script>
  2. <scriptsrc="Scripts/jquery.signalR-1.0.0-rc2.min.js"></script>
  3. <scriptsrc="http://pbclone.azurewebsites.net/signalr/hubs/"type="text/javascript"></script>
  4. <scripttype="text/javascript">
  5.     $(function () {
  6.         $.connection.hub.url = 'http://pbclone.azurewebsites.net/signalr';
  7.         //$.connection.hub.url = 'http://localhost:4341/signalr';
  8.         // Proxy created on the fly
  9.         var mainHub = $.connection.imgHub;
  10.         var guid = '<%=HttpContext.Current.Session["InstanceGuid"] %>';
  11.  
  12.         // Declare a function on the hub so the server can invoke it
  13.         mainHub.client.receiveImage = function (imageArray) {
  14.             //window.location = "/ImagePage.aspx?arr=" + imageArray;
  15.             $('#hiddenByteArray').val(imageArray);
  16.             $('#form1').submit();
  17.         };
  18.        
  19.         // Start the connection
  20.         $.connection.hub.start().done(function () {
  21.             mainHub.server.create(guid);
  22.         });
  23.     });
  24. </script>

First, we need to add jquery and the SignalR javascript library to our page. The third included script comes from wherever you host your SignalR service. The /signalr/hubs/ will be a proxy in javascript that contains the methods in the hub, allowing us to use them from our clients (try browsing to that url and have a look inside the javascript). $.connection comes from the SignalR javascript library, we set the correct url and get the correct hub. We’ll also use a bit of inline asp.net to get the guid from the session. Remember in the SignalR part that we called ReceiveImage on the dynamic object? Line 13 is where we declare a callback handler on that method call. We set the received value, which will be a byte array, to a hidden field and POST the form. Those handlers need to be set before we call the start() method on the hub. <yourhub>.client is where all your client side callbacks are registered. <yourhub>.server is where all server side methods can be called, those methods are loaded from the /signalr/hubs/ proxy. On line 20 we start the connection to the hub, once we’re connected we’ll call the create method and pass the guid in to create and join the group.

We’ll need a second page in this webclient to actually show the image. Only one element on the page, an img element.

Code Snippet
  1. <body>
  2.     <formid="form1"runat="server">
  3.     <div>
  4.         <imgsrc="/ByteArrayHandler.ashx"style="text-align: center"/>
  5.     </div>
  6.     </form>
  7. </body>

The img element uses a second generic handler that will take care of deserializing the byte array back into an image.

Code Snippet
  1. publicclassByteArrayHandler : IHttpHandler, IRequiresSessionState
  2. {
  3.  
  4.     publicvoid ProcessRequest(HttpContext context)
  5.     {
  6.         string base64String = HttpContext.Current.Session["ByteArray"].ToString();
  7.         byte[] convertedFromBase64 = Convert.FromBase64String(base64String);
  8.  
  9.         context.Response.OutputStream.Write(convertedFromBase64, 0, convertedFromBase64.Length);
  10.         context.Response.ContentType = "image/JPEG";
  11.     }
  12.  
  13.     publicbool IsReusable
  14.     {
  15.         get
  16.         {
  17.             returnfalse;
  18.         }
  19.     }
  20. }

We’ll get the byte array from the session object. SignalR encodes arrays with Base64 encoding so we need to decode that first, once that’s done we can just write the byte array into the outputstream as a JPEG, just like we did with the QR code. Onto the ImagePage.aspx.cs to see how the byte array goes into the session object

Code Snippet
  1. protectedvoid Page_Load(object sender, EventArgs e)
  2. {
  3.     NameValueCollection postedValues = Request.Form;
  4.  
  5.     var base64String = postedValues["hiddenByteArray"];
  6.     HttpContext.Current.Session["ByteArray"] = base64String;
  7. }

We get our POST values from Request.Form, look for the hidden field called hiddenByteArray and place its value in the session.

We now have our service and one client complete, all that’s left is building a Windows Phone application that connects to that same group on that same service and send the picture over.

Windows Phone client

For this we’ll need a Windows Phone 8 project as SignalR has no official support for Windows Phone 7. Make sure that you have the latest version of Nuget installed or it won’t find the correct SignalR assembly for Windows Phone 8 (thanks David Fowler for pointing this out).

Add the SignalR.Client assembly to the project. Here’s the XAML for the MainPage.

Code Snippet
  1. <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
  2.     <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
  3.     <TextBlock x:Name="StatusText" Text="Not connected" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
  4. </StackPanel>
  5.  
  6. <!--ContentPanel - place additional content here-->
  7. <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
  8.     <Rectangle x:Name="_previewRect"
  9.        Margin="0"
  10.        Height="800"
  11.        Width="600"
  12.        HorizontalAlignment="Center"
  13.        VerticalAlignment="Center">
  14.         <Rectangle.Fill>
  15.             <VideoBrush x:Name="_previewVideo">
  16.                 <VideoBrush.RelativeTransform>
  17.                       <CompositeTransform
  18.                 x:Name="_previewTransform" CenterX=".5" CenterY=".5" />
  19.                 </VideoBrush.RelativeTransform>
  20.             </VideoBrush>
  21.         </Rectangle.Fill>
  22.     </Rectangle>
  23.     <ListBox Margin="10" x:Name="_matchesList" FontSize="30" FontWeight="ExtraBold" />
  24. </Grid>

I use one of the default textboxes in the page’s header for a connection status. In the content grid we place a rectangle filled with a VideoBrush, this will be used to scan the QR code, Let’s have a look at the code for the WP app.

First we declare some fields

Code Snippet
  1. privatestring _guid;
  2. privatePhotoChooserTask _photoChooserTask;
  3. privateIHubProxy _mainHub;
  4. privateHubConnection _connection;
  5. privatereadonlyDispatcherTimer _timer;
  6. privatePhotoCameraLuminanceSource _luminance;
  7. privateQRCodeReader _reader;
  8. privatePhotoCamera _photoCamera;
  9. privateStream _imgStream;

I’ll explain these when we encounter them. Now for the page’s constructor

 

Code Snippet
  1. public MainPage()
  2. {
  3.     InitializeComponent();
  4.  
  5.     _photoCamera = newPhotoCamera();
  6.     _photoCamera.Initialized += OnPhotoCameraInitialized;
  7.     _previewVideo.SetSource(_photoCamera);
  8.     CameraButtons.ShutterKeyHalfPressed += (sender, args) => _photoCamera.Focus();
  9.  
  10.     _photoChooserTask = newPhotoChooserTask();
  11.     _photoChooserTask.Completed += photoChooserTask_Completed;
  12.     _photoChooserTask.Show();
  13.  
  14.     _timer = newDispatcherTimer
  15.                  {
  16.                      Interval = TimeSpan.FromMilliseconds(250)
  17.                  };
  18.  
  19.     _timer.Tick += (o, arg) => ScanPreviewBuffer();
  20. }

First we initialize a PhotoCamera instance. _previewVideo is the VideoBrush set in the rectangle, we set its source to the PhotoCamera instance. On line 8 we state that when the hardware camera button is half pressed we focus the camera, just a small helper for when the app has troubles reading the QR code. The next part is calling the PhotoChooserTask, this task gives us access to the albums and pictures on the device. We’ll need a timer as well, every timer tick we’ll check if the camera preview window contains a QR code. We’ve declared some event handlers in this constructor, let’s go over them one by one. We’ll start with the OnPhotoCameraInitialized.

Code Snippet
  1. privatevoid OnPhotoCameraInitialized(object sender, CameraOperationCompletedEventArgs e)
  2. {
  3.     int width = Convert.ToInt32(_photoCamera.PreviewResolution.Width);
  4.     int height = Convert.ToInt32(_photoCamera.PreviewResolution.Height);
  5.     _photoCamera.FlashMode = FlashMode.Off;
  6.  
  7.     _luminance = newPhotoCameraLuminanceSource(width, height);
  8.     _reader = newQRCodeReader();
  9.  
  10.     Dispatcher.BeginInvoke(() =>
  11.     {
  12.         _previewTransform.Rotation = _photoCamera.Orientation;
  13.     });
  14. }

We get the resolution’s width and height and turn the flash off. The PhotoCameraLuminanceSource on line 7 is a custom class that will provide us with a previewbuffer that we can fill. Here’s the class

Code Snippet
  1. publicclassPhotoCameraLuminanceSource : LuminanceSource
  2. {
  3.     publicbyte[] PreviewBufferY { get; privateset; }
  4.  
  5.  
  6.     public PhotoCameraLuminanceSource(int width, int height)
  7.         : base(width, height)
  8.     {
  9.         PreviewBufferY = newbyte[width * height];
  10.     }
  11.  
  12.  
  13.     publicoverridesbyte[] Matrix
  14.     {
  15.         get { return (sbyte[])(Array)PreviewBufferY; }
  16.     }
  17.  
  18.  
  19.     publicoverridesbyte[] getRow(int y, sbyte[] row)
  20.     {
  21.         if (row == null || row.Length < Width)
  22.         {
  23.             row = newsbyte[Width];
  24.         }
  25.  
  26.  
  27.         for (int i = 0; i < Height; i++)
  28.             row[i] = (sbyte)PreviewBufferY[i * Width + y];
  29.  
  30.  
  31.         return row;
  32.     }
  33. }

The class inherits from LuminanceSource which comes from the Google zxing project. Zxing is a library to decode QR and barcode images, it has a .NET port on codeplex (http://zxingnet.codeplex.com/) that port is what I use in this project and that’s where the LuminanceSource comes from. That’s also where the QRCodeReader class lives.

Next event handler that we attached in the constructor is the photoChooserTask_Completed

Code Snippet
  1. void photoChooserTask_Completed(object sender, PhotoResult e)
  2. {
  3.     if (e.TaskResult == TaskResult.OK)
  4.     {
  5.         _imgStream = e.ChosenPhoto;
  6.  
  7.         _timer.Start();
  8.     }
  9. }

If the task returns succesfully we’ll set the chosen photo, which arrives here as a stream, to the _imgStream field and we start the timer. Now on every timer tick (every 250 milliseconds in this example) we will scan the previewbuffer for QR codes.

Code Snippet
  1. privatevoid ScanPreviewBuffer()
  2. {
  3.     if (_guid != null)
  4.     {
  5.         _timer.Stop();
  6.  
  7.         SendImage();
  8.     }
  9.  
  10.     try
  11.     {
  12.         _photoCamera.GetPreviewBufferY(_luminance.PreviewBufferY);
  13.         var binarizer = newHybridBinarizer(_luminance);
  14.         var binBitmap = newBinaryBitmap(binarizer);
  15.         var result = _reader.decode(binBitmap);
  16.  
  17.         Dispatcher.BeginInvoke(() =>
  18.                                    {
  19.                                        _guid = result.Text;
  20.                                    });
  21.     }
  22.     catch
  23.     {
  24.  
  25.     }
  26. }

First thing we do here is checking if we already have a guid, if we do we stop the timer and send the image to the SignalR service. If _guid is still null we’ll get the previewbuffer and try to decode it, if there’s no QR code in the previewbuffer it will throw an exception, hence the empty catch block. When we can decode  we’ll go to the SendImage() method.

Code Snippet
  1. privateasyncvoid SendImage()
  2. {
  3.     if (_connection == null || _connection.State != ConnectionState.Connected)
  4.     {
  5.         await SetupSignalRConnection();
  6.     }
  7.  
  8.     if (_connection.State == ConnectionState.Connected || _connection.State == ConnectionState.Reconnecting)
  9.     {
  10.         MemoryStream s = newMemoryStream();
  11.         _imgStream.CopyTo(s);
  12.         _mainHub.Invoke("ShareImage", newobject[]{s.ToArray(), _guid});
  13.     }
  14.     else
  15.     {
  16.         MessageBox.Show("not connected");
  17.     }
  18. }

If there’s no active connection, we’ll call the SetupSignalRConnection() method. if there is and we are connected we copy the imagestream into a MemoryStream and we invoke the ShareImage() method on the SignalR server, passing in the memorystream, converted into a byte array, and the guid we got from the qr code.

Now for the connection to the server.

Code Snippet
  1. privateasyncTask SetupSignalRConnection()
  2. {
  3.     _connection = newHubConnection("http://pbclone.azurewebsites.net/");
  4.     _connection.StateChanged += ConnectionOnStateChanged;
  5.     _mainHub = _connection.CreateHubProxy("imghub");
  6.  
  7.     await _connection.Start();
  8.  
  9.     _mainHub.Invoke("Create", _guid);
  10. }

We instantiate a new HubConnection with the url to the service as parameter. We generate a proxy for the hub we want to use and we call the start() method on the connection. It will connect to the hub, get the javascript proxy and translate it into a .net proxy. We then invoke the Create() method and pass in the guid so that our Windows Phone client joins the same group as the web client. The ConnectionOnStateChanged event handler is only used to update the textblock on the page to show whether or not we’re connected.

Code Snippet
  1. privatevoid ConnectionOnStateChanged(StateChange stateChange)
  2. {
  3.     switch (stateChange.NewState)
  4.     {
  5.         caseConnectionState.Connecting:
  6.             StatusText.Text = "Connecting...";
  7.             break;
  8.         caseConnectionState.Connected:
  9.             Dispatcher.BeginInvoke(() => StatusText.Text = "Connected");
  10.             break;
  11.         caseConnectionState.Reconnecting:
  12.             Dispatcher.BeginInvoke(() => StatusText.Text = "Reconnecting...");
  13.             break;
  14.         caseConnectionState.Disconnected:
  15.             Dispatcher.BeginInvoke(() => StatusText.Text = "Disconnected");
  16.             break;
  17.     }
  18. }

And that’s it, we can now start sending images to any device with a browser and an internet connection.

Conclusion

In this post I’ve tried to demystify the magic from Nokia’s Photobeamer app. It is a really cool app but when you take it apart, it’s not that magical. Like a lot of impressive looking tech it just combines a bunch of existing techs into something no one else thought of.

The code in this article is all my own, I have no clue how the Nokia app actually works and what technology they are using, I’m only mimicking their behavior.

Update: I've uploaded the project to Github https://github.com/NicoVermeir/photobeamerclone


Tags:

.Net | Metro | signalr | Web development | WP8 | XAML

Discovering the Windows Phone 8 SDK MSDN webcast slides and demos

by Nico

Today I did my second MSDN webcast, this time about the brand new Windows Phone 8 SDK. I had great fun doing this, I knew what to expect so I went in relaxed and just enjoyed it. This time even the audio and recording went fine (had no sound for the first five minute last time). The recording is being edited the coming days and should be on Channel9 somewhere next week I think, I’ll update this post when it’s online.

Until then, my demos can be found on SkyDrive and my slides are on SlideShare.


Tags:

.Net | Community | Metro | WP8 | XAML | MSDN | Talk

Stream comics from Windows 8 to other devices using PlayTo

by Nico

There are plenty of blogposts, tutorials, videos, books and many more out there that talk about searching, sharing settings and if you’re lucky even printing. But the Devices charm can be used for something way cooler than printing some pages, it can trigger the Play To contract.

The Play To contract can share media like music, video and pictures to other devices on your network, be it other Windows 8 devices or even Xbox 360 consoles. Being a comic geek I the first thing on my mind when reading about the Play To contract was “this would be awesome to stream comics from my pc to my Xbox” and so a challenge was born and accepted on the same day. An evening or two of hacking later I’m proud to say that I did it and it’s really easy, just like everything that involves charms (Microsoft really did a good job on allowing us to integrate our apps with the OS here). Most of the time putting this thing together went to building the actual comic viewer, but enough talk, let’s take a look at how it’s done. First let me show you how it looks like, we’ll start with the app itself.

Pretty empty so far, if we load a digital comic (only .cbz format supported in this demo) and select the Devices charm we get this.

That’s right! that’s Captain America himself, including Bucky. And oh yeah, the xbox shows up in the Devices charm as well. After selecting the xbox from the list of devices we get this.

And here it is playing on my TV (yes that’s a Sony, because Microsoft doesn’t build televisions yet Winking smile)

Pretty cool eh? Let’s check under the hood.

First, a digital comic mostly exists in either .cbz or .cbr format. They’re actually nothing more then a zip or a rar file (Comic Book Zip and Comic Book Rar). Since WinRT has the ZipArchive class we can support .cbz out of the box, for cbr format we would need to find a library that supports rar files but that’s outside the scope of this post.

First the XAML, the main control here is a FlipView, that allows for touch and mouse support out of the box. The FlipView is bound to a collection of bitmap images that get loaded from the digital comic. Next to the FlipView there’s also an appbar containing the load file button and a textblock that shows the connection to other devices.

   1: <common:LayoutAwarePage.BottomAppBar>
   2:     <AppBar IsOpen="True" Background="#FF1A76B6">
   3:         <StackPanel Orientation="Horizontal">
   4:             <Button Click="OpenButton_Click" Style="{StaticResource OpenFileAppBarButtonStyle}" />
   5:         </StackPanel>
   6:     </AppBar>
   7: </common:LayoutAwarePage.BottomAppBar>
   8:  
   9: <Grid Style="{StaticResource LayoutRootStyle}">
  10:     <Grid.RowDefinitions>
  11:         <RowDefinition Height="140"/>
  12:         <RowDefinition Height="*"/>
  13:     </Grid.RowDefinitions>
  14:  
  15:     <TextBlock x:Name="ConnectionText" TextWrapping="Wrap" Text="Not connected" Margin="38,18,766,571" 
  16:                Grid.Row="1" Style="{StaticResource SubheaderTextStyle}"/>
  17:  
  18:     <FlipView x:Name="FlipImage" Margin="0,3,0,0" Grid.RowSpan="2" SelectionChanged="FlipImage_NextImage">
  19:         <FlipView.ItemTemplate>
  20:             <DataTemplate>
  21:                 <Image Source="{Binding}" />
  22:             </DataTemplate>
  23:         </FlipView.ItemTemplate>
  24:     </FlipView>
  25:  
  26:     <Grid>
  27:         <Grid.ColumnDefinitions>
  28:             <ColumnDefinition Width="Auto"/>
  29:             <ColumnDefinition Width="*"/>
  30:         </Grid.ColumnDefinitions>
  31:         <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" 
  32:                 Style="{StaticResource BackButtonStyle}"/>
  33:         <TextBlock x:Name="pageTitle" Grid.Column="1" Text="{StaticResource AppName}" 
  34:                    Style="{StaticResource PageHeaderTextStyle}"/>
  35:     </Grid>
  36: </Grid>

The FlipView template is just a simple Image control, nothing special in the XAML, the magic is in the code behind.

First some fields that we’ll need later on

   1: private List<BitmapImage> _pages;
   2: private bool _isConnected;
   3: private Image _current;

We’re going to take a look at how to load the cbz file first, I’ll go over this quickly as the main focus of this post is the PlayTo contract.

   1: private async void OpenButton_Click(object sender, RoutedEventArgs e)
   2: {
   3:     _pages = new List<BitmapImage>();
   4:  
   5:     _pages = await OpenZip();
   6:  
   7:     if (_pages.Count > 0)
   8:         FlipImage.ItemsSource = _pages;
   9: }

All we do in the button’s eventhandler is initializing the field that will hold all the pages, call the function that will load the file and if it contains any items it will set the FlipView’s itemssource to that list. Next up: the function to load the comic.

   1: async Task<List<BitmapImage>> OpenZip()
   2: {
   3:     FileOpenPicker openPicker = new FileOpenPicker();
   4:     List<BitmapImage> comic = new List<BitmapImage>();
   5:  
   6:     openPicker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
   7:     openPicker.FileTypeFilter.Add(".cbz");
   8:  
   9:     var storageFile = await openPicker.PickSingleFileAsync();
  10:     // Create stream for compressed files in memory
  11:     using (MemoryStream zipMemoryStream = new MemoryStream())
  12:     {
  13:         using (IRandomAccessStream zipStream = await storageFile.OpenAsync(FileAccessMode.Read))
  14:         {
  15:             // Read compressed data from file to memory stream
  16:             using (Stream instream = zipStream.AsStreamForRead())
  17:             {
  18:                 byte[] buffer = new byte[1024];
  19:                 while (instream.Read(buffer, 0, buffer.Length) > 0)
  20:                 {
  21:                     zipMemoryStream.Write(buffer, 0, buffer.Length);
  22:                 }
  23:             }
  24:         }
  25:  
  26:  
  27:         // Create zip archive to access compressed files in memory stream
  28:         using (ZipArchive zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read))
  29:         {
  30:             // For each compressed file...
  31:             foreach (ZipArchiveEntry item in zipArchive.Entries)
  32:             {
  33:                 if (item.Name.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase))
  34:                 {
  35:                     byte[] imageInBytes;
  36:  
  37:                     using (MemoryStream ms = new MemoryStream())
  38:                     {
  39:                         var stream = item.Open();
  40:                         stream.CopyTo(ms);
  41:                         imageInBytes = ms.ToArray();
  42:                     }
  43:  
  44:                     BitmapImage bImg = new BitmapImage();
  45:                     await bImg.SetSourceAsync(new RandomStream(imageInBytes));
  46:  
  47:                     comic.Add(bImg);
  48:                 }
  49:             }
  50:         }
  51:     }
  52:  
  53:     return comic;
  54: }

We start by initializing the FileOpenPicker, allowing our user to select the comic he/she wants to read. We add a suggested location where the FileOpenPicker should start and add the filetypes it should look for. The PickFileAsync method shows the actual filepicker to the user, the user selects the cbz file he wants and it gets loaded into the storageFile variable. The file gets read in as an IRandomAccessStream. We need that stream to create a ZipArchive instance. Once we have that we can loop through all files in that zip archive. Each .jpg file in that zip archive gets read into a byte array that we then convert into a bitmap by using RandomStream, an implementation of IRandomAccessStream (if you want to see the implementation, the project is attached to this post at the bottom). The bitmap image then gets added to the list. When they’re all done the list gets returned to the caller.

That’s it for loading the comic, let’s take a look at the sharing to other devices in your network.

We need to initialize the PlayTo contract, I’ll be doing this from the constructor

   1: public MainPage()
   2: {
   3:     InitializeComponent();
   4:  
   5:     var playToManager = PlayToManager.GetForCurrentView();
   6:     playToManager.SourceRequested += PlayToManagerOnSourceRequested;
   7:     playToManager.SourceSelected += PlayToManagerOnSourceSelected;
   8: }

PlayToManager is the class that we need, we get this for free from the WinRT framework. The GetForCurrentView() method returns an instance of the PlayToManager class bound to this page. Once we have the instance we attach an eventhandler to the SourceRequested and the SourceSelected events. The SourceRequested event will fire as soon as the user hits the Devices charm, this is where we’ll prepare the first media element for streaming. The SourceSelected event fires when the user selects a source, obviously.

   1: private async void PlayToManagerOnSourceRequested(PlayToManager sender, PlayToSourceRequestedEventArgs args)
   2: {
   3:     var deferral = args.SourceRequest.GetDeferral();
   4:  
   5:     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
   6:         {
   7:             var firstImage = GetChildren(FlipImage).First();
   8:  
   9:             // Provide Play To with the first image to stream.
  10:             args.SourceRequest.SetSource(firstImage.PlayToSource);
  11:             _current = firstImage;
  12:             deferral.Complete();
  13:         });
  14:  
  15: }

The OnSourceRequested eventhandler needs to be marked as async. First we get the deferral, then we need to run some async code, Dispatcher.RunAsync is the same as calling an async method with await on this line. The PlayTo contract works with certain XAML controls. In our case we need the Image control, that’s why we’ve set the itemtemplate of the FlipView to be an Image. We’ll take a look at the GetChildren() method in a minute, for now just know that it returns a list of all Image controls inside the FlipView. We take the first element in the returned list and that’s the element that we’ll stream to the device. The arguments have a property of type PlayToSourceRequest, that one has a SetSource function that takes in a PlayToSource object and that’s a property of the Image control. We set the current image to the _current field and mark the deferral as complete.

Phew that was quite some work. Don’t worry, the hard part is over (yes this was really the hard part). Now a quick look at that GetChildren() function.

   1: private List<Image> GetChildren(DependencyObject parent)
   2: {
   3:     var list = new List<Image>();
   4:  
   5:     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
   6:     {
   7:         var child = VisualTreeHelper.GetChild(parent, i);
   8:         var item = child as Image;
   9:         if (item != null)
  10:             list.Add(item);
  11:  
  12:         list.AddRange(GetChildren(child));
  13:     }
  14:  
  15:     return list;
  16: }

The function takes in a DependencyObject and starts walking through its visual tree. We try to cast each item as an Image, if that cast fails the variable will contain null, a quick check there and if it isn’t null we add it to the list which we then return.

The OnSourceSelected is only used to set the name of the selected source to the textblock

   1: private async void PlayToManagerOnSourceSelected(PlayToManager sender, PlayToSourceSelectedEventArgs args)
   2: {
   3:     _isConnected = true;
   4:  
   5:     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
   6:         ConnectionText.Text = string.Format("Connected to {0}", args.FriendlyName));
   7: }

And that’s enough to stream the first image, when you run this code and select the Devices charm the first page of the comic should show up on your device. All there’s left now is to go back and forward in the comic. In the app itself this already works, the FlipView takes care of navigating between the pages. Before we start developing this we need to make a small halt and take a look at how the FlipView actually works. First thought in my head was “okay this is easy, I just get all the image controls in the FlipView and I’m golden”. That was a big nono. The itemspanel of a FlipView is actually a VirtualizingStackPanel, meaning that at any given time there are maximum three Image controls inside the FlipView, usually previous-current-next. As soon as we navigate to another page the FlipView automatically loads in the next item in line. This can easily be seen by using a handy tool called XamlSpy. XamlSpy allows us to view the entire visual tree of any XAML based application. When we view the default visual tree of a FlipView after loading a comic we get this.

As you can see, we only have three FlipViewItems here. When we change the FlipView’s paneltemplate to this

   1: <FlipView x:Name="FlipImage" Margin="0,3,0,0" Grid.RowSpan="2" SelectionChanged="FlipImage_NextImage">
   2:     <FlipView.ItemsPanel>
   3:         <ItemsPanelTemplate>
   4:             <StackPanel />
   5:         </ItemsPanelTemplate>
   6:     </FlipView.ItemsPanel>
   7:     <FlipView.ItemTemplate>
   8:         <DataTemplate>
   9:             <Image Source="{Binding}" />
  10:         </DataTemplate>
  11:     </FlipView.ItemTemplate>
  12: </FlipView>

and we load the same comic in XamlSpy we get this result

Quite the difference I would say. The VirtualizingStackPanel is lighter on memory usage, since some comics can be quite large we’ll stick to the default template.

Now that we have that cleared out, let’s take a look at what happens when we browse to the next page of the comic.

   1: private async void FlipImage_NextImage(object sender, SelectionChangedEventArgs e)
   2: {
   3:     if (!_isConnected) return;
   4:  
   5:     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
   6:         {
   7:             var current = GetChildren(FlipImage)[1];
   8:  
   9:             _current.PlayToSource.Next = current.PlayToSource;
  10:             _current.PlayToSource.PlayNext();
  11:             _current = current;
  12:         });
  13: }

First, this code does not need to be executed when we’re not connected to any device, if we are we need to run the next block of code asynchronously. First the code fetches all the available Image controls inside the FlipView, we save a reference to the middle one because that one is the one currently shown in the FlipView. The field _current contains the image currently shown on the external device, we need to set that field’s PlayToSource.Next property. That property always needs to be set on the current image before the PlayNext() method is called. Once that’s set we call the aforementioned PlayNext() method. That method will sent the control that is set to the PlayToSource.Next property to the connected device. To end we set the image control that was just send to the device to the _current field so that it can be called upon on the next run.

In this post I have shown how you can share media content from your Windows Store application to an external device like the Xbox 360. The project used in this post can be downloaded from my SkyDrive


Tags:

.Net | Devices | Metro | WinRT | Windows 8 | XAML

  Log in

About the author

Hi,

My name is Nico, I’m an MVP Windows Platform Development living in Belgium.
I’m currently employed as a .NET consultant at RealDolmen, one of Belgium’s leading IT single source providers.

I'm also founding member and board member of the Belgian Metro App Developer Network, a user group focussed on Windows 8 and Windows Phone development. If you're in Belgium feel free to drop by if we're doing an event. http://www.madn.be

Since June 2012 I'm a proud member of Microsoft's Extended Experts Team Belgium. And in February 2013 I became a member of DZone's Most Valuable Bloggers family.

In 2013 I became a book author and wrote "Windows 8 app projects, XAML & C# edition".

In 2014 I received the MVP award for the very first time.

I hope to get feedback from my readers either through comments, mail (nico_vermeir@hotmail.com), twitter, facebook, …

 

mvp

 

mvp

 

 

MeetLogo

 

MVBLogo

mybook

 

Month List