App Studio: let’s take a look at a generated project

In the previous post we’ve seen how App Studio, the new tool by Microsoft, is able to generate a full Windows Phone application without having to write a single line of code. Anyway, even if the tool is very powerful, it doesn’t support every possible Windows Phone feature or scenario: for this reason, other than just downloading the XAP, you can also download the full Visual Studio project, so that you can edit and customize it.

In this post we’ll see the structure of this project and how it works, so that you can understand how to add new views or new features. Let’s start to download the project from App Studio, using the link provided at the end of the creation process: for this post I’m going to use the Comics application I’ve created in the previous post.

The project

When you’ll extract the compressed file you’ve downloaded, you’ll find a folder called src, which contains the real Visual Studio project.

image

Open the solution using the file Solution.sln with Visual Studio 2012 or 2013 Preview (since it’s a Windows Phone 8 project, it’s supported by both versions): you’ll find that the application is made by 3 projects, splitted in various folders. It’s an application based on the Model-View-ViewModel pattern, which is the most famous development pattern in the XAML world.  I’ve deeply talked about it in my series of posts about Caliburn Micro, which is one of the most popular MVVM frameworks. In this project, MVVM isn’t implemented using a specific toolkit or framework, but with custom classes that are built in the project. We’ll see the details in the rest of the post. Another important thing to highlight is that the project uses NuGet: most of the third party libraries are installed using this tool, but to use it you have to make sure that, in the NuGet settings (right click on the project, choose Mange NuGet packages and then click on Settings) the option Allow NuGet to download missing packages during the build in the Package restore section is enabled. This step is required because the project is configured using the Package restore NuGet’s feature: basically, the project just contains a reference to the packages that have been installed, but the real packages’ files are not included in the solution. They will be downloaded the first time the solution is built: this way, the size of the zip file generated by App Studio is reduced.

Here is how the solution looks like in Solution Explorer:

image

The folders contains various projects and files: the UI folder contains the real Windows Phone application (the one you’ll need to launch on the emulator or on a device to test it), while the Data folder contains two other projects called Entities and Repositories, which take care of handling the application data. Let’s see them in details.

Entities

This project contains all the classes that define the entities that are used in the app. You’ll find some basic entities (for common scenarios, like RSS or Twitter feeds), plus an entity for every data source you’ve defined in the web tool. For example, in my application I have a created a ComicsCollection (if you remember, it’s a collection to store a list of comics): the project will contain a class called ComicsCollectionSchema, which is the base class that identifies a comic (and that exposes the properties we’ve defined when we’ve created the data source columns in the visual editor).

As I’ve already mentioned in the beginning of the post, the project generated by App Studio is built using the MVVM pattern: for this reason, every entity is defined to support this pattern, by implementing the BindableBase class. It’s a custom class built-in in the project, that offers an implementation of the INotifyPropertyChanged interface: it’s one the key concepts when you deal with binding, since it allows to propagate property changes to the user interface automatically. If you take a look at one of the entities’ definition, you’ll notice that the value of each property is set using a method called SetProperty : it takes care of storing the new value and to raise the NotifyPropertyChanged event, so that the control which is in binding is notified of the update. This way, you can simply connect a ComicsCollectionSchema object’s property defined in a ViewModel to a control in the View simply like this:

<TextBlock Text="{Binding Path=Title}" />

Except for this, it’s a standard class that defines an entity: I have a property for every field, like Title, Author and Description.

Here is the code:

public class ComicsCollectionSchema : BindableBase
{
    /// <summary>
    /// Identifier for instances created according ComicsCollectionSchema Data Schema.
    /// </summary>
    public Guid Id { get; set; }

    private string _author;

    /// <summary>
    /// Gets/Sets value of Author column.
    /// </summary>
    public string Author
    {
        get { return _author; }
        set
        {
            SetProperty(ref _author, value);
        }
    }

    private string _title;

    /// <summary>
    /// Gets/Sets value of Title column.
    /// </summary>
    public string Title
    {
        get { return _title; }
        set
        {
            SetProperty(ref _title, value);
        }
    }

    private string _image;

    /// <summary>
    /// Gets/Sets value of Image column.
    /// </summary>
    public string Image
    {
        get { return _image; }
        set
        {
            SetProperty(ref _image, value);
        }
    }

    private string _description;

    /// <summary>
    /// Gets/Sets value of Description column.
    /// </summary>
    public string Description
    {
        get { return _description; }
        set
        {
            SetProperty(ref _description, value);
        }
    }
}

Repositories

The project uses an approach based on repositories to make data available in the application. Like for entities, the project contains a repository for each data source we’ve defined in the application: in this case, we’ll find a class called ComicsCollection. This class acts as a middle man between the application and the data: the queries on data (in this case, to retrieve the comics list) aren’t performed directly by the ViewModel, but by the repository class, which exposes the basic methods to load and filter the available data set. The generated class will be different according if you’re using a static or dynamic collection: in the first case, you’ll find a method called GetData() which takes care of initializing the data that has been defined in the web tool; in the second case, instead, it will provide the basic operations to query the dynamic service that has been generated with the application. Here is a sample of the second scenario:

public class ComicsCollection : IComicsCollection 
{
    private readonly IJsonDataSource _jsonDataSource; 

    private const string DataServiceUrl = "http://dowapp.cloudapp.net/api/data?clientId={0}&appId={1}&datasourceName={2}";

    /// <summary>
    /// Initializes a new instance of the <see cref="ComicsCollection" /> class.
    /// </summary>
    /// <param name="jsonDataSource">A JSON based data source.</param>
    public ComicsCollection(IJsonDataSource jsonDataSource)
    {
        _jsonDataSource = jsonDataSource;
    }

    /// <summary>
    /// Retrieves the data from a dynamic data service (URL specified in DataServiceUrl) , in an observable collection of ComicsCollectionSchema items.
    /// </summary>
    /// <returns>An observable collection of ComicsCollectionSchema items.</returns>
    public async Task<ObservableCollection<ComicsCollectionSchema>> GetData()
    {            
        return await LoadData();
    } 

    private async Task<ObservableCollection<ComicsCollectionSchema>> LoadData()
    {
        var items = await _jsonDataSource.LoadRemote<ComicsCollectionSchema[]>(string.Format(DataServiceUrl, "1426","5b07b520-7b22-4756-97ae-4d92660afa17", "ComicsCollection"));
        return items != null ? new ObservableCollection<ComicsCollectionSchema>(items.OrderBy(i=>i.Author)) : new ObservableCollection<ComicsCollectionSchema>();
    }
}

How does it work a dynamic data source, under the hood? It’s a REST service (which URL is set in the DataServiceUrl constant), which returns data using the JSON format.

The repository class uses a JsonDataSource class, which identifies a REST service that exchange data with the JSON format: the LoadRemote<T>() method (that is used in the LoadData() method) takes care of performing a network request and getting the data in JSON format from the service. Then, it’s able to automatically deserialize and convert it into a specific type, which is passed as T parameter: in this sample, the JSON data is converted into an array of ComicsCollectionSchema objects (which, if you remember, is the basic entity that defines a single comic). The method simply requires as parameter the URL of the service (that is combined with some fixed identifiers that are used to generate the unique URL) and return a collection of items, which is converted into an ObservableCollection<T>() to have built-in support to binding.

As you can see, every reporitory class implements an interface, which simply described the available methods. For example, the ComicsCollection class implements the following IComicsCollection interface:

public interface IComicsCollection
{
    Task<ObservableCollection<ComicsCollectionSchema>> GetData();
}

We’ll see later why this class is useful in the project’s ecosystem.

The Windows Phone application

The biggest and most important project is the Windows Phone application, which contains many folders to organize the application structure. Since the application is built with the MVVM pattern, the two most important folders are View and ViewModel: the first one contains the application pages, which are the XAML files; the second one, instead, contains the ViewModels, which are the classes that define the interaction logic behind the view. In the View folder you’ll find a view for every page defined in the web tool: in the comics application, there will be a page called Comics_List.xaml (which is the main page that contains a panorama control with the comics list) and one called Comics_Detail.xaml (which, instead, is the page that display the details about the selected comic). In the same way, in the ViewModel folder you’ll find the two view models that are connected to the views: Comics_ListViewModel e Comics_DetailViewModel.

