Портирование Windows Phone 7 приложений на Windows 8 Metro

Совсем недавно Microsoft представила сборку windows 8 для разработчиков. Сборка ранняя и неоднозначная. Меня она интересовала в первую очередь с точки зрения ос для планшетного устройства и как она сочетается с приложениями для windows phone 7.

Когда на презентации показали windows store, думаю, не один я заметил множество иконок приложений для wp7 (в основном это были иконки игр xbox live):

рис 1

Это вселило мне некоторые надежды, но Microsoft пока их развеивает.

Надежды были на то, что МС даст способ запускать приложения скомпилированные для WP7. Такой подход не нов, при разработке под iOS вы можете в некоторых случаях создать 2 файла описывающих интерфейс: для телефона и планшета. Учитывая возможности .NET и XAML, на стеке Microsoft было бы даже больше пространства для маневра. Я, как и все разработчики хочу максимального переиспользования кода. Возможно с развитием обоих ОС (w8 и wp7) так и будет, но пока нам предлагают компилировать два разных приложения с разной архитектурой

Архитектура

на wp7 во главе угла стоит постраничная навигация. В WPF вы можете использовать XBAP или NavigationWindows. Если вы откроете не пустой шаблон .Net Metro приложения, то увидите, что навигация там осуществляется вручную, по средствам глобальных функций приложения, которые подменяют контент у окна. Хорошо, что нам оставили Frame и Navigation window можно сделать вручную на его основе.

Для этого я взял в качестве шаблона SplitApplication. Все ресурсы из xaml перенесятя в app.xaml (Здесь вы можете заметить, что вместо понятия AccentBrush используется локально заданная HighlightBrush). Далее, внутри файла остается только заголовок с кнопкой Назад. В тело файла помещаем Frame. Вот что получилось у меня:

<UserControl x:Class="Navigation.NavigationController"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;

xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;

xmlns:my="using:Navigation"

Loaded="Page_Loaded" Unloaded="Page_Unloaded"

mc:Ignorable="d"

d:DesignHeight="768" d:DesignWidth="1366">

<!— Page Content —>

<Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}">

<VisualStateManager.VisualStateGroups>

<VisualStateGroup x:Name="OrientationStates">

<VisualState x:Name="Full" />

<VisualState x:Name="Fill" />

<VisualState x:Name="Portrait" />

<VisualState x:Name="Snapped">

<Storyboard>

<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Style" Storyboard.TargetName="BackButton">

<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnapBackButtonStyle}"/>

</ObjectAnimationUsingKeyFrames>

<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Style" Storyboard.TargetName="PageTitle">

<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnapPageTitleStyle}"/>

</ObjectAnimationUsingKeyFrames>

</Storyboard>

</VisualState>

</VisualStateGroup>

</VisualStateManager.VisualStateGroups>

<Grid.RowDefinitions>

<RowDefinition Height="140"/>

<RowDefinition Height="*"/>

</Grid.RowDefinitions>

<!— Standard title area —>

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="Auto" />

<ColumnDefinition Width="*" />

</Grid.ColumnDefinitions>

<Button x:Name="BackButton" Style="{StaticResource BackButtonStyle}" Click="BackButton_Click" IsEnabled="{Binding CanGoBack, ElementName=NavigationFrame}"/>

<TextBlock x:Name="PageTitle" Text="{StaticResource AppName}" Grid.Column="1" Style="{StaticResource PageTitleStyle}" />

</Grid>

<Frame Name="NavigationFrame" Grid.Row="1" Grid.ColumnSpan="2">

<my:MainPage/>

</Frame>

</Grid>

</UserControl>

Далее необходимо обеспечить навигацию внутри страниц. Я не нашел ничего лучше чем передавать Frame наверх в класс App:

namespace Navigation

{

partial class App

{

public App()

{

InitializeComponent();

}

public Frame ApplicationFrame { get; set; }

protected override void OnLaunched(LaunchActivatedEventArgs args)

{

var nc = new NavigationController();

ApplicationFrame = nc.AppFrame;

Window.Current.Content = nc;

Window.Current.Activate();

}

}

}

После этого навигацию можно будет осуществлять с помощью подобных вызовов:

(App.Current as App).ApplicationFrame.Navigate("url");

Элементы управления

Что касается элементов управления, то тут все интересно. Начать стоит с того что все они сменили пространство имен. Теперь они доступны по «адресу» Windows.UI.Xaml.Controls.

Так же стоить помнить, что на windows 8 доступно намного больше рабочего пространства, нежели на телефоне (минимальное разрешение 1024×768). Поэтому базовые для wp7 Pivot и Panorama способен заменить горизонтальный ListBox. Впрочем, тут есть еще одна тонкость, в windows 8 существует возможность «прилепить» программу к краю экрана (для этого нужно иметь разрешение экрана минимум 1366×768). Какие-то интерфейсы могут сами легко масштабироваться на меньший размер, у других следует сменить макет. Примером второго интерфейса служит Tweet@rama, ListView которой превращается в табы.

рис2

рис3

Для этого в своем приложении можно определить поведение в корневом элементе управления с помощью <VisualStateManager.VisualStateGroups>. В нем вы можете определить поведение при переходе в соответствующее состояние:

<VisualStateManager.VisualStateGroups>

<VisualStateGroup x:Name="OrientationStates">

<VisualState x:Name="Full"/>

<VisualState x:Name="Fill"/>

<VisualState x:Name="Portrait"/>

<VisualState x:Name="Snapped">

<Storyboard>

<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="flip">

<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>

</ObjectAnimationUsingKeyFrames>

</Storyboard>

</VisualState>

</VisualStateGroup>

</VisualStateManager.VisualStateGroups>

В целом, пожалуй, больше проблем не должно быть.

Асинхронные запросы

Если ваше приложение делает хоть что-нибудь полезное для общества, то вы скорее всего используете асинхронные запросы. Здесь МС сделала решительный шаг: такие запросы теперь другие. Да они удобные, но они другие. Если раньше нам приходилось обращаться к сервису подобным образом:

public void ReadRss(Uri rssUri)

{

WebClient wclient = new WebClient();

wclient.OpenReadCompleted += (sender, e) =>

{

if (e.Error != null)

return;

Stream str = e.Result;

//код обработки результата

};

wclient.OpenReadAsync(rssUri);

}

Т.е. по сути, приходилось плодить методы. А при последовательных запросах, когда параметры одного зависят от результатов предыдущего, код становился трудно читаемым. В Metro приложениях асинхронность строится вокруг класса Task. И предыдущий код может быть представлен в следующем виде:

public async void ReadRss(Uri rssUri)

{

HttpClient wclient = new HttpClient();

var resp = await wclient.GetAsync(rssUri);

Stream str = resp.Content.ContentReadStream;

// код обработки результата

}

Подробнее о новом подходе к асинхронности можно найти по ключевой фразе Async CTP.

Tasks

Пожалуй, последняя тема, которую я хочу затронуть это задачи. Не те задачи, что были описаны в предыдущей части, а задачи находящиеся в Microsoft.Phone.Tasks. Здесь они распределены по нескольким пространствам имен. Например если вы хотите получит контакты, то вам нужно Windows.ApplicationModel.Contacts (ContactPicker). Если хотите работать с магазином — Windows.ApplicationModel.Store. Для файлов Windows.Storage.Pickers.

Отправка Email отличается от того что мы заем по wp7. Для этого вы можете воспользоваться механизмами sharing contract. Смысл в том, что вы готовите данные, которые готовы опубликовать, а пользователь самостоятельно выбирает, с помощью какого приложения он готов это сделать.

рис4

Но на данный момент они не описаны для .Net приложений.

Заключение

У меня как wp7 разработчика очень неоднозначное ощущение от всего выше описанного. С одной стороны, если отойти от задачи портирования, то все достаточно логично и удобно (кроме, быть может, навигации). Но когда начинаешь думать о портировании более-менее объемного приложения с wp7, понимаешь что лучше сразу писать с нуля. Надеюсь, конечно, что к выходу w8 и wp8 разница между платформами заметно уменьшится (асинхронные подходы сделают аналогичными в wp, к примеру). Но пока Microsoft меня как разработчика держит в напряжении.

Стоит так же добавить, что не все тонкие моменты мне довелось рассмотреть. На dev.windows.com можно найти более подробную информацию по этому поводу, в том числе с таблицами соотношения namespace в wp7 и w8.

Реклама
Comments
5 комментариев to “Портирование Windows Phone 7 приложений на Windows 8 Metro”
  1. http://msdn.microsoft.com/en-us/library/windows/apps/hh465045(v=vs.85).aspx#adding_pages_and_navigation
    там есть про навигацию.
    по моему меньший велосипед

    • Да я в это видел, более того, я в статье про это же и пишу 😉 там 2 варианта навигации либо вручную выставлять контент окна (то есть никакой истории и прочего) и использовать frame на втором яостановился подробнее 😉

  2. Хорошая статья Дим!

  3. I really like what you guys tend to be up too. This sort of clever work and exposure!
    Keep up the awesome works guys I’ve included you guys to our blogroll.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: