
Quite often, you have to port an existing application to other platforms or initially write it for several platforms at once. In this article we will look at the basics of sharing the code specifically for the three platforms, but the principles described are applicable for developing cross-platform applications on other platforms, for example, using Xamarin.
Since the material was quite voluminous, I decided to split the article into two parts. Today, we will consider the basics of sharing for beginners, and if you already have basic skills, then you can safely skip this article and wait for the next one, where in practice we will look at more complicated code sharing scenarios.
')
And now I will talk about two main ways of sharing the code: linking files and a library with common code. Consistently consider both approaches, the main advantages and disadvantages of each of them.
0. CopyOf course, you can't start with linking without saying a few words about another popular way of sharing the code - copying. Copying and modification of the code for a specific platform is the easiest way of “sharing”, and, most likely, in places we will partially use this approach. But we will not consider it as the basic principle of sharinga due to the fact that it has more minuses than pluses. Advantages of the approach: we quickly get working code for another platform and at the same time our changes cannot affect the main platform in any way. Cons: maintenance is expensive, as you have to make the same changes already in each copy for each platform.
1. LinkingThe easiest, and perhaps the most popular way to write cross-platform applications, is to link files. Often, when we already have a ready-made application for WP7 and want to get the same application for WP8 (or vice versa), there is a great temptation to simply reuse the existing code and not make any changes to the existing application architecture (if the architecture has not been sharpened) ).
Consider step by step this approach.
For example, create a very simple WP8 application and on the main page (MainPage.Xaml) add the classic “calculator” - two text fields for entering numbers, an addition button and a field for outputting the result.
<StackPanel> <TextBlock Text="A" Style="{StaticResource PhoneTextLargeStyle}"></TextBlock> <TextBox x:Name="TextBoxA" Text=""></TextBox> <TextBlock Text="B" Style="{StaticResource PhoneTextLargeStyle}"></TextBlock> <TextBox x:Name="TextBoxB" Text=""></TextBox> <Button Content="Summ" Click="ButtonBase_OnClick"></Button> <TextBlock x:Name="TextBlockResult" Text="" Style="{StaticResource PhoneTextLargeStyle}"></TextBlock> </StackPanel>
And C # code
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { var valueA = Int32.Parse(TextBoxA.Text); var valueB = Int32.Parse(TextBoxB.Text); TextBlockResult.Text = (valueA + valueB).ToString(); }
Now we need to add a new project for WP7 to Solultion (File - Add - New project - Windows Phone App - Windows Phone 7).
After that, you must remove the MainPage.xaml from the WP7 project and add a link to the MainPage.xaml from the WP8 project.
In the context menu on the project WP7 (right mouse button), select Add - Existing Item.

Further in the folder with the project for WP8 we find the MainPage.xaml file (only this file, the .cs file will be added automatically) and select Add As Link.
In the end, you should have something like this in the project:

By and large, we have a project with a common code, and in the same way we can link, if necessary, also images or app.xaml. Now we can make changes to the project (for example, add validation of entering numbers) and receive these changes in both projects at once.
I also recommend specifying the same namespace for both projects in the properties.
Sooner or later we will face the features of each platform. We can separate these features using compilation symbols using #If / #else / #endif directives. For example, let's assume that we save data for WP8 and Win8 projects using ApplicationData, and for WP7, IsolatedStorage.
For example, for a WP8 project, we have the following method:
public async Task SaveText(string text) { var fileBytes = System.Text.Encoding.UTF8.GetBytes(text); var local = ApplicationData.Current.LocalFolder; var dataFolder = await local.CreateFolderAsync("DataFolder", CreationCollisionOption.OpenIfExists); var file = await dataFolder.CreateFileAsync("DataFile.txt", CreationCollisionOption.ReplaceExisting); using (var s = await file.OpenStreamForWriteAsync()) { s.Write(fileBytes, 0, fileBytes.Length); } }
Accordingly, for WP7 there may be the following code to save the string:
public void SaveText(string text) { using (var local = IsolatedStorageFile.GetUserStoreForApplication()) { using (var stream = local.CreateFile("DataFile.txt")) { using (var streamWriter = new StreamWriter(stream)) { streamWriter.Write(text); } } } }
How can we maximize our code?
First of all, it is necessary to unify the signature of the method, i.e. or refuse async / await on WP8 / Win8, or support async on WP7.
Of course, we don’t want to give up on goodies, so first we will install Microsoft.Bcl on WP7 project to support async. We can install it as via Nuget package manager (context menu by clicking on a project from WP7 - Manage NuGet Packages) or via the Nuget console with the following command (you can open the console in the studio via Tools -Nuget Package Manager - Package Manager Consol):
Install-Package microsoft.Bcl
(You should make sure that the Default Project is selected for WP7).
Now we can have the following code for saving text under WP7:
public async Task SaveText(string text) { using (var local = IsolatedStorageFile.GetUserStoreForApplication()) { using (var stream = local.CreateFile("DataFile.txt")) { using (var streamWriter = new StreamWriter(stream)) { streamWriter.Write(text); } } } }
It turns out the same method for WP7 and WP8 files. The question is how to combine the method body for a project under WP7, WP8, Win8?
This can be done using compilation symbols. Add them to the project is quite simple. In the properties of the project in the Build tab, we can add the necessary compilation characters (I, for example, prefer WP7 / WP8 / WIN8 characters).

