Скомпилированные привязки Xamarin.Forms
Скомпилированные привязки разрешаются быстрее классических, что позволяет повысить производительность привязки данных в приложениях Xamarin.Forms.
С привязками данных связаны две основные проблемы:
- Не выполняется проверка выражений привязки во время компиляции. Вместо этого привязки разрешаются во время выполнения. Таким образом, недопустимые привязки проявляются только во время выполнения в виде нарушений в поведении приложения или сообщений об ошибке.
- Затрачиваются избыточные ресурсы. Привязки разрешаются во время выполнения с использованием проверки объектов общего назначения (отражение), причем объем затрачиваемых на это ресурсов зависит от платформы.
Использование скомпилированных привязок позволяет оптимизировать производительность привязки данных в приложениях Xamarin.Forms за счет разрешения выражений привязки во время компиляции, а не во время выполнения. Кроме того, такая проверка выражений привязки во время компиляции позволяет повысить эффективность устранения неполадок, поскольку недопустимые привязки выявляются как ошибки построения.
Процесс использования скомпилированных привязок выглядит следующим образом:
- Включите компиляцию XAML. Дополнительные сведения о компиляции XAML см. в статье Компиляция XAML.
- Присвойте атрибуту
x:DataType
объектаVisualElement
тип объекта, к которому будут привязываться объектVisualElement
и его дочерние объекты.
Примечание.
Атрибут x:DataType
рекомендуется задавать на том же уровне иерархии представления, на котором задается BindingContext
. Однако этот атрибут может быть переопределен в любом месте иерархии представлений.
Чтобы использовать скомпилированные привязки, атрибуту x:DataType
необходимо назначить строковый литерал или тип, использующий расширение разметки x:Type
. Во время компиляции XAML любые недопустимые выражения привязки будут выявляться как ошибки построения. Тем не менее компилятор XAML будет возвращать ошибку построения только для первого обнаруженного недопустимого выражения привязки. Любые допустимые выражения привязки, которые определены для объекта VisualElement
или его дочерних объектов, будут скомпилированы независимо от того, задается ли BindingContext
в XAML или в коде. При компиляции выражения привязки создается скомпилированный код, который получает значение из свойства источника и присваивает его свойству адресата, который указан в разметке. Кроме того, в зависимости от выражения привязки созданный код может наблюдать изменения в значении свойства источника и обновляет свойство адресата, а также может отправлять изменения из адресата обратно в источник.
Внимание
Скомпилированные привязки на данный момент отключены для любых выражений привязки, которые определяют свойство Source
. Это связано с тем, что свойство Source
всегда задается с использованием расширения разметки x:Reference
, которое не может быть разрешено во время компиляции.
Использование скомпилированных привязок
На странице скомпилированного средства выбора цвета демонстрируется использование скомпилированных привязок между представлениями Xamarin.Forms и свойствами модели представления:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorSelectorPage"
Title="Compiled Color Selector">
...
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
... />
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>
Корневое представление StackLayout
создает экземпляр HslColorViewModel
и инициализирует свойство Color
в тегах элемента свойства для свойство BindingContext
. Это корневое представление StackLayout
также определяет атрибут x:DataType
как тип модели представления, указывая, что любое выражение привязки в иерархии корневого представления StackLayout
будет компилироваться. Это можно проверить, изменив любое выражение привязки так, чтобы оно было привязано к несуществующему свойству модели представления, что приведет к ошибке сборки. Хотя в этом примере атрибуту x:DataType
присваивается строковый литерал, для него также можно задать тип с расширением разметки x:Type
. Дополнительные сведения о расширении разметки x:Type
см. в разделе Расширение разметки x:Type.
Внимание
Обратите внимание, что атрибут x:DataType
может быть переопределен в любом месте иерархии представления.
Элементы BoxView
, Label
и представления Slider
наследуют контекст привязки из представления StackLayout
. Эти представления являются целевыми объектами привязки, которые ссылаются на свойства источника в модели представления. Для свойств BoxView.Color
и Label.Text
привязки данных имеют режим OneWay
: свойства в представлении задаются по свойствам в модели представления. Тем не менее свойство Slider.Value
использует привязку TwoWay
. Поэтому каждый объект Slider
задается из модели представления, а модель представления задается из каждого объекта Slider
.
При первом запуске приложения элементы BoxView
, Label
и Slider
получают значения из модели представления в зависимости от первоначального свойства Color
, заданного при создании экземпляра модели представления. Эти действия показаны на следующих снимках экрана:
При выполнении действий с ползунками элементы BoxView
и Label
соответствующим образом обновляются.
Дополнительные сведения о средстве выбора цвета см. в статье Уведомления об изменении свойства и модели представления.
Использование скомпилированных привязок в DataTemplate
Привязки в DataTemplate
интерпретируются в контексте объекта, к которому применяется шаблон. Таким образом, при использовании скомпилированных привязок в DataTemplate
объект DataTemplate
должен объявлять тип своего объекта данных с использованием атрибута x:DataType
.
На странице скомпилированного списка цветов демонстрируется использование скомпилированных привязок в DataTemplate
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorListPage"
Title="Compiled Color List">
<Grid>
...
<ListView x:Name="colorListView"
ItemsSource="{x:Static local:NamedColor.All}"
... >
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:NamedColor">
<ViewCell>
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
... />
<Label Text="{Binding FriendlyName}"
... />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- The BoxView doesn't use compiled bindings -->
<BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
... />
</Grid>
</ContentPage>
Свойство ListView.ItemsSource
получает статическое свойство NamedColor.All
. Класс NamedColor
использует отражение .NET для перечисления всех открытых статических полей в структуре Color
и их хранения с именами в коллекции, доступной из статического свойства All
. Таким образом, объект ListView
заполняется экземплярами NamedColor
. Для каждого элемента в ListView
в качестве контекста привязки для элемента задается объект NamedColor
. Элементы BoxView
и Label
в объекте ViewCell
привязываются к свойствам NamedColor
.
Обратите внимание, что DataTemplate
определяет атрибут x:DataType
как тип NamedColor
, указывая, что любое выражение привязки в иерархии представления DataTemplate
будет компилироваться. Это можно проверить, изменив любое выражение привязки так, чтобы оно было привязано к несуществующему свойству NamedColor
, что приведет к ошибке построения. Хотя в этом примере атрибуту x:DataType
присваивается строковый литерал, для него также можно задать тип с расширением разметки x:Type
. Дополнительные сведения о расширении разметки x:Type
см. в разделе Расширение разметки x:Type.
При первом запуске приложения объект ListView
заполняется экземплярами NamedColor
. При выборе элемента в объекте ListView
свойству BoxView.Color
присваивается цвет элемента, выбранного в ListView
:
При выборе других элементов в ListView
обновляется цвет элемента BoxView
.
Объединение скомпилированных привязок с классическими привязками
Выражения привязки компилируются только для иерархии представления, в которой определен атрибут x:DataType
. И наоборот, любые представления в иерархии, в которой не определен атрибут x:DataType
, будут использовать классические привязки. Таким образом, на одной странице могут объединяться скомпилированные и классические привязки. Например, в предыдущем разделе представления в DataTemplate
используют скомпилированные привязки, а элемент BoxView
, которому присваивается выбранный в ListView
цвет, не использует их.
Таким образом, при тщательной проработке структуры атрибутов x:DataType
на одной странице могут одновременно использоваться скомпилированные и классические привязки. Кроме того, атрибут x:DataType
может в любом месте иерархии быть переопределен как null
с использованием расширения разметки x:Null
. Это указывает, что любые выражения привязки в иерархии этого представления будут использовать классические привязки. Этот подход демонстрируется на странице смешанных привязок:
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />
<StackLayout x:DataType="{x:Null}"
Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
Корневое представление StackLayout
задает атрибут x:DataType
как тип HslColorViewModel
, указывая, что любое выражение привязки в иерархии корневого представления StackLayout
будет компилироваться. Тем не менее внутреннее представление StackLayout
переопределяет атрибут x:DataType
как null
с использованием расширения разметки x:Null
. Таким образом, в выражениях привязки внутреннего представления StackLayout
используются классические привязки. Скомпилированные привязки используются только элементом BoxView
в иерархии корневого представления StackLayout
.
Дополнительные сведения о расширении разметки x:Null
см. в статье Расширение разметки x:Null.
Производительность
Использование скомпилированных привязок позволяет повысить производительность привязки данных с учетом различных факторов. Результаты модульного тестирования демонстрируют следующее:
- Скомпилированные привязки, использующие уведомление об изменении свойства (то есть привязки в режиме
OneWay
,OneWayToSource
илиTwoWay
), разрешаются примерно в 8 раз быстрее относительно классических привязок. - Скомпилированные привязки, не использующие уведомление об изменении свойства (то есть привязки в режиме
OneTime
), разрешаются примерно в 20 раз быстрее относительно классических привязок. - Задание
BindingContext
для скомпилированных привязок, использующих уведомление об изменении свойства (то есть для привязок в режимеOneWay
,OneWayToSource
илиTwoWay
), выполняется примерно в 5 раз быстрее, чем заданиеBindingContext
для классических привязок. - Задание
BindingContext
для скомпилированных привязок, не использующих уведомление об изменении свойства (то есть для привязок в режимеOneTime
), выполняется примерно в 7 раз быстрее, чем заданиеBindingContext
для классических привязок.
Выигрыш в производительности может быть еще более весомым на мобильных устройствах в зависимости от используемой платформы, версии операционной системы и типа устройства, на котором выполняется приложение.