
Shel 2013 year. For a dollar, they gave 30 rubles, and I got a job at 2GIS to develop for Windows Phone. I managed to participate in the launch of the almost ready for that time application 2GIS, which soon became available to our users in the Marketplace.
This application had one annoying feature: it worked on our WebAPI, and, accordingly, required an Internet connection. Therefore, almost immediately it became necessary to teach 2GIS under WP to work offline. But at the same time to solve other pressing problems.
Reasons to rewrite everything
The old application, despite the fact that it was published quite recently, did not cope well with the requirements of users and businesses. Requirements looked like this.
')
Fast data delivery
Suppose 2GIS learned some new information about your city. In order to share this information with users, we performed such actions here.
- They taught the application to display new data.
- All tested.
- Published a new version of the application in the store.
- We released data updates for the city.
Only after that you downloaded the new version of the application, and found out, finally, how much does it cost to comb a beard in the nearest barbershop. I am not talking about the problems of versioning data and applications, compatibility and all that. Fast data delivery means that we would like to exclude items 1-3 from this process altogether, and thus make the beard owners a little happier.
The rapid emergence of new features
Suppose we come up with a new search algorithm that searches better and faster. I wanted this algorithm to appear in the product without significant effort on the part of the Windows Phone team.
Offline
As I said, for the previous version of the application needed the Internet.

For some of our users, this was slightly frustrating, and therefore the new 2GIS for WP had to work offline.
The architecture of the new 2GIS under Windows Phone
Well, our small, but friendly team has clarified the basic requirements, was charged early in the morning with positive feedback from fresh reviews and began to develop. First of all, of course, architecture.
It should be said that in 2GIS, mobile applications have been doing for quite some time, and for other platforms, several versions have changed. When we designed the architecture, we took into account the experience gained by the company and the requirements voiced above. That's what happened.