As you can see, we can also separate the Windows 8 and Windows Phone platforms by the default character WINDOWS_PHONE.
Now that we have compilation symbols, we can divide our code for different platforms as follows:
public async Task SaveText(string text) { #if WP7 using (var local = IsolatedStorageFile.GetUserStoreForApplication()) { using (var stream = local.CreateFile("DataFile.txt")) { using (var streamWriter = new StreamWriter(stream)) { streamWriter.Write(text); } } } #else var fileBytes = System.Text.Encoding.UTF8.GetBytes(text); var local = ApplicationData.Current.LocalFolder; var file = await local.CreateFileAsync("DataFile.txt", CreationCollisionOption.ReplaceExisting); using (var s = await file.OpenStreamForWriteAsync()) { s.Write(fileBytes, 0, fileBytes.Length); } #endif }
Please note that in different projects the selection of the method is different, as the gray underlines the code that will not be compiled in this project. In this case, the file was opened in the WP7 project and if you close and open the file in the project with WP8, the selection will be inverted. Compiler "see" code for WP8
2. Library with shared code2.1. WP7 shared libraryIn the event that you have projects only for WP7 and WP8, you can select the common code into a separate Windows Phone 7 library and use this library for two projects. To do this, add a new project (File - Add - New Project) Windows Phone Class Library, select the Windows Phone 7 platform and name it in our calculator example, for example, CalculatorCore.
In order to be able to add pages to this project, you need to insert a link to the Microsoft.Phone library:

In the Assemblies - Framework tab:

The next step is to add a link to the Calculator Core project in WP7 and WP8 projects.
For each of the projects in References we add the link to the project in the same way, which can be found in the Solution tab:

Now we can transfer our MainPage page to this shared library.
If everything is done correctly, then the structure of your project will look like this:

In the same way, content, localization, UserControl, etc. can be transferred to the shared library.
In order for the project to work, the last step remains: in order for the project to find this page in a different assembly, you must add a full link to it in each project to the manifest files (file WMAppManifest.xml).
Those. instead of reference:
/>
You must write the full path:
/>
Now, if we run the project, we will see our page. Thus, we got two different projects, where we have one common working code. In the next article we will discuss how to use the features of each platform.
2.2. Library Portable LibraryOften we need to “fumble” code between several WP7 / WP8 / Win8 platforms, which have different UIs, but there is a common logic.
In this case, the general WP7 library, of course, does not suit us. Instead, we can use a project of type Portable Library (this type of project can be found in Windows templates and not Windows Phone):

As you can see, we can use common code even with Android and iOS, if you use, for example, Xamarin (In a “pure” form, the studio offers no Android and iOS items)
Here we can choose which types of project we will have, and at the same time we will use only those platform features that are in all selected types of projects.
More information on the list of supported features can be found on the
msdn website. Or, if you use,
Xamarin .
Here we will not dwell on this library in detail, since in the next part most of the examples will be connected with the Portable Library.
ConclusionIn practice, quite a lot of people and teams seek advice on the topic of code sharing and probably the sample is not presentable, but I saw that most novice developers prefer linking files.
In general, the popularity of sharing files is due to the simplicity and speed of implementation of this approach. In most cases, you do not need to refactor the code and you can take the existing code, making small insertions of compilation symbols, quickly use the features of the platform. On the contrary, a library with common code often does not allow for the simple separation of features of a platform, and in the next part we will dwell on this point in detail.
There are two significant drawbacks to the file linking approach, which is why I try not to use it:
- In large projects, refactoring and code maintenance are much more complicated, since the compiler and the studio simply do not see the code, which is divided by the compilation symbol.
- When adding a new platform or a new software, to use this code we will have to accompany all these changes again, often making edits to all symbols of the compilation. Maintenance code is complicated at times.
The main disadvantage of the common library approach is that more code is needed (although this is more than offset by ease of maintenance). In addition, for projects with low quality code, this method is poorly suited. During the consultation of different teams, I repeatedly encountered the fact that in order to use the common library, the teams had to do a rather large and voluminous job of “cleaning” the project. But on the other hand, the need to think that the code should be shared and for this it is necessary to single out a common logic indirectly led to an improvement in the quality of the code.
UpdatedAt the Build conference, a new type of UniversalApps project was shown that allows you to create a single application for W8.1 and WP8.1. Details can be found in the
article written by a wonderful author
shwars.