How Views and ViewModels are connected together? First we need to do a step back and to highlight that the whole project is based on the dependency injection approach: it means that basically every class of the project (including ViewModels) isn’t manually created, but it’s automatically resolved at runtime by a class called dependency container. What does it mean? Let’s explain it with a concrete example: we’ve already seen that, to interact with the data, the project uses the repository approach, by offering a class called ComicsCollection that retrieves the data from the cloud service generated by the tool. This means that we can expect that, somewhere in the ViewModel of the main application page, the class creates a new ComicsCollection object and calls the GetData() method to populate the list:

public async void RefreshComics()
{
   ComicsCollection collection = new ComicsCollection();
   await collection.GetData();
}

Which is the problem of this approach in a complex application? That if we need to swap the data source (for example, because we’re in testing stage and, instead of using real data from the service, we want to use fake data), we need to change every point in the application in which we’ve created a new instance of the ComicsCollection class. Dependancy injection, instead, allows to specify in one single point (tipically, when the application starts) which concrete implementation we want to use when we require to work with a class. This is why the ComicsCollection class implements an IComicsCollection interface: we can register, in the dependency container, which implementation we want to use for that interface. The App Studio projects uses Unity (which is an open source project by Microsoft) to support dependency injection: you can see its implementation in the Ioc folder, which contains a class called Container: its purpose is to register all the application classes. As you can see in the class constructor, by using the RegisterType<T, Y>() method of the UnityContainer class, the application specifies, for every interface, which is the concrete implementation to use (the T parameter is the interface, the Y one is the implementation). Here is a sample implementation:

public Container()
{
    _currentContainer = new UnityContainer();

    _currentContainer.RegisterType<ILiveTileService, LiveTileService>();
    _currentContainer.RegisterType<ILockScreenService, LockScreenService>();
    _currentContainer.RegisterType<IDialogService, DialogService>();
    _currentContainer.RegisterType<IReminderService, ReminderService>();
    _currentContainer.RegisterType<IShareService, ShareService>();
    _currentContainer.RegisterType<ISpeechService, SpeechService>();
    _currentContainer.RegisterType<INavigationService, NavigationService>();
    _currentContainer.RegisterType<IJsonDataSource, JsonDataSource>();
    _currentContainer.RegisterType<IXmlDataSource, XmlDataSource>();
    _currentContainer.RegisterType<IYoutubeDataSource, YoutubeDataSource>();

    _currentContainer.RegisterType<IComics_ListViewModel, Comics_ListViewModel>();
    _currentContainer.RegisterType<IComics_DetailViewModel, Comics_DetailViewModel>();

    if (!System.ComponentModel.DesignerProperties.IsInDesignTool)
    {
        _currentContainer.RegisterType<IComicsCollection, ComicsCollection>(new ContainerControlledLifetimeManager());
    }
    else
    {
        _currentContainer.RegisterType<IComicsCollection, FakeComicsCollection>(new ContainerControlledLifetimeManager());
    }    
}

The application simply registers in the bootstrapper every available service and view model: it’s important to keep an eye on this class; if we want to add new pages or new services to the application, we’ll have to register them in this place. We can see also a sample of the scenario I’ve previously described: if the user is working with a page that uses the ComicsCollection class in the Visual Studio or Blend designer, it uses an implementation with fake data called FakeComicsCollection; otherwise, it uses the real one that gets data from the cloud service.

You can also see, that others than View and ViewModels, the application uses the concepts of services: basically, they are classes which takes care of satisfying a specific scenario and that are stored inside the Services folder. Instead of writing the code to perform a task directly in the ViewModel, it’s defined in a separate class, which is a service: then, in the ViewModel, we interact with this class to perform our operation. You can see, for example, that we have a LiveTileService, which exposes methods to create secondary tiles or to update them; a LockScreenService, to set an image as lock screen background; a ShareService, to support sharing on social network. One of the most important (that we’ll cover in the next post) is NavigationService, which can be used to manage navigation between different pages directly in the ViewModel.

Now that we’ve seen how classes are registered,  a question may arise: how are they resolved and used in a ViewModel? The most common way is completely automatic: it’s enough to declare the interface of the class we want to use as parameter of the public constructor. Since both the interface and the ViewModel are registered in the container, Unity will automatically resolve them. To see an example, open any ViewModel of the application: here is a sample of the first lines of code.

public partial class Comics_ListViewModel : BindableBase, IComics_ListViewModel
{       
     private readonly IDialogService _dialogService;
     private readonly INavigationService _navigationService;
     private readonly ILockScreenService _lockScreenService;
     private readonly IComicsCollection _comicsCollection;

