Статьи

Повторное использование существующих компонентов Silverlight с Windows Phone 7


Использование .NET — это все, что касается использования вашего кода на разных платформах.
Это было верно в отношении предыдущих версий ОС Windows Mobile и в современной среде, ориентированной на XAML. Но с Silverlight разработчик .NET должен уделять особое внимание разделению логики ядра и пользовательского интерфейса, чтобы повторно использовать большую часть кода. Организовав свое приложение в шаблон MVVM, или шаблон Model-View-Presenter (он же View-Model), вы сможете повторно использовать удивительный объем кода между вашими веб-приложениями Silverlight и приложениями для Windows Phone 7. В этом пошаговом руководстве будет показано базовое приложение Silverlight и продемонстрировано, как это сделать.

Этот учебник структурирован из статьи следующим образом:

MVVM и повторное использование кода

MVVM Обзор

MVVM — это шаблон архитектуры, целью которого является организация кода на трех уровнях: модель, представление и модель представления. Это дает множество преимуществ, наиболее важными из которых являются:

  • Разделение логики GUI и логики приложения. Шаблон полностью разделяет представление и модель, поэтому при внесении изменений в один из них их можно сделать, не затрагивая другой.
  • Поддержка юнит-тестов. Функциональность приложения может быть полностью протестирована путем написания модульных тестов, что сводит к минимуму (или устраняет) необходимость тестов на основе пользовательского интерфейса.
  • Поддержка инструмента. Представители, заполненные фиктивными данными, могут редактироваться дизайнерами в Blend и Visual Studio без изменения других частей проекта.

Другое преимущество MVVM, которое часто упускается из виду, заключается в том, что он позволяет эффективно повторно использовать код при переносе между Silverlight, Windows Phone 7 (и в некоторой степени также WPF).

Повторное использование кода с MVVM

MVVM делает повторное использование кода особенно мощным в приложениях Silverlight и WP7 благодаря структурированию его уровней. Модель содержит бизнес-логику без специфических для фреймворка деталей, поэтому она может быть разделена между реализациями Silverlight и WP7. Если логика пользовательского интерфейса приложения идентична или схожа для обоих приложений, большая часть (если не все) кода уровня ViewModel также может использоваться совместно. Однако View в большинстве случаев существенно отличается для приложений Silverlight и WP7. Даже если есть возможность совместно использовать части View между двумя проектами, поскольку веб-интерфейс обычно сильно отличается от телефонного интерфейса, обычно это не имеет смысла.

Таким образом, используя MVVM, можно повторно использовать весь код существующего приложения Silverlight, кроме View. Учитывая, что веб-приложения Silverlight и Windows Phone 7 большую часть времени вызывают разные пользовательские интерфейсы, это означает, что с MVVM нужно переписать только часть интерфейса приложения.

Повторное использование компонентов Silverlight с WP7: пример

Чтобы понять, как эффективно использовать код из существующего приложения Silverlight при портировании на Windows Phone 7, давайте рассмотрим простой пример — калькулятор экономии.

Приложение Silverlight

Приложение Silverlight в этом примере представляет собой простой калькулятор сбережений, который при запуске выглядит следующим образом:

в приложении пользователь должен ввести начальную сумму депозита, ежемесячный депозит, годовую процентную ставку и количество лет, на которые нужно сэкономить. Затем приложение рассчитывает общую сумму депозита, а также окончательную экономию с добавлением годовых процентов.

В приложении три слоя проекта структурированы в три отдельных проекта. Модель представляет собой библиотеку классов Silverlight 3 с именем
SavingsCalculatorModel , ViewModel также является библиотекой классов SL 3 с именем
SavingsCalculatorViewModel, а View (приложение, которое будет запущено) является приложением SL 4 с именем
SavindsCalculatorSilverlight., Зависимости такие же, как и в шаблоне MVVM: проект ViewModel ссылается на модель, а проект View ссылается на ViewModel.

Обрисовав интерфейс и архитектуру примера приложения, давайте посмотрим, как оно реализовано с использованием Silverlight.

Модель

Слой модели отвечает за реализацию бизнес-логики. В случае этого приложения калькулятора сбережений это означает ответственность за расчет сбережений без процентов и с процентами. Код модели довольно прост и состоит из нескольких свойств и
метода
CalculateSavings, который рассчитывает общий депозит и окончательную экономию. Код для этого выглядит следующим образом:

public class SavingsCalculatorModel
{
public int NumberOfYears { get; set; }

public double AnnualInterest { get; set; }

public double InitialAmount { get; set; }

public double MonthlyDeposit { get; set; }

public double FinalSavingsWithInterest { get; private set; }

public double FinalSavingsWithoutInterest { get; private set; }

/// Calculates FinalSavingsWithInterest and FinalSavingsWithoutInterest based on
/// InitialAmount, NumberOfYears, AnnualInterest and MonthlyDeposit
public void CalculateSavings()
{
// See source for details
}
}