Cross-platform core
The upper block in the picture is a cross-platform core, the foundation of everything, the entry point to all our algorithms and services. Our offline back end to which we ask questions and get answers. This thing provides us work without connecting to the network. We call it cross-platform, because we can build it not only under WP, but also under Windows, OS X, Linux, iOS and Android.
In accordance with the requirement to quickly add new features, everything new that appears in 2GIS appears in the kernel and automatically gets into the new 2GIS for WP (as in all products that use this kernel). The cross-platform kernel is developed in C ++ by very smart guys from the special team for the development of the cross-platform kernel. They are great, but I will not write anything more about them, because the article is not about them, but about Windows Phone.
Ui
The lowest block in the diagram is the UI, the front end, the part that the user is working with. It is developed using native platform tools (C # and XAML) to provide the user with the usual experience of interacting with his favorite platform as easily and efficiently as possible. At the time of this writing, several types of applications were available to developers under WP: Silverlight Application, Windows Phone (not Silverlight!) Application, Universal Application. But when we first started working on the new 2GIS, there was only Silverlight, so it’s not surprising that we chose it.
Intermediate layer
In order to make friends C ++ and C #, to teach the kernel to communicate with the application, and the application with the kernel, you need some intermediate layer in the form of the Windows Runtime Component, written in C ++ / CX.
OpenGL 3D Map
Continuing the conversation about offline, we can not say about our map, which also works without an internet connection. The 2GIS map is a fairly recognizable element. It is three-dimensional, cross-platform (also compiled for different operating systems) and written in OpenGL.
Unfortunately, OpenGL is not supported on WP, so we have to use
Angle to translate OpenGL calls to DirectX. I want to note that with the integration of the card we have suffered a lot of different things, but in the end we managed to launch it on WP. Of course, the use of Angle leaves its mark on performance, but we try to minimize this effect.
Instruments
As in any other application written in C # / XAML, the entire internal structure of the 2GIS frontend for WP obeys the MVVM pattern.
Any programmer using MVVM, sooner or later there is a need
to write your own start to use some MVVM framework. I present to you a very brief instruction on the choice of MVVM framework, not claiming to be the ultimate truth.
- Open your favorite browser. For example, Internet Exporer.
- Go to the site caliburnmicro.com .
- Download Caliburn.Micro, install and enjoy.
But seriously, in 2013, the popular MVVM frameworks running on WP8 were not very numerous. In fact, the choice was between Prism, MVVM Light and Caliburn. Micro. Prism is too monstrous, more suitable for large enterprise applications, MVVM Light, on the contrary, is too light, and I wanted something more. But Caliburn.Micro liked us for the following reasons.
Navigation support
Usually navigation between pages in a silverlight application looks like this:
NavigationService.Navigate(new Uri("/GroupPage.xaml?name=Administrators", UriKind.Relative));
This is not very beautiful, it is easy to make a mistake when entering lines, because no typing. The name parameter itself must be retrieved inside the page's onNavigated event in this form.
var name = NavigationContext.QueryString["name"];
Caliburn.Micro allows you to solve the same problem as follows.
NavigationService.UriFor<GroupPageViewModel>() .WithParam(x => x.Name, "Administrators") .Navigate();
The code looks beautiful, there is type control, and the Name parameter is immediately written to the corresponding ViewModel property when navigating.
State preservation support
Caliburm.Micro offers an interesting infrastructure for maintaining the state of the application. For example, in order to determine the persistence strategy for GroupPageViewModel, it is sufficient to define such a class.
public class GroupPageViewModelStorage : StorageHandler<GroupPageViewModel> { public override void Configure() { Property(x => x.Name) .InPhoneState() .RestoreAfterActivation(); } }
The code above means that if the system suddenly unloads your application while it is inactive, then the Name property of GroupPageViewModel will survive this trouble and will be saved and then restored when the application is reactivated.
Native support for IoC container
The heart of Caliburn.Micro is an
embedded IoC container with which the dependency injection pattern is implemented. When navigating between the ViewModel's pages, they get all the necessary services using constructor / property injection, and this is extremely convenient. I strongly recommend.
For WP - Pivot support
Caliburn.Micro provides the infrastructure in which each Pivot control page can be a separate View with its own ViewModel. This is very convenient, allows you to decompose logic and relatively easy to adjust the lazy loading of data for the Pivot tabs.
Special methods in viewmodels associated with the page life cycle
Screen class - the base class for most of your ViewModels has very convenient methods OnInitialize, OnActivate, OnDeactivate, etc., which are called by the framework when creating an instance of ViewModel and navigating to the corresponding page or leaving it. You can override these methods in your ViewModels and execute some useful code there.
Open source
Caliburn.Micro has open source code. If you lack something in the framework, you can always add it yourself.
Low threshold of entry
Getting started using Caliburn.Micro is easy. In addition, it is quite lightweight, all Caliburn.Micro code is quite possible to study in a day or two.
Saving Application State
It is worth saying that we have slightly refined the mechanism for maintaining the state of the application used in Caliburn.Micro. By default, Caliburn uses the standard XML serialization mechanisms used in WP. We added support for binary serialization using the
SharpSerializer . It turned out conveniently, quickly, and you can serialize almost anything.
Fast data delivery
So, the cross-platform core provides us with the rapid emergence of new features and work offline, but what about the fast delivery of data? How can new city data appear in the application if the application does not know anything about this data?
The answer is that along with the new data we have to supply a new UI to display it. In our case, these are XAML templates. Usually, XAML templates live within the application itself and come with it, but we want to distribute XAML resources separately and completely independently of the application itself.
I'm not sure that anyone else is doing it, but, by and large, there is nothing fantastic here. For some time we experimented with various options and settled on a very simple, in my opinion, scheme, which I will try to tell you now very simply.
Suppose that apart from the application we are distributing the data we want to display.
{ "data": "Windows Phone" }
Nothing special here - it's just json.
We also distribute (also separately from the application) the XAML template needed to display this data.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"> <DataTemplate x:Key="TestIcon"> <Path Width="42" Height="41" Stretch="Fill" Fill="{StaticResource PhoneForegroundBrush}" Data="F1 M 17,23L 34,20.7738L 34,37L 17,37L 17,23 ZM 34,55.2262L 17,53L 17,39L 34,39L 34,55.2262 ZM 59,17.5L 59,37L 36,37L 36,20.5119L 59,17.5 ZM 59,58.5L 36,55.4881L 36,39L 59,39L 59,58.5 Z " /> </DataTemplate> <DataTemplate x:Key="EntryPoint"> <StackPanel> <ContentPresenter ContentTemplate="{StaticResource TestIcon}" Margin="0,0,0,12" /> <TextBlock Text="{Binding [data]}" /> </StackPanel> </DataTemplate> </ResourceDictionary>
Here it is worth noting a few points.
- We will load this template on the side of the application as a string and parse using XamlReader.Load (). It naturally follows from this that not every XAML can be used like this. A valid XAML should not contain any code behind, no references to x: Class, event subscriptions, etc.
- DataTemplates are great for the previous requirement, so we will use them.
- We use ResourceDictionary as a container for several templates.
- Notice how we distribute the TestIcon icon, also in the form of a DataTemplate. And display it using ContentPresenter.
- The Text property of a text box is bound to some data property by binding to an indexer of some ViewModel'i (about which after). Please note that in our json there is an element with the exact same name, and this is no accident.
Suppose, already in the application itself, we have this View.
<phone:PhoneApplicationPage x:Class="DynamicXaml.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:DynamicXaml" mc:Ignorable="d"> <phone:PhoneApplicationPage.DataContext> <local:MainPageViewModel /> </phone:PhoneApplicationPage.DataContext> <ContentControl Content="{Binding DynamicData}" ContentTemplate="{StaticResource EntryPoint}" /> </phone:PhoneApplicationPage>
In this View, the ContentControl element is the entry point for displaying dynamic data. There is an important agreement here: ContentControl knows what it needs to display a template with the EntryPoint key, and it is this template in our XAML that we distribute separately. Actually, the key name is the only thing that the application knows about the template that will be shown.
Accordingly, ViewModel is defined for View, which implements some test magic on loading dynamic content.
public class MainPageViewModel { public MainPageViewModel() {
Let me explain a few points.
- In the example, I used Json.Net to parse json and get some object from it suitable for data binding. In fact, we use the DynamicDataContext for this purpose, but in this example JObject is used for simplicity.
- JObject has an indexer that takes a string — the name of the json element, and returns the value of this element.
- That is why in the template text of the text block is attached to the [data] indexer, which returns the value of the data element from json. So the usual json becomes the viewfinder for our template.
If you collect this example and run it on your favorite phone running Windows Phone, you can see such a picture.

It’s so easy and natural that we just displayed data in the application that the application knows nothing about. And the application also does not know how to display this data - all information is downloaded from 2GIS servers.
Results
We made a real 2GIS for WP: we have a three-dimensional map, a detailed directory of organizations, a cross-platform core, and we distribute xaml-templates independently of the application. And it all works without an internet connection. If for some reason you have not yet installed the new 2GIS on your Windows Phone smartphones, it
's time to do it .