     public Comics_ListViewModel(IDialogService dialogService, INavigationService navigationService, ILockScreenService lockScreenService, IComicsCollection comicsCollection)
     {
         _dialogService = dialogService;
         _navigationService = navigationService;
         _lockScreenService = lockScreenService;
         _comicsCollection = comicsCollection;
     }
}

As you can see, the public constructor of the ViewModel includes a parameter for every service and class that it needs to use: automagically, every interface will be “injected” (thus, the dependency injection name) with the concrete implementation declared in the container. This way, we’ll be able to use our services and classes without having to create a new instance each time. For example, the sample usage of the ComicsCollection class we’ve previously seen can be converted simply in:

public async void RefreshComics() 
{
    await _comicsCollection.GetData();
}

Is there another way to resolve a class using dependency injection? Yes, and we can introduce it by speaking about how Views and ViewModels are connected together in the Windows Phone project. The used approach is called ViewModelLocator, which is a class that acts as a middle man between the Views and the ViewModels: it simply exposes every ViewModel as a property, which is, in the end, defined as DataContext of every view. You can find the ViewModelLocator implementation in the Services folder and it’s called ViewModelLocatorService. This service offers a sample of another way to get a reference to a class using dependency injection:

public class ViewModelLocatorService
{
    // IoC container
    private readonly IContainer _container;

    /// <summary>
    /// Initializes a new instance of the <see cref="ViewModelLocatorService" /> class.
    /// </summary>
    public ViewModelLocatorService()
    {
        _container = new Container();
    }

    /// <summary>
    /// Gets the reference to a Comics_ListViewModel.
    /// </summary>
    public IComics_ListViewModel Comics_ListViewModel
    {
        get { return _container.Resolve<Comics_ListViewModel>(); }
    }

    /// <summary>
    /// Gets the reference to a Comics_DetailViewModel.
    /// </summary>
    public IComics_DetailViewModel Comics_DetailViewModel
    {
        get { return _container.Resolve<Comics_DetailViewModel>(); }
    }
}

As you can see, we have a public property for each ViewModel: if we want to add new pages to our application, we should keep an eye also on this class, since we’ll have to add a new property for every view. And here comes the manual usage of the dependency injection’s container: since, in this case, we can’t resolve the class automatically (we explicity need to create a new instance of the ViewModel) we ask to the container for the instance that has been registed at startup using the Resolve<T> method, where T is the ViewModel’s type we want to require. This way, since we’re not manually creating a new instance but we’re asking to the container to get the registered one, all the ViewModel’s dependencies (remember all the services and classes that we’ve added as parameters of the ViewModel’s public constructor?) will be automatically satisfied.

In the end, the ViewModelLocatorService class is exposed by the application as global resource, so we can interact with it directly from XAML and assign every ViewModel to every View. If you open the App.xaml file you’ll see that the class is registered in the resources section:

<Application.Resources>
    <sys:String x:Key="AppName">Comics Tracker beta</sys:String>

    <!-- ViewModel locator -->
    <services:ViewModelLocatorService x:Key="ViewModelLocator"/>       
</Application.Resources>

If you open any View of the application, you’ll see that the DataContext property of the page is assigned to its specific ViewModel thanks to the ViewModelLocator resource we’ve previously defined:

<phone:PhoneApplicationPage 
x:Class="WPAppStudio.View.Comics_List"
DataContext="{Binding Path=Comics_ListViewModel, Source={StaticResource ViewModelLocator}}">

<!-- content of the page -->

</phone:PhoneApplicationPage>

It was a long ride

Yeah, it’s been a long ride: the project generated by Visual Studio can be complex and scary, especially if you aren’t an experienced Windows Phone developer, so it took a while to explain how things are working. In the next post, we’ll see how to start customizing our poject to add new pages and new data source. Stay tuned!

This entry was posted in Windows Phone and tagged , . Bookmark the permalink.

2 Responses to App Studio: let’s take a look at a generated project

  1. Shortiiik says:

    Hi,

    thanks for your post. I have also downloaded the source and peeked around a bit, because the application did not work OK (the App Studio Data Services). Its because the app dowapp.cloudapp.net is down. Can you please confirm that ATM App Studio Data Services is not working?
    Regards
    Jan

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.