Вид

В представлении мы отображаем поля ввода для всех необходимых сведений, кнопку для запуска расчета и результаты этого расчета. Для этого нам нужно создать
элементы
TextBlock для текстов,
TextBoxes для ввода и
кнопку для кнопки расчета.

Значения входных
TextBoxes являются данными, привязанными к членам ViewModel. Это делается с помощью двусторонней привязки, чтобы изменения, сделанные пользователем, применялись к ViewModel. Например, поле ввода для годового процента настраивается следующим образом:

<TextBox Text="{Binding InitialAmount, Mode=TwoWay}"/>

Нам также нужно привязать результат расчетов к представлению. Результаты не должны изменяться пользователем, поэтому мы можем использовать одностороннюю привязку (и поскольку это значение по умолчанию, нет необходимости указывать режим привязки).

<TextBlock Text="{Binding FinalSavingsWithInterest}" FontWeight="Bold"/>

Последней частью настройки View является пересылка
события
Click Button в ViewModel. Это делается с помощью командования, то есть
передачи команд в ViewModel. Для этого нам нужно привязать
свойство
Command Button к ICommand, который будет выставлен во ViewModel:

<Button Command="{Binding CalculateCommand}"/>

Код для представления можно найти в прилагаемом исходном коде в файле MainPage.xaml.

public class SavingsCalculatorViewModel: INotifyPropertyChanged
{
private SavingsCalculatorModel _model;

public int NumberOfYears
{
get
{
return _model.NumberOfYears;
}
set
{
_model.NumberOfYears = value;
}
}
// Similarly wrapping of AnnualInterest, InitialAmount, MonthlyDeposit, FinalSavingsWithInterest and FinalSavingsWithoutInterest
(...)

public ICommand CalculateCommand
{
get
{
return new RelayCommand(CalculateSavings) { IsEnabled = true };
}
}

private void CalculateSavings()
{
_model.CalculateSavings();
RaisePropertyChanged("FinalSavingsWithoutInterest");
RaisePropertyChanged("FinalSavingsWithInterest");
}

// Constructor initializing the default values and INotifyProperyChanged implementations
(...)

ViewModel

ViewModel отвечает за склейку модели и вида. Он должен будет раскрыть все свойства, с которыми будет связан Вид, и обернуть их вокруг Модели. В этом примере ViewModel довольно прост: он действует как обертка вокруг модели, устанавливает для нее значения по умолчанию при инициализации и предоставляет команду
CalculateCommand, которая запускается при нажатии кнопки вычисления. В примере используется простая реализация ICommand —
версия
RelayCommand Джоша Смита . Важными частями кода ViewModel являются следующие:

public class SavingsCalculatorViewModel: INotifyPropertyChanged
{
private SavingsCalculatorModel _model;

public int NumberOfYears
{
get
{
return _model.NumberOfYears;
}
set
{
_model.NumberOfYears = value;
}
}
// Similarly wrapping of AnnualInterest, InitialAmount, MonthlyDeposit, FinalSavingsWithInterest and FinalSavingsWithoutInterest
(...)

public ICommand CalculateCommand
{
get
{
return new RelayCommand(CalculateSavings) { IsEnabled = true };
}
}

private void CalculateSavings()
{
_model.CalculateSavings();
RaisePropertyChanged("FinalSavingsWithoutInterest");
RaisePropertyChanged("FinalSavingsWithInterest");
}

// Constructor initializing the default values and INotifyProperyChanged implementations
(...)

Портирование приложения Silverlight на Windows Phone

Теперь, когда мы увидели, как создается приложение Silverlight, давайте рассмотрим его портирование на Windows Phone 7. Мы хотим сохранить ту же логику приложения, но немного оптимизировать пользовательский интерфейс для телефона, чтобы придать ему естественный вид. После завершения работы перенесенное приложение Windows Phone 7 будет выглядеть следующим образом:

Портирование модели и ViewModel

Поскольку бизнес-логика не изменилась, весь код модели повторно используется в приложении WP7. В этом примере Model была библиотекой классов Silverlight, поэтому проекту Windows Phone просто нужна ссылка, указывающая на проект модели.

Наши требования к пользовательскому интерфейсу функционально такие же, как и для приложения Silverlight, что означает, что весь код ViewModel также может быть повторно использован — никакого кодирования пока не требуется!

Портирование вида

При переносе представления приложения нет особого смысла повторно использовать представление приложения Silverlight. На интерфейсе телефона нам бы хотелось, чтобы пользовательский интерфейс гармонировал с миром WP7. Нам нужно изменить исходный вид, чтобы добиться этого. Вот некоторые из изменений, которые мы вносим в представление:

Обзор портирования

Перенос этого приложения Silverlight на Windows Phone оказался удивительно простым: мы смогли повторно использовать слои Model и ViewModel исходного приложения без изменений, и нам пришлось только переписать View. Однако, поскольку приложение Silverlight, запускаемое в браузере и на телефоне, требует различных пользовательских интерфейсов, нам пришлось бы вносить изменения в пользовательский интерфейс телефона во всех случаях.

В целом можно с уверенностью сказать, что, разработав пример Silverlight по шаблону MVVM, мы смогли перенести его на Windows Phone 7, повторно использовав большую часть его кода и переписав только часть, специфичную для пользовательского интерфейса Windows Phone — View.

Скачать код

Решение, содержащее Model, ViewModel, Silverlight View и Windows Phone 7 View, можно
загрузить здесь . Чтобы запустить приложение Silverlight, создайте и запустите проект SavingsCalculatorSilverlight, для приложения Windows Phone создайте и запустите проект SavingsCalculatorWP7.

Мысли о повторном использовании кода между Silverlight и Windows Phone

Повторное использование частей представления с помощью пользовательских элементов управления

В этом примере мы не использовали какую-либо часть представления. Основной причиной этого было то, что XAML страницы Silverlight и страницы Windows Phone различаются, что делает невозможным совместное использование одного и того же XAML.

Тем не менее, можно повторно использовать
UserControls между приложениями Silverlight и Windows Phone. Это можно сделать как на уровне сборки, так и с помощью ссылки на XAML UserControl.

Возможные проблемы при повторном использовании компонентов Silverlight с Windows Phone

Структурирование проекта Silverlight по шаблону MVVM не всегда гарантирует, что код будет на 100% повторно использован. Если приложение Silverlight использует API, которые не реализованы в среде выполнения Windows Phone 7 Silverlight, проект не будет компилироваться для Windows Phone. Поскольку Windows Phone 7 запускает расширенную среду Silverlight 3, в настоящее время эта проблема в основном локализована для нескольких новых API, представленных в Silverlight 4. Однако, когда выйдет Silverlight 5 для Интернета, эта проблема, вероятно, станет более важной.

Есть несколько обходных путей для решения этой проблемы, два наиболее распространенных из них:

  • Оберните определенные вызовы Silverlight 4 (или позже Silverlight 5) между определениями макросов #if! WINDOWS_PHONE (…) #endif . Таким образом, они будут скомпилированы только в проекте Silverlight, так как в проекте Windows Phone по умолчанию определена константа WINDOWS_PHONE .
  • Используйте частичные классы и переместите логику, зависящую от версии фреймворка, в файл частичных классов, на который ссылается только решение Silverlight.

Реализация командования последовательным образом

В этом примере мы реализовали команду (связывающую команду кнопки с действием в ViewModel), отличную для приложения Silverlight от порта Windows Phone. Причиной этого было то, что элементы управления вводом в Windows Phone имеют только понятия триггеров, а не команд. Мы разрешили ситуацию с помощью
вспомогательного класса EventToCommand фреймворка
MVVM Light для пересылки событий, вызванных триггерами, командам в ViewModel. Это означает, что, находясь внутри проекта Silverlight, мы использовали следующий синтаксис для привязки к команде:

<Button Content="Calculate" Command="{Binding CalculateCommand}" />

В Windows Phone, с другой стороны, мы использовали этот синтаксис:

<Button Content="Calculate" xmlns:mvvmlight="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7" xmlns:interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="Click">
<mvvmlight:EventToCommand Command="{Binding CalculateCommand}" />
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
</Button>

Этой ситуации можно было бы избежать, используя одну и ту же инфраструктуру MVVM для проекта Silverlight и WP7. В этом примере ключом была простота, поэтому в примере Silverlight не использовалась инфраструктура MVVM. Однако в реальном проекте определенно стоит использовать одну и ту же платформу в проектах Silverlight и Windows Phone 7 для максимального повторного использования кода. Среды MVVM, поддерживающие среды Silverlight и WP7, включают
MVVM Light ,
Caliburn Micro и — в определенной степени — Prism (
Silverlight и
сборка
WP7 ).

Резюме

В статье кратко описаны некоторые ключевые преимущества использования MVVM в проектах Silverlight, а также показано, как структурирование проекта по шаблону MVVM помогает повторно использовать код при переносе на Windows Phone. Затем было дано пошаговое руководство по созданию простого примера — калькулятора сбережений — который дает краткий обзор структуры проекта. Затем он объяснил, как перенести его на Windows Phone, повторно используя весь код, кроме слоя View, специфичного для пользовательского интерфейса. Наконец, были рассмотрены некоторые другие темы, которые могут быть важны при повторном использовании кода Silverlight в WP7, такие как повторное использование частей представления, командование и возможные проблемы.

Подводя итог, статья продемонстрировала еще одно преимущество структурирования проектов Silverlight по шаблону MVVM. Таким образом можно позднее перенести его на Windows Phone 7, только переписав определенные части пользовательского интерфейса приложения.