Совместимость приложений Windows Phone Classic и Windows Phone 7
После анонса Windows Phone 7 и первых технических деталей о новой мобильной платформе от Microsoft, стало известно, что обратной совместимости приложений с Windows Phone Classic не будет. По моим наблюдениям, на эту тему началось множество различных спекуляций и провокаций. Здесь я хотел бы подробно обсудить эту тему и рассказать о том, как обстоят дела на самом деле.
Итак, первое о чем сразу же хотелось бы сказать - обратной совместимости на уровне бинарников действительно нет. Это значит, что вы не можете взять готовое приложение для Windows Phone Classic и запустить его на Windows Phone 7 - этому есть ряд ограничений. Однако, не все так плохо, как может показаться на первый взгляд, и вот почему.
Дело в том, что все приложения для Windows Phone 7 (исключая системные) работают в рамках управляемого кода. При этом разрабатывать приложения предлагается используя Silverlight или XNA. Вот как выглядит схематическое обобщенное представление платформы Windows Phone 7.
Весь управляемый код по-прежнему работает в рамках старого и доброго .NET Compact Framework. Да, это не точная копия .NET Compact Framework 2.0 или 3.5, но суть от этого не изменяется. Если мы попробуем глубже взглянуть на среду исполнения, то увидим следующую картинку.
Что следует из этой схемы? А следует несколько интересных выводов. Во-первых, видно, что все управляемые приложения могут использовать стандартную BCL (Base Class Library) и множество уже привычных нам объектов и пространств имен, например, таких как System.IO, System.Text, System.Threading и т.д. Дальше отчетливо видно, что и приложения XNA, и приложения Silverlight могут использовать эти объекты для своей работы, однако каждый из них имеет собственные объекты специфичные для каждого из вариантов. Эти объекты в большинстве случаев отвечают за построение пользовательского интерфейса или предназначены для сопутствующих задач. Ну и, наконец, видно, что есть несколько объектов "надстроек" над Silverlight и XNA, которые специфичны для телефона. Например, такие объекты позволяют получить доступ к камере или сенсорам, работать с радио или вызывать системные окна и т.д.
Если говорить о совместимости приложений, то такой подход позволяет нам безболезненно портировать часть приложения для Windows Phone Classic на новую платформу, если оно написано на управляемом коде. Портировать только часть приложения мы сможем из-за того, что среди представленных объектов нет Windows Forms. Это означает, что функциональность, связанную с пользовательским интерфейсом придется все-таки переделать. Но переделать пользовательский интерфейс - это не значит переделать полностью все приложение!
Таким образом, если ваше приложение для Windows Phone Classic работает на управляемом коде, то большую часть логики вы скорее всего сможете перенести путем простого копирования кода в новое приложение.
Как известно, рассуждать проще, чем сделать на практике. Поэтому здесь я прервусь и попробую взять приложение Windows Phone Classic и перенести его на новую платформу. Поехали!
Эксперимент по переносу приложения с WP Classic на WP7
Итак, для того, чтобы нам перенести наше Windows Phone Classic приложение, нам нужно сначала его создать. Я не буду сейчас уделять внимание какой-либо сложной логике, а создам несложное приложение, вычисляющее тригонометрические функции. Для этого на форме я добавлю несколько элементов управления и задам для них обработчики. Выглядеть эта красота будет примерно так.
Позволю себе напомнить, что при добавлении элементов управления в дизайнер среда разработки автоматически генерирует код и помещает его в файл ".designer.cs". Выглядит этот код примерно так:
namespace MyHardApplication
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.SinTextBox = new System.Windows.Forms.TextBox();
this.SinButton = new System.Windows.Forms.Button();
this.CosButton = new System.Windows.Forms.Button();
this.CosTextBox = new System.Windows.Forms.TextBox();
this.TanButton = new System.Windows.Forms.Button();
this.TanTextBox = new System.Windows.Forms.TextBox();
this.AtanButton = new System.Windows.Forms.Button();
this.AtanTextBox = new System.Windows.Forms.TextBox();
this.SuspendLayout();
// Определение элементов управления
//
// SinTextBox
//
this.SinTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SinTextBox.Location = new System.Drawing.Point(12, 16);
this.SinTextBox.Name = "SinTextBox";
this.SinTextBox.Size = new System.Drawing.Size(138, 21);
this.SinTextBox.TabIndex = 0;
// Аналогичное описание для остальных элементов управления
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoScroll = true;
this.ClientSize = new System.Drawing.Size(240, 294);
this.Controls.Add(this.AtanButton);
this.Controls.Add(this.AtanTextBox);
this.Controls.Add(this.TanButton);
this.Controls.Add(this.TanTextBox);
this.Controls.Add(this.CosButton);
this.Controls.Add(this.CosTextBox);
this.Controls.Add(this.SinButton);
this.Controls.Add(this.SinTextBox);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TextBox SinTextBox;
private System.Windows.Forms.Button SinButton;
private System.Windows.Forms.Button CosButton;
private System.Windows.Forms.TextBox CosTextBox;
private System.Windows.Forms.Button TanButton;
private System.Windows.Forms.TextBox TanTextBox;
private System.Windows.Forms.Button AtanButton;
private System.Windows.Forms.TextBox AtanTextBox;
}
}
m.Windows.Forms.TextBox AtanTextBox;
}
}
[/code]
Как видно, такое описание достаточно легко поддается прочтению и осмыслению и впоследствии может послужить основной для переноса пользовательского интерфейса. Но об этом позже.
Как я говорил, для кнопок мы создадим обработчики с минимальной логикой. В реальном приложении кода, конечно, будет больше, но суть от этого не меняется.
[code]public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void SinButton_Click(object sender, EventArgs e)
{
SinTextBox.Text = Math.Sin(double.Parse(SinTextBox.Text)).ToString();
}
private void CosButton_Click(object sender, EventArgs e)
{
CosTextBox.Text = Math.Cos(double.Parse(CosTextBox.Text)).ToString();
}
private void TanButton_Click(object sender, EventArgs e)
{
TanTextBox.Text = Math.Cos(double.Parse(TanTextBox.Text)).ToString();
}
private void AtanButton_Click(object sender, EventArgs e)
{
AtanTextBox.Text = Math.Cos(double.Parse(AtanTextBox.Text)).ToString();
}
}
[/code]
Итак, теперь у нас есть готовое работающее приложение для Windows Phone Classic. Давайте попробуем перенести его на Windows Phone 7.
Первое, что мы сделаем - попробуем преобразовать пользовательский интерфейс. Для этих целей уже сейчас доступны различные инструменты (например,
На выходе получим разметку, похожую на следующую:
[code]<phoneNavigation:PhoneApplicationPage
x:Class="MyHardApplication.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phoneNavigation="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Navigation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}">
<Canvas x:Name="cvsForm1" Background="{StaticResource PhoneBackgroundBrush}">
<Button x:Name="AtanButton" Width="144" Height="20" Canvas.Top="249" Canvas.Left="307" Content="Atan"
Click="AtanButton_Click" />
<TextBox x:Name="AtanTextBox" Width="289" Height="20" Canvas.Top="249" Canvas.Left="12" Text="" />
<Button x:Name="TanButton" Width="144" Height="20" Canvas.Top="171" Canvas.Left="307" Content="Tan"
Click="TanButton_Click" />
<TextBox x:Name="TanTextBox" Width="289" Height="20" Canvas.Top="171" Canvas.Left="12" Text="" />
<Button x:Name="CosButton" Width="144" Height="20" Canvas.Top="93" Canvas.Left="307" Content="Cos"
Click="CosButton_Click" />
<TextBox x:Name="CosTextBox" Width="289" Height="20" Canvas.Top="93" Canvas.Left="12" Text="" />
<Button x:Name="SinButton" Width="144" Height="20" Canvas.Top="16" Canvas.Left="307" Content="Sin"
Click="SinButton_Click" />
<TextBox x:Name="SinTextBox" Width="289" Height="20" Canvas.Top="16" Canvas.Left="12" Text="" />
</Canvas>
</phoneNavigation:PhoneApplicationPage>
[/code]
К сожалению, используемый мной инструмент для переноса не смог перенести обработчики, а также не совсем корректно обработал отступы. Но в целом результат получился неплохой.
Ну и осталось только перенести код логики (простым копированием) и обработчиков.
[code]public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;
}
private void SinButton_Click(object sender, RoutedEventArgs e)
{
SinTextBox.Text = Math.Sin(double.Parse(SinTextBox.Text)).ToString();
}
private void CosButton_Click(object sender, RoutedEventArgs e)
{
CosTextBox.Text = Math.Cos(double.Parse(CosTextBox.Text)).ToString();
}
private void TanButton_Click(object sender, RoutedEventArgs e)
{
TanTextBox.Text = Math.Tan(double.Parse(TanTextBox.Text)).ToString();
}
private void AtanButton_Click(object sender, RoutedEventArgs e)
{
AtanTextBox.Text = Math.Atan(double.Parse(AtanTextBox.Text)).ToString();
}
}
[/code]
Теперь можно запустить приложение и полюбоваться на результат.
Так мы перенесли небольшое приложение с Windows Phone Classic на Windows Phone 7 в несколько шагов.
Подводим итог
В этом примере я не старался показать, что перенести приложение на Windows Phone 7 можно в несколько кликов. Однако, я думаю теперь стало понятно, что процесс переноса приложений не такой уж и страшный, и некоторых ситуациях не нужно переписывать приложения полностью с чистого листа.
Тем не менее, справедливости ради стоит отметить, что такой подход не работает в случае когда:
- Исходное приложение работает на неуправляемом (native) коде;
- Исходное приложение использует вызовы P/Invoke (в этом случае этот участок кода придется дорабатывать);
- Исходное приложение использует сторонние (нестандартные) элементы управления - в этом случае конвертеры в XAML вряд ли смогут обработать эти случаи.
Также стоит сказать, что библиотека .NET CF в WP7 покрывает не все объекты, которые были доступны в WP Classic. Поэтому при переносе логики также могут возникать ньюансы.
Однако, в целом видно, что платформы очень схожие и перенос своих приложений - не такое уж и тяжелое занятие.
Источник:
Автор: sergey.zwezdin
По теме
- Видео-курсы от MS: Разработка приложений виртуальной и расширенной реальности на платформе Microsoft
- ECMA JavaScript 6: Объекты
- Как просто создать приложение для iPhone
- Разработка приложений под Windows Phone 8
- Индексированное хранилище, часть 2
- Индексированное хранилище, часть 1
- Начала Metro-программирования: создание настраиваемых приложений (ч.2)
- Начала Metro-программирования: создание настраиваемых приложений (ч.1)
- Начала Metro-программирования: создание компонентов WinRT (ч.3)
- Начала Metro-программирования: создание компонентов WinRT (ч.2)