Привязываемые макеты в Xamarin.Forms
Привязываемые макеты позволяют любому классу макета, наследуемому из Layout<T>
класса, создавать его содержимое путем привязки к коллекции элементов, при этом параметром можно задать внешний вид каждого элемента.DataTemplate
Привязываемые макеты предоставляются классом BindableLayout
, который предоставляет следующие присоединенные свойства:
ItemsSource
— указывает коллекцию элементов, отображаемыхIEnumerable
макетом.ItemTemplate
— задаетDataTemplate
применение к каждому элементу в коллекции элементов, отображаемых макетом.ItemTemplateSelector
— указываетDataTemplateSelector
, что будет использоваться для выбораDataTemplate
элемента во время выполнения.
Примечание.
Свойство ItemTemplate
имеет приоритет, если заданы оба ItemTemplate
ItemTemplateSelector
свойства.
Кроме того, BindableLayout
класс предоставляет следующие привязываемые свойства:
EmptyView
— указываетstring
или представление, которое будет отображаться, еслиItemsSource
свойство равноnull
или когда коллекция, указаннаяItemsSource
свойствомnull
, или пуста. Значение по умолчанию —null
.EmptyViewTemplate
— задаетDataTemplate
значение, которое будет отображаться, еслиItemsSource
свойство равноnull
или когда коллекция, указаннаяItemsSource
свойством, илиnull
пуста. Значение по умолчанию —null
.
Примечание.
Свойство EmptyViewTemplate
имеет приоритет, если заданы оба EmptyView
EmptyViewTemplate
свойства.
Все эти свойства могут быть присоединены к AbsoluteLayout
классам , Grid
FlexLayout
RelativeLayout
и StackLayout
классам, производным от Layout<T>
класса.
Класс Layout<T>
предоставляет Children
коллекцию, к которой добавляются дочерние элементы макета. BindableLayout.ItemsSource
Если свойству присвоено значение коллекции элементов и присоединено к Layout<T>
производному классу, каждый элемент в коллекции добавляется в Layout<T>.Children
коллекцию для отображения макетом. Затем производный Layout<T>
класс обновляет дочерние представления при изменении базовой коллекции. Дополнительные сведения о цикле макета Xamarin.Forms см. в разделе "Создание пользовательского макета".
Привязываемые макеты следует использовать только в том случае, если коллекция элементов для отображения невелика, а прокрутка и выделение не требуются. Хотя прокрутка может быть предоставлена путем упаковки привязываемого макета в a ScrollView
, это не рекомендуется, так как привязываемые макеты не имеют виртуализации пользовательского интерфейса. Если требуется прокрутка, необходимо использовать прокручиваемое представление, включающее виртуализацию пользовательского интерфейса, например ListView
или CollectionView
. Сбой в наблюдении за этой рекомендацией может привести к проблемам с производительностью.
Внимание
Хотя технически можно подключить привязываемый макет к любому классу макета, наследуемому от Layout<T>
класса, это не всегда удобно сделать, особенно для AbsoluteLayout
классов и Grid
RelativeLayout
классов. Например, рассмотрим сценарий отображения коллекции данных в Grid
привязываемом макете, где каждый элемент в коллекции является объектом, содержащим несколько свойств. Каждая строка в Grid
коллекции должна отображать объект из коллекции с каждым столбцом в Grid
отображении одного из свойств объекта. DataTemplate
Так как для привязываемого макета может содержаться только один объект, это необходимо для того, чтобы этот объект был классом макета, содержащим несколько представлений, каждый из которых отображает одно из свойств объекта в определенном Grid
столбце. Хотя этот сценарий можно реализовать с привязываемыми макетами, он приводит к Grid
родительскому элементу, содержашему дочерний Grid
элемент в связанной коллекции, что является очень неэффективным и проблемным использованием макета Grid
.
Заполнение привязываемого макета данными
Привязываемый макет заполняется данными, задав его ItemsSource
свойство любой коллекции, реализующей IEnumerable
и присоединяя ее к производном классу Layout<T>
:
<Grid BindableLayout.ItemsSource="{Binding Items}" />
Эквивалентный код на C# выглядит так:
IEnumerable<string> items = ...;
var grid = new Grid();
BindableLayout.SetItemsSource(grid, items);
BindableLayout.ItemsSource
Если присоединенное свойство задано в макете, но BindableLayout.ItemTemplate
присоединенное свойство не задано, каждый элемент в IEnumerable
коллекции будет отображаться Label
классом, созданным классомBindableLayout
.
Определение внешнего вида элемента
Внешний вид каждого элемента в привязываемом макете можно определить, задав BindableLayout.ItemTemplate
присоединенное свойство следующим DataTemplate
образом:
<StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"
Orientation="Horizontal"
...>
<BindableLayout.ItemTemplate>
<DataTemplate>
<controls:CircleImage Source="{Binding}"
Aspect="AspectFill"
WidthRequest="44"
HeightRequest="44"
... />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
Эквивалентный код на C# выглядит так:
DataTemplate circleImageTemplate = ...;
var stackLayout = new StackLayout();
BindableLayout.SetItemsSource(stackLayout, viewModel.User.TopFollowers);
BindableLayout.SetItemTemplate(stackLayout, circleImageTemplate);
В этом примере каждый элемент в TopFollowers
коллекции будет отображаться представлениемCircleImage
, определенным в :DataTemplate
Дополнительные сведения о шаблонах данных см. в разделе Общие сведения о шаблонах данныхXamarin.Forms.
Выбор внешнего вида элемента во время выполнения
Внешний вид каждого элемента в привязываемом макете можно выбрать во время выполнения на основе значения элемента, задав BindableLayout.ItemTemplateSelector
присоединенное свойство следующим DataTemplateSelector
образом:
<FlexLayout BindableLayout.ItemsSource="{Binding User.FavoriteTech}"
BindableLayout.ItemTemplateSelector="{StaticResource TechItemTemplateSelector}"
... />
Эквивалентный код на C# выглядит так:
DataTemplateSelector dataTemplateSelector = new TechItemTemplateSelector { ... };
var flexLayout = new FlexLayout();
BindableLayout.SetItemsSource(flexLayout, viewModel.User.FavoriteTech);
BindableLayout.SetItemTemplateSelector(flexLayout, dataTemplateSelector);
Используемый DataTemplateSelector
в примере приложения показан в следующем примере:
public class TechItemTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; }
public DataTemplate XamarinFormsTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return (string)item == "Xamarin.Forms" ? XamarinFormsTemplate : DefaultTemplate;
}
}
Класс TechItemTemplateSelector
определяет DefaultTemplate
и XamarinFormsTemplate
DataTemplate
свойства, которые задаются различными шаблонами данных. Метод OnSelectTemplate
возвращает XamarinFormsTemplate
элемент , который отображает элемент в темно-красном цвете с сердцем рядом с ним, когда элемент равен "Xamarin.Forms". Если элемент не равен "Xamarin.Forms", OnSelectTemplate
метод возвращает DefaultTemplate
элемент, который отображает элемент с использованием цвета по умолчанию:Label
Дополнительные сведения о селекторах шаблонов данных см. в разделе "Создание Xamarin.Forms объекта DataTemplateSelector".
Отображение строки при недоступности данных
Свойство EmptyView
может быть задано строкой, которая будет отображаться Label
в случае, если ItemsSource
свойство имеет null
значение, или когда коллекция, указанная ItemsSource
свойством null
, или пуста. В следующем коде XAML показан пример этого сценария:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}"
BindableLayout.EmptyView="No achievements">
...
</StackLayout>
Результатом является то, что при сборе null
привязанных к данным строке EmptyView
отображается значение свойства:
Отображение представлений при недоступности данных
Свойство EmptyView
может быть задано в представлении, которое будет отображаться, если ItemsSource
свойство равно null
или когда коллекция, указанная ItemsSource
свойством null
, или пуста. Это может быть одно представление или представление, содержащее несколько дочерних представлений. В следующем примере XAML показано EmptyView
свойство, заданное для представления, содержащего несколько дочерних представлений:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
<BindableLayout.EmptyView>
<StackLayout>
<Label Text="None."
FontAttributes="Italic"
FontSize="{StaticResource smallTextSize}" />
<Label Text="Try harder and return later?"
FontAttributes="Italic"
FontSize="{StaticResource smallTextSize}" />
</StackLayout>
</BindableLayout.EmptyView>
...
</StackLayout>
Результатом является то, что при отображении коллекции null
StackLayout
привязанных к данным представлений и его дочерних представлений.
Аналогичным образом EmptyViewTemplate
можно задать DataTemplate
значение , которое будет отображаться, если ItemsSource
свойство равно null
или когда коллекция, указанная ItemsSource
свойством, или null
пуста. Может DataTemplate
содержать одно представление или представление, содержащее несколько дочерних представлений. Кроме того, BindingContext
EmptyViewTemplate
наследуется от BindingContext
объекта BindableLayout
. В следующем примере XAML показан набор EmptyViewTemplate
свойств, DataTemplate
содержащий одно представление:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
<BindableLayout.EmptyViewTemplate>
<DataTemplate>
<Label Text="{Binding Source={x:Reference usernameLabel}, Path=Text, StringFormat='{0} has no achievements.'}" />
</DataTemplate>
</BindableLayout.EmptyViewTemplate>
...
</StackLayout>
Результатом является то, что при сборе null
Label
DataTemplate
привязанных к данным данных отображается в ней:
Примечание.
Свойство EmptyViewTemplate
не может быть задано через объект DataTemplateSelector
.
Выбор EmptyView во время выполнения
Представления, которые будут отображаться как EmptyView
недоступные данные, можно определить как ContentView
объекты в объекте ResourceDictionary
. Затем EmptyView
свойство может быть задано на основе определенной ContentView
бизнес-логики во время выполнения. В следующем коде XAML показан пример этого сценария:
<ContentPage ...>
<ContentPage.Resources>
...
<ContentView x:Key="BasicEmptyView">
<StackLayout>
<Label Text="No achievements."
FontSize="14" />
</StackLayout>
</ContentView>
<ContentView x:Key="AdvancedEmptyView">
<StackLayout>
<Label Text="None."
FontAttributes="Italic"
FontSize="14" />
<Label Text="Try harder and return later?"
FontAttributes="Italic"
FontSize="14" />
</StackLayout>
</ContentView>
</ContentPage.Resources>
<StackLayout>
...
<Switch Toggled="OnEmptyViewSwitchToggled" />
<StackLayout x:Name="stackLayout"
BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
...
</StackLayout>
</StackLayout>
</ContentPage>
XAML определяет два ContentView
объекта на уровне ResourceDictionary
страницы с Switch
объектом, определяющим, какой ContentView
объект будет задан в качестве EmptyView
значения свойства. Switch
При переключение OnEmptyViewSwitchToggled
обработчик событий выполняет ToggleEmptyView
метод:
void ToggleEmptyView(bool isToggled)
{
object view = isToggled ? Resources["BasicEmptyView"] : Resources["AdvancedEmptyView"];
BindableLayout.SetEmptyView(stackLayout, view);
}
Метод ToggleEmptyView
задает EmptyView
свойство stackLayout
объекта одному из двух ContentView
объектов, хранящихся в объекте ResourceDictionary
, на основе значения Switch.IsToggled
свойства. Затем, когда коллекция null
привязанных к данным данных, ContentView
объект, заданный в качестве EmptyView
свойства, отображается: