Создание представлений HTML с помощью шаблонов Razor
В мире разработки мобильных устройств термин "гибридное приложение" обычно относится к приложению, которое представляет некоторые (или все) его экраны как HTML-страницы внутри размещенного элемента управления веб-просмотра.
Существуют некоторые среды разработки, которые позволяют создавать мобильное приложение полностью в HTML и JavaScript, однако эти приложения могут страдать от проблем с производительностью при попытке выполнить сложную обработку или эффекты пользовательского интерфейса, а также ограничены в функциях платформы, к которым они могут получить доступ.
Xamarin предлагает лучшие из обоих миров, особенно при использовании обработчика шаблонов Razor HTML. Благодаря Xamarin вы можете создавать кроссплатформенные шаблонные HTML-представления, использующие JavaScript и CSS, но также имеют полный доступ к базовым API-интерфейсам платформы и быстрой обработке с помощью C#.
В этом документе объясняется, как использовать обработчик шаблонов Razor для создания представлений HTML+JavaScript+CSS, которые можно использовать на мобильных платформах с помощью Xamarin.
Использование веб-представлений программным способом
Прежде чем узнать о Razor, в этом разделе описывается, как использовать веб-представления для отображения HTML-содержимого напрямую — в частности HTML-содержимое, созданное в приложении.
Xamarin предоставляет полный доступ к базовым API платформы в iOS и Android, поэтому легко создавать и отображать HTML с помощью C#. Ниже показан базовый синтаксис для каждой платформы.
iOS
Отображение HTML в элементе управления UIWebView в Xamarin.iOS также занимает несколько строк кода:
var webView = new UIWebView (View.Bounds);
View.AddSubview(webView);
string contentDirectoryPath = Path.Combine (NSBundle.MainBundle.BundlePath, "Content/");
var html = "<html><h1>Hello</h1><p>World</p></html>";
webView.LoadHtmlString(html, NSBundle.MainBundle.BundleUrl);
Дополнительные сведения об использовании элемента управления UIWebView см. в рецептах iOS UIWebView.
Android
Отображение HTML в элементе управления WebView с помощью Xamarin.Android выполняется всего в нескольких строках кода:
// webView is declared in an AXML layout file
var webView = FindViewById<WebView> (Resource.Id.webView);
// enable JavaScript execution in your html view so you can provide "alerts" and other js
webView.SetWebChromeClient(new WebChromeClient());
var html = "<html><h1>Hello</h1><p>World</p></html>";
webView.LoadDataWithBaseURL("file:///android_asset/", html, "text/html", "UTF-8", null);
Дополнительные сведения об использовании элемента управления WebView см. в рецептах Android WebView.
Указание базового каталога
На обеих платформах имеется параметр, указывающий базовый каталог для HTML-страницы. Это расположение в файловой системе устройства, которая используется для разрешения относительных ссылок на ресурсы, такие как изображения и CSS-файлы. Например, теги, например
<link rel="stylesheet" href="style.css" />
<img src="monkey.jpg" />
<script type="text/javascript" src="jscript.js">
см. следующие файлы: style.css, monkey.jpg и jscript.js. Параметр базового каталога сообщает веб-представлению, где находятся эти файлы, чтобы их можно было загрузить на страницу.
iOS
Выходные данные шаблона отображаются в iOS со следующим кодом C#:
webView.LoadHtmlString (page, NSBundle.MainBundle.BundleUrl);
Базовый каталог указывается как NSBundle.MainBundle.BundleUrl
который относится к каталогу, в котором установлено приложение. Все файлы в папке resources копируются в это расположение, например файл style.css, показанный здесь:
Действие сборки для всех статических файлов содержимого должно иметь значение BundleResource:
Android
Android также требует, чтобы базовый каталог был передан в качестве параметра, когда html-строки отображаются в веб-представлении.
webView.LoadDataWithBaseURL("file:///android_asset/", page, "text/html", "UTF-8", null);
Специальная строка file:///android_asset/ ссылается на папку ресурсов Android в приложении, показанную здесь, содержащую файл style.css .
Действие сборки для всех статических файлов содержимого должно быть AndroidAsset.
Вызов C# из HTML и JavaScript
Когда html-страница загружается в веб-представление, она обрабатывает ссылки и формы, как это было бы, если страница была загружена с сервера. Это означает, что если пользователь щелкает ссылку или отправляет форму, веб-представление попытается перейти к указанному целевому объекту.
Если ссылка связана с внешним сервером (например, google.com), веб-представление попытается загрузить внешний веб-сайт (если есть подключение к Интернету).
<a href="http://google.com/">Google</a>
Если ссылка относительна, веб-представление попытается загрузить это содержимое из базового каталога. Очевидно, что сетевое подключение не требуется для работы, так как содержимое хранится в приложении на устройстве.
<a href="somepage.html">Local content</a>
Действия формы соответствуют тому же правилу.
<form method="get" action="http://google.com/"></form>
<form method="get" action="somepage.html"></form>
Вы не собираетесь размещать веб-сервер на клиенте; однако вы можете использовать те же методы связи сервера, которые используются в современных шаблонах адаптивного проектирования для вызова служб HTTP GET и асинхронного обработки ответов путем создания JavaScript (или вызова JavaScript, уже размещенного в веб-представлении). Это позволяет легко передавать данные из HTML-кода обратно в код C#, а затем отображать результаты на HTML-странице.
IOS и Android предоставляют механизм перехвата этих событий навигации для кода приложения, чтобы код приложения может реагировать (при необходимости). Эта функция важна для создания гибридных приложений, так как она позволяет машинным кодом взаимодействовать с веб-представлением.
iOS
Событие ShouldStartLoad в веб-представлении в iOS можно переопределить, чтобы разрешить коду приложения обрабатывать запрос навигации (например, щелкнуть ссылку). Параметры метода предоставляют все сведения
bool HandleShouldStartLoad (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType) {
// return true if handled in code
// return false to let the web view follow the link
}
а затем назначьте обработчик событий:
webView.ShouldStartLoad += HandleShouldStartLoad;
Android
В Android просто подкласс WebViewClient, а затем реализуйте код для реагирования на запрос навигации.
class HybridWebViewClient : WebViewClient {
public override bool ShouldOverrideUrlLoading (WebView webView, IWebResourceRequest request) {
// return true if handled in code
// return false to let the web view follow the link
}
}
а затем задайте клиент в веб-представлении:
webView.SetWebViewClient (new HybridWebViewClient ());
Вызов JavaScript из C#
Помимо того, что веб-представление загружает новую HTML-страницу, код C# также может запускать JavaScript на текущей отображаемой странице. Все блоки кода JavaScript можно создавать с помощью строк C# и выполнять их или создавать вызовы методов к JavaScript, которые уже доступны на странице с помощью script
тегов.
Android
Создайте код JavaScript для выполнения, а затем префиксируйте его с помощью javascript:, и укажите веб-представлению загрузить следующую строку:
var js = "alert('test');";
webView.LoadUrl ("javascript:" + js);
iOS
Веб-представления iOS предоставляют метод специально для вызова JavaScript:
var js = "alert('test');";
webView.EvaluateJavascript (js);
Итоги
В этом разделе представлены функции элементов управления веб-представлениями в Android и iOS, которые позволяют создавать гибридные приложения с помощью Xamarin, в том числе:
- Возможность загрузки HTML из строк, созданных в коде,
- Возможность ссылаться на локальные файлы (CSS, JavaScript, Изображения или другие HTML-файлы)
- Возможность перехвата запросов навигации в коде C#
- Возможность вызова JavaScript из кода C#.
В следующем разделе представлен Razor, что упрощает создание HTML-кода для использования в гибридных приложениях.
Что такое Razor?
Razor — это обработчик шаблонов, который был представлен с ASP.NET MVC, изначально выполняющийся на сервере и создающий HTML для отправки веб-браузерам.
Модуль шаблонов Razor расширяет стандартный синтаксис HTML с помощью C#, чтобы можно было легко выразить макет и включить таблицы стилей CSS и JavaScript. Шаблон может ссылаться на класс Model, который может быть любым настраиваемым типом и свойствами которого можно получить доступ непосредственно из шаблона. Одним из основных преимуществ является возможность легко смешивать синтаксис HTML и C#.
Шаблоны Razor не ограничены использованием на стороне сервера, они также могут быть включены в приложения Xamarin. Использование шаблонов Razor вместе с возможностью работы с веб-представлениями программным способом позволяет создавать сложные кроссплатформенные гибридные приложения с помощью Xamarin.
Основы шаблона Razor
Файлы шаблонов Razor имеют расширение CSHTML . Их можно добавить в проект Xamarin из раздела "Шаблон текста" в диалоговом окне создания файла :
Ниже показан простой шаблон Razor ( RazorView.cshtml).
@model string
<html>
<body>
<h1>@Model</h1>
</body>
</html>
Обратите внимание на следующие отличия от обычного HTML-файла:
- Символ имеет особое значение в шаблонах Razor. Это
@
означает, что следующее выражение — C# для вычисления. @model
директива всегда отображается как первая строка файла шаблона Razor.- За
@model
директивой следует тип. В этом примере простая строка передается в шаблон, но это может быть любой пользовательский класс. - При
@Model
ссылке на шаблон он предоставляет ссылку на объект, переданный шаблону при создании (в этом примере это строка). - Интегрированная среда разработки автоматически создаст частичный класс для шаблонов (файлы с расширением CSHTML ). Этот код можно просмотреть, но его не следует редактировать. Частичный класс называется RazorView для сопоставления имени файла шаблона CSHTML. Это имя, которое используется для ссылки на шаблон в коде C#.
@using
инструкции также можно включить в начало шаблона Razor, чтобы включить дополнительные пространства имен.
Затем окончательные выходные данные HTML можно создать с помощью следующего кода C#. Обратите внимание, что модель должна быть строкой Hello World, которая будет включена в выходные данные отрисованного шаблона.
var template = new RazorView () { Model = "Hello World" };
var page = template.GenerateString ();
Ниже приведены выходные данные, отображаемые в веб-представлении в симуляторе iOS и эмуляторе Android:
Более подробный синтаксис Razor
В этом разделе мы рассмотрим базовый синтаксис Razor, который поможет вам приступить к работе с ним. Примеры в этом разделе заполняют следующий класс данными и отображают его с помощью Razor:
public class Monkey {
public string Name { get; set; }
public DateTime Birthday { get; set; }
public List<string> FavoriteFoods { get; set; }
}
Все примеры используют следующий код инициализации данных
var animal = new Monkey {
Name = "Rupert",
Birthday=new DateTime(2011, 04, 01),
FavoriteFoods = new List<string>
{"Bananas", "Banana Split", "Banana Smoothie"}
};
Отображение свойств модели
Если модель является классом со свойствами, они легко ссылаются в шаблоне Razor, как показано в этом примере шаблона:
@model Monkey
<html>
<body>
<h1>@Model.Name</h1>
<p>Birthday: @(Model.Birthday.ToString("d MMMM yyyy"))</p>
</body>
</html>
Это можно отобразить в строке с помощью следующего кода:
var template = new RazorView () { Model = animal };
var page = template.GenerateString ();
Окончательные выходные данные показаны здесь в веб-представлении в симуляторе iOS и эмуляторе Android:
Операторы C#
Более сложный C# можно включить в шаблон, например обновления свойств модели и вычисление age в этом примере:
@model Monkey
<html>
<body>
@{
Model.Name = "Rupert X. Monkey";
Model.Birthday = new DateTime(2011,3,1);
}
<h1>@Model.Name</h1>
<p>Birthday: @Model.Birthday.ToString("d MMMM yyyy")</p>
<p>Age: @(Math.Floor(DateTime.Now.Date.Subtract (Model.Birthday.Date).TotalDays/365)) years old</p>
</body>
</html>
Можно создавать сложные однострочные выражения C# (например, форматирование возраста), связав код с @()
помощью .
Несколько инструкций C# можно записать, окружив их @{}
.
Операторы If-else
Ветви кода можно выразить, @if
как показано в этом примере шаблона.
@model Monkey
<html>
<body>
<h1>@Model.Name</h1>
<p>Birthday: @(Model.Birthday.ToString("d MMMM yyyy"))</p>
<p>Age: @(Math.Floor(DateTime.Now.Date.Subtract (Model.Birthday.Date).TotalDays/365)) years old</p>
<p>Favorite Foods:</p>
@if (Model.FavoriteFoods.Count == 0) {
<p>No favorites</p>
} else {
<p>@Model.FavoriteFoods.Count favorites</p>
}
</body>
</html>
Циклы
Также можно добавить конструкции foreach
циклического цикла. @
Префикс можно использовать в переменной цикла ( @food
в данном случае) для отрисовки в HTML.
@model Monkey
<html>
<body>
<h1>@Model.Name</h1>
<p>Birthday: @Model.Birthday.ToString("d MMMM yyyy")</p>
<p>Age: @(Math.Floor(DateTime.Now.Date.Subtract (Model.Birthday.Date).TotalDays/365)) years old</p>
<p>Favorite Foods:</p>
@if (Model.FavoriteFoods.Count == 0) {
<p>No favorites</p>
} else {
<ul>
@foreach (var food in @Model.FavoriteFoods) {
<li>@food</li>
}
</ul>
}
</body>
</html>
Выходные данные приведенного выше шаблона отображаются в симуляторе iOS и эмуляторе Android:
В этом разделе рассматриваются основы использования шаблонов Razor для отображения простых представлений только для чтения. В следующем разделе объясняется, как создавать более полные приложения с помощью Razor, которые могут принимать входные данные пользователя и взаимодействовать между JavaScript в представлении HTML и C#.
Использование шаблонов Razor с Xamarin
В этом разделе объясняется, как создать собственное гибридное приложение с помощью шаблонов решений в Visual Studio для Mac. В окне "Создание файла>" > доступны три шаблона:
- Приложение Android App > Android > WebView
- Приложение iOS > App > WebView
- проект MVC ASP.NET
Окно нового решения выглядит так для проектов i Телефон и Android — описание решения справа выделяет поддержку обработчика шаблонов Razor.
Обратите внимание, что вы можете легко добавить шаблон Razor cshtml в любой существующий проект Xamarin, не обязательно использовать эти шаблоны решений. Для проектов iOS не требуется раскадровка для использования Razor; Просто добавьте элемент управления UIWebView в любое представление программным способом, и вы можете отобразить шаблоны Razor целиком в коде C#.
Ниже показаны содержимое решения шаблона по умолчанию для проектов i Телефон и Android:
Шаблоны предоставляют инфраструктуру приложений, готовую к работе, для загрузки шаблона Razor с объектом модели данных, обработки ввода пользователем и обратного взаимодействия с пользователем с помощью JavaScript.
Важными компонентами решения являются:
- Статическое содержимое , например файл style.css .
- Файлы шаблонов Razor .cshtml, такие как RazorView.cshtml .
- Классы моделей, на которые ссылаются шаблоны Razor, например ExampleModel.cs .
- Класс, зависящий от платформы, который создает веб-представление и отрисовывает шаблон, например
MainActivity
в Android иiPhoneHybridViewController
iOS.
В следующем разделе объясняется, как работают проекты.
Статическое содержимое
Статическое содержимое включает таблицы стилей CSS, изображения, файлы JavaScript или другое содержимое, которое может быть связано с HTML-файлом, отображаемым в веб-представлении.
Проекты шаблонов включают минимальную таблицу стилей для демонстрации включения статического содержимого в гибридное приложение. Таблица стилей CSS ссылается на шаблон следующим образом:
<link rel="stylesheet" href="style.css" />
Вы можете добавить любую нужную таблицу стилей и файлы JavaScript, включая платформы, такие как JQuery.
Шаблоны cshtml Razor
Шаблон содержит CSHTML-файл Razor, который содержит предварительно написанный код для обмена данными между HTML/JavaScript и C#. Это позволит создавать сложные гибридные приложения, которые не только отображают данные только для чтения из модели, но и принимают входные данные пользователя в HTML и передают его обратно в код C# для обработки или хранения.
Отрисовка шаблона
GenerateString
Вызов шаблона отрисовывает HTML-код, готовый к отображению в веб-представлении. Если шаблон использует модель, перед отрисовкой его следует предоставить. На этой схеме показано, как работает отрисовка , а не то, что статические ресурсы разрешаются веб-представлением во время выполнения, используя предоставленный базовый каталог для поиска указанных файлов.
Вызов кода C# из шаблона
Обмен данными из отрисованного веб-представления обратно в C# выполняется путем задания URL-адреса веб-представления, а затем перехвата запроса в C# для обработки собственного запроса без перезагрузки веб-представления.
Пример можно увидеть в том, как обрабатывается кнопка RazorView. Кнопка имеет следующий HTML-код:
<input type="button" name="UpdateLabel" value="Click" onclick="InvokeCSharpWithFormValues(this)" />
Функция InvokeCSharpWithFormValues
JavaScript считывает все значения из HTML-формы и задает location.href
для веб-представления:
location.href = "hybrid:" + elm.name + "?" + qs;
При попытке перейти к веб-представлению по URL-адресу с настраиваемой схемой (например. hybrid:
)
hybrid:UpdateLabel?textbox=SomeValue&UpdateLabel=Click
Когда собственное веб-представление обрабатывает этот запрос навигации, у нас есть возможность перехватывать его. В iOS это делается путем обработки события HandleShouldStartLoad UIWebView. В Android мы просто подкласс webViewClient, используемый в форме, и переопределяем ShouldOverrideUrlLoading.
Внутренние элементы этих двух перехватчиков навигации по сути одинаковы.
Во-первых, проверка URL-адрес, который веб-представление пытается загрузить, и если он не начинается с пользовательской схемы (hybrid:
), разрешает навигацию выполняться как обычно.
Для пользовательской схемы URL-адресов все в URL-адресе между схемой и "?" — это имя метода для обработки (в данном случае —UpdateLabel). Все в строке запроса будет рассматриваться как параметры вызова метода:
var resources = url.Substring(scheme.Length).Split('?');
var method = resources [0];
var parameters = System.Web.HttpUtility.ParseQueryString(resources[1]);
UpdateLabel
В этом примере выполняется минимальная обработка строк в параметре текстового поля (предустановка "C# говорит" в строке), а затем возвращается к веб-представлению.
После обработки URL-адреса метод прерывает навигацию, чтобы веб-представление не пыталось завершить переход по пользовательскому URL-адресу.
Управление шаблоном из C#
Взаимодействие с отрисованным веб-представлением HTML из C# выполняется путем вызова JavaScript в веб-представлении. В iOS это делается путем вызова EvaluateJavascript
UIWebView:
webView.EvaluateJavascript (js);
В Android JavaScript можно вызвать в веб-представлении, загрузив JavaScript в качестве URL-адреса с помощью "javascript:"
схемы URL-адресов:
webView.LoadUrl ("javascript:" + js);
Создание приложения действительно гибридной
Эти шаблоны не используют собственные элементы управления на каждой платформе— весь экран заполняется одним веб-представлением.
HTML может быть отлично подходит для прототипа, и отображение типов вещей, которые интернет лучше всего использовать, например форматированный текст и адаптивный макет. Однако не все задачи подходят для HTML и JavaScript— прокрутка длинных списков данных, например, лучше работает с помощью собственных элементов управления пользовательского интерфейса (например, UITableView в iOS или ListView на Android).
Веб-представления в шаблоне можно легко дополнить элементами управления, зависящими от платформы, — просто изменить MainStoryboard.storyboard с помощью Xcode на компьютере Mac или Resources/layout/Main.axml в Android.
Пример RazorTodo
Репозиторий RazorTodo содержит два отдельных решения для отображения различий между полностью html-приложением и приложением, которое объединяет HTML с собственными элементами управления:
- RazorTodo — полностью управляемое HTML-приложение с помощью шаблонов Razor.
- RazorNativeTodo — использует собственные элементы управления представлением списка для iOS и Android, но отображает экран редактирования с помощью HTML и Razor.
Эти приложения Xamarin работают как в iOS, так и в Android, используя переносимые библиотеки классов (PCLs) для совместного использования общего кода, например классов баз данных и моделей. Шаблоны Razor .cshtml также можно включить в PCL, чтобы они легко совместно используются на разных платформах.
Оба примера приложений включают api общего доступа к Twitter и api преобразования текста в речь из собственной платформы, демонстрируя, что гибридные приложения с Xamarin по-прежнему имеют доступ ко всем базовым функциям из представлений на основе шаблонов HTML Razor.
Приложение RazorTodo использует шаблоны Razor HTML для списка и редактирования представлений. Это означает, что приложение можно создать почти полностью в общей переносимой библиотеке классов (включая базы данных и шаблоны Razor .cshtml ). На снимках экрана ниже показаны приложения iOS и Android.
Приложение RazorNativeTodo использует шаблон Razor HTML для представления редактирования, но реализует собственный список прокрутки на каждой платформе. Это обеспечивает ряд преимуществ, в том числе:
- Производительность — собственные элементы управления прокруткой используют виртуализацию, чтобы обеспечить быструю, плавную прокрутку даже с очень длинными списками данных.
- Собственный интерфейс — элементы пользовательского интерфейса для конкретной платформы легко включены, такие как поддержка индекса быстрого прокрутки в iOS и Android.
Ключевым преимуществом создания гибридных приложений с помощью Xamarin является то, что вы можете начать с полного пользовательского интерфейса на основе HTML (например, первого примера), а затем добавить функциональные возможности для конкретной платформы при необходимости (как показано во втором примере). Экраны собственного списка и экраны редактирования HTML Razor в iOS и Android показаны ниже.
Итоги
В этой статье описаны функции элементов управления веб-представлениями, доступных в iOS и Android, которые упрощают создание гибридных приложений.
Затем он обсудил подсистему шаблонов Razor и синтаксис, который можно использовать для создания HTML в приложениях Xamarin с помощью.файлы шаблонов cshtml Razor. В нем также описаны шаблоны решений Visual Studio для Mac, которые позволяют быстро приступить к созданию гибридных приложений с помощью Xamarin.
Наконец, он представил примеры RazorTodo, демонстрирующие объединение веб-представлений с собственными пользовательскими интерфейсами и API.