Собственные представления в XAML
Собственные представления из iOS, Android и универсальная платформа Windows можно напрямую ссылаться на Xamarin.Forms файлы XAML. Свойства и обработчики событий можно задать в собственных представлениях, и они могут взаимодействовать с представлениями Xamarin.Forms . В этой статье показано, как использовать собственные представления из Xamarin.Forms XAML-файлов.
Чтобы внедрить собственное представление в Xamarin.Forms XAML-файл:
xmlns
Добавьте объявление пространства имен в XAML-файле для пространства имен, содержащего собственное представление.- Создайте экземпляр собственного представления в XAML-файле.
Внимание
Скомпилированный КОД XAML должен быть отключен для всех страниц XAML, использующих собственные представления. Это можно сделать, декорируя класс code-behind для страницы XAML атрибутом [XamlCompilation(XamlCompilationOptions.Skip)]
. Дополнительные сведения о компиляции XAML см. в Xamarin.Formsразделе "Компиляция XAML".
Чтобы ссылаться на собственное представление из файла программной части, необходимо использовать проект общего ресурса (SAP) и упаковать код для конкретной платформы с помощью директив условной компиляции. Дополнительные сведения см. в статье "Ссылки на собственные представления из кода".
Использование собственных представлений
В следующем примере кода демонстрируется использование собственных представлений для каждой Xamarin.FormsContentPage
платформы в :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
x:Class="NativeViews.NativeViewDemo">
<StackLayout Margin="20">
<ios:UILabel Text="Hello World" TextColor="{x:Static ios:UIColor.Red}" View.HorizontalOptions="Start" />
<androidWidget:TextView Text="Hello World" x:Arguments="{x:Static androidLocal:MainActivity.Instance}" />
<win:TextBlock Text="Hello World" />
</StackLayout>
</ContentPage>
Кроме того, targetPlatform
необходимо указать clr-namespace
assembly
и для собственного пространства имен представления. Это значение должно иметь значение iOS
, Android
, UWP
Windows
(что эквивалентно UWP
macOS
), , , GTK
, Tizen
или WPF
. Во время выполнения средство синтаксического анализа XAML будет игнорировать все префиксы пространства имен XML, имеющие не соответствующую targetPlatform
платформе, на которой работает приложение.
Каждое объявление пространства имен можно использовать для ссылки на любой класс или структуру из указанного пространства имен. Например, ios
объявление пространства имен можно использовать для ссылки на любой класс или структуру из пространства имен iOS UIKit
. Свойства собственного представления можно задать с помощью XAML, но свойства и типы объектов должны соответствовать. Например, UILabel.TextColor
для свойства задано UIColor.Red
использование x:Static
расширения разметки и ios
пространства имен.
Привязываемые свойства и присоединенные привязываемые свойства также можно задать в собственных представлениях с помощью синтаксиса Class.BindableProperty="value"
. Каждое собственное представление упаковывается в экземпляр для конкретной NativeViewWrapper
платформы, который является производным от Xamarin.Forms.View
класса. Задание привязываемого свойства или присоединенного привязываемого свойства в собственном представлении передает значение свойства оболочке. Например, по центру горизонтального макета можно указать, задав View.HorizontalOptions="Center"
в собственном представлении.
Примечание.
Обратите внимание, что стили нельзя использовать с собственными представлениями, так как стили могут использовать только целевые свойства, поддерживаемые объектами BindableProperty
.
Конструкторы мини-приложений Android обычно требуют объекта Android Context
в качестве аргумента, и это можно сделать доступным через статическое свойство в MainActivity
классе. Поэтому при создании мини-приложения Android в XAML Context
объект обычно должен передаваться конструктору мини-приложения с помощью x:Arguments
атрибута с расширением x:Static
разметки. Дополнительные сведения см. в разделе "Передача аргументов в собственные представления".
Примечание.
Обратите внимание, что именование собственного представления x:Name
невозможно либо в проекте библиотеки .NET Standard, либо в проекте общего ресурса (SAP). Это приведет к созданию переменной собственного типа, что приведет к ошибке компиляции. Однако собственные представления можно упаковать в ContentView
экземпляры и получить в файле программной части, если используется SAP. Дополнительные сведения см. в разделе "Машинное представление" из кода.
Собственные привязки
Привязка данных используется для синхронизации пользовательского интерфейса с источником данных и упрощает Xamarin.Forms отображение и взаимодействие приложения с данными. При условии, что исходный объект реализует INotifyPropertyChanged
интерфейс, изменения в исходном объекте автоматически отправляются в целевой объект платформой привязки, а изменения в целевом объекте при необходимости могут быть отправлены в исходный объект.
Свойства собственных представлений также могут использовать привязку данных. В следующем примере кода демонстрируется привязка данных с помощью свойств собственных представлений:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:NativeSwitch"
x:Class="NativeSwitch.NativeSwitchPage">
<StackLayout Margin="20">
<Label Text="Native Views Demo" FontAttributes="Bold" HorizontalOptions="Center" />
<Entry Placeholder="This Entry is bound to the native switch" IsEnabled="{Binding IsSwitchOn}" />
<ios:UISwitch On="{Binding Path=IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=ValueChanged}"
OnTintColor="{x:Static ios:UIColor.Red}"
ThumbTintColor="{x:Static ios:UIColor.Blue}" />
<androidWidget:Switch x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Checked="{Binding Path=IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=CheckedChange}"
Text="Enable Entry?" />
<win:ToggleSwitch Header="Enable Entry?"
OffContent="No"
OnContent="Yes"
IsOn="{Binding IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=Toggled}" />
</StackLayout>
</ContentPage>
Страница содержит свойство, свойство которого привязывается Entry
к свойствуNativeSwitchPageViewModel.IsSwitchOn
.IsEnabled
На BindingContext
странице устанавливается новый экземпляр NativeSwitchPageViewModel
класса в файле кода программной части с классом ViewModel, реализующим INotifyPropertyChanged
интерфейс.
Страница также содержит собственный коммутатор для каждой платформы. Каждый собственный коммутатор использует привязку TwoWay
для обновления значения NativeSwitchPageViewModel.IsSwitchOn
свойства. Поэтому при отключении Entry
выключения отключена и включена функция включения переключателя Entry
. На следующих снимках экрана показана эта функция на каждой платформе:
Двусторонняя привязка поддерживается автоматически, если собственное свойство реализует INotifyPropertyChanged
или поддерживает наблюдение за ключом (KVO) в iOS или используется DependencyProperty
в UWP. Однако многие собственные представления не поддерживают уведомление об изменении свойств. Для этих представлений можно указать UpdateSourceEventName
значение свойства в рамках выражения привязки. Это свойство должно иметь имя события в собственном представлении, которое сигнализирует об изменении целевого свойства. Затем, когда изменяется значение собственного коммутатора, класс уведомляется о том, Binding
что пользователь изменил значение коммутатора, а NativeSwitchPageViewModel.IsSwitchOn
значение свойства обновляется.
Передача аргументов в собственные представления
Аргументы конструктора можно передать в собственные представления с помощью атрибута x:Arguments
с расширением x:Static
разметки. Кроме того, методы фабрики собственных представлений (public static
методы, возвращающие объекты или значения того же типа, что и класс или структура, определяющие методы), могут вызываться путем указания имени метода с помощью атрибута и его аргументов с помощью x:FactoryMethod
атрибута x:Arguments
.
В следующем примере кода показаны оба метода:
<ContentPage ...
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidGraphics="clr-namespace:Android.Graphics;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winMedia="clr-namespace:Windows.UI.Xaml.Media;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winText="clr-namespace:Windows.UI.Text;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winui="clr-namespace:Windows.UI;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows">
...
<ios:UILabel Text="Simple Native Color Picker" View.HorizontalOptions="Center">
<ios:UILabel.Font>
<ios:UIFont x:FactoryMethod="FromName">
<x:Arguments>
<x:String>Papyrus</x:String>
<x:Single>24</x:Single>
</x:Arguments>
</ios:UIFont>
</ios:UILabel.Font>
</ios:UILabel>
<androidWidget:TextView x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Simple Native Color Picker"
TextSize="24"
View.HorizontalOptions="Center">
<androidWidget:TextView.Typeface>
<androidGraphics:Typeface x:FactoryMethod="Create">
<x:Arguments>
<x:String>cursive</x:String>
<androidGraphics:TypefaceStyle>Normal</androidGraphics:TypefaceStyle>
</x:Arguments>
</androidGraphics:Typeface>
</androidWidget:TextView.Typeface>
</androidWidget:TextView>
<winControls:TextBlock Text="Simple Native Color Picker"
FontSize="20"
FontStyle="{x:Static winText:FontStyle.Italic}"
View.HorizontalOptions="Center">
<winControls:TextBlock.FontFamily>
<winMedia:FontFamily>
<x:Arguments>
<x:String>Georgia</x:String>
</x:Arguments>
</winMedia:FontFamily>
</winControls:TextBlock.FontFamily>
</winControls:TextBlock>
...
</ContentPage>
Метод UIFont.FromName
фабрики используется для задания UILabel.Font
свойства новым UIFont
в iOS. UIFont
Имя и размер указываются аргументами метода, которые являются дочерними элементами атрибутаx:Arguments
.
Метод Typeface.Create
фабрики используется для задания TextView.Typeface
свойства новым Typeface
в Android. Имя Typeface
семейства и стиль задаются аргументами метода, которые являются дочерними элементами атрибута x:Arguments
.
Конструктор FontFamily
используется для задания TextBlock.FontFamily
свойства новым FontFamily
для универсальная платформа Windows (UWP). Имя FontFamily
указывается аргументом метода, который является дочерним элементом атрибута x:Arguments
.
Примечание.
Аргументы должны соответствовать типам, необходимым конструктору или методу фабрики.
На следующих снимках экрана показан результат указания метода фабрики и аргументов конструктора для задания шрифта в различных собственных представлениях:
Дополнительные сведения о передаче аргументов в XAML см. в разделе "Передача аргументов" в XAML.
Ссылки на собственные представления из кода
Хотя имя собственного представления с x:Name
атрибутом невозможно, можно получить экземпляр собственного представления, объявленный в XAML-файле из файла кода программной части в проекте общего доступа, если собственное представление является дочерним ContentView
x:Name
элементом атрибута. Затем в директивах условной компиляции в файле программной части необходимо выполнить следующее:
ContentView.Content
Извлеките значение свойства и приведите его к типу конкретнойNativeViewWrapper
платформы.NativeViewWrapper.NativeElement
Получите свойство и приведите его к типу собственного представления.
Затем собственный API можно вызвать в собственном представлении для выполнения требуемых операций. Этот подход также обеспечивает преимущество того, что несколько собственных представлений XAML для разных платформ могут быть дочерними элементами одного и того же ContentView
. В следующем примере кода демонстрируется этот метод:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:NativeViewInsideContentView"
x:Class="NativeViewInsideContentView.NativeViewInsideContentViewPage">
<StackLayout Margin="20">
<ContentView x:Name="contentViewTextParent" HorizontalOptions="Center" VerticalOptions="CenterAndExpand">
<ios:UILabel Text="Text in a UILabel" TextColor="{x:Static ios:UIColor.Red}" />
<androidWidget:TextView x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Text in a TextView" />
<winControls:TextBlock Text="Text in a TextBlock" />
</ContentView>
<ContentView x:Name="contentViewButtonParent" HorizontalOptions="Center" VerticalOptions="EndAndExpand">
<ios:UIButton TouchUpInside="OnButtonTap" View.HorizontalOptions="Center" View.VerticalOptions="Center" />
<androidWidget:Button x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Scale and Rotate Text"
Click="OnButtonTap" />
<winControls:Button Content="Scale and Rotate Text" />
</ContentView>
</StackLayout>
</ContentPage>
В приведенном выше примере собственные представления для каждой платформы являются дочерними элементами управления, с x:Name
значением атрибутаContentView
, используемым для получения ContentView
в коде программной части:
public partial class NativeViewInsideContentViewPage : ContentPage
{
public NativeViewInsideContentViewPage()
{
InitializeComponent();
#if __IOS__
var wrapper = (Xamarin.Forms.Platform.iOS.NativeViewWrapper)contentViewButtonParent.Content;
var button = (UIKit.UIButton)wrapper.NativeView;
button.SetTitle("Scale and Rotate Text", UIKit.UIControlState.Normal);
button.SetTitleColor(UIKit.UIColor.Black, UIKit.UIControlState.Normal);
#endif
#if __ANDROID__
var wrapper = (Xamarin.Forms.Platform.Android.NativeViewWrapper)contentViewTextParent.Content;
var textView = (Android.Widget.TextView)wrapper.NativeView;
textView.SetTextColor(Android.Graphics.Color.Red);
#endif
#if WINDOWS_UWP
var textWrapper = (Xamarin.Forms.Platform.UWP.NativeViewWrapper)contentViewTextParent.Content;
var textBlock = (Windows.UI.Xaml.Controls.TextBlock)textWrapper.NativeElement;
textBlock.Foreground = new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.Red);
var buttonWrapper = (Xamarin.Forms.Platform.UWP.NativeViewWrapper)contentViewButtonParent.Content;
var button = (Windows.UI.Xaml.Controls.Button)buttonWrapper.NativeElement;
button.Click += (sender, args) => OnButtonTap(sender, EventArgs.Empty);
#endif
}
async void OnButtonTap(object sender, EventArgs e)
{
contentViewButtonParent.Content.IsEnabled = false;
contentViewTextParent.Content.ScaleTo(2, 2000);
await contentViewTextParent.Content.RotateTo(360, 2000);
contentViewTextParent.Content.ScaleTo(1, 2000);
await contentViewTextParent.Content.RelRotateTo(360, 2000);
contentViewButtonParent.Content.IsEnabled = true;
}
}
Доступ ContentView.Content
к свойству осуществляется для получения встроенного представления в виде экземпляра конкретной NativeViewWrapper
платформы. Затем NativeViewWrapper.NativeElement
свойство получает доступ к собственному представлению в качестве собственного типа. Затем API собственного представления вызывается для выполнения требуемых операций.
Собственные кнопки iOS и Android используют один и тот же OnButtonTap
обработчик событий, так как каждая собственная кнопка использует EventHandler
делегат в ответ на событие сенсорного ввода. Однако в универсальная платформа Windows (UWP) используется отдельный RoutedEventHandler
обработчик событий, который, в свою очередь, использует OnButtonTap
обработчик событий в этом примере. Поэтому при нажатии собственной кнопки обработчик событий выполняется, OnButtonTap
который масштабируется и поворачивает собственный элемент управления, содержащийся в именованном элементе contentViewTextParent
ContentView
управления. На следующих снимках экрана показано, что это происходит на каждой платформе:
Собственные представления подклассов
Многие собственные представления iOS и Android не подходят для создания экземпляров в XAML, так как они используют методы, а не свойства для настройки элемента управления. Решением этой проблемы является подкласс собственных представлений в оболочках, определяющих более понятный API XAML, который использует свойства для настройки элемента управления и использует события, независимые от платформы. Затем упакованные собственные представления можно поместить в проект общего ресурса (SAP) и окружены директивами условной компиляции или поместить в проекты для конкретной платформы и ссылаться на XAML в проекте библиотеки .NET Standard.
В следующем примере кода показана Xamarin.Forms страница, используюющая подклассированные собственные представления:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:iosLocal="clr-namespace:SubclassedNativeControls.iOS;assembly=SubclassedNativeControls.iOS;targetPlatform=iOS"
xmlns:android="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SubclassedNativeControls.Droid;assembly=SubclassedNativeControls.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:SubclassedNativeControls"
x:Class="SubclassedNativeControls.SubclassedNativeControlsPage">
<StackLayout Margin="20">
<Label Text="Subclassed Native Views Demo" FontAttributes="Bold" HorizontalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="You have chosen:" />
<Label Text="{Binding SelectedFruit}" />
</StackLayout>
<iosLocal:MyUIPickerView ItemsSource="{Binding Fruits}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=SelectedItemChanged}" />
<androidLocal:MySpinner x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
ItemsSource="{Binding Fruits}"
SelectedObject="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=ItemSelected}" />
<winControls:ComboBox ItemsSource="{Binding Fruits}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=SelectionChanged}" />
</StackLayout>
</ContentPage>
Страница содержит Label
фрукты, выбранные пользователем из собственного элемента управления. Привязка Label
к свойству SubclassedNativeControlsPageViewModel.SelectedFruit
. На BindingContext
странице устанавливается новый экземпляр SubclassedNativeControlsPageViewModel
класса в файле кода программной части с классом ViewModel, реализующим INotifyPropertyChanged
интерфейс.
Страница также содержит собственное представление средства выбора для каждой платформы. Каждое собственное представление отображает коллекцию фруктов путем привязки его ItemSource
свойства к SubclassedNativeControlsPageViewModel.Fruits
коллекции. Это позволяет пользователю выбрать фрукты, как показано на следующих снимках экрана:
В iOS и Android собственные средства выбора используют методы для настройки элементов управления. Поэтому эти средства выбора должны быть подклассами для предоставления свойств, чтобы сделать их понятными для XAML. В универсальная платформа Windows (UWP) ComboBox
уже понятно xaml и поэтому не требует подкласса.
iOS
Реализация iOS классирует UIPickerView
представление и предоставляет свойства и событие, которое можно легко использовать из XAML:
public class MyUIPickerView : UIPickerView
{
public event EventHandler<EventArgs> SelectedItemChanged;
public MyUIPickerView()
{
var model = new PickerModel();
model.ItemChanged += (sender, e) =>
{
if (SelectedItemChanged != null)
{
SelectedItemChanged.Invoke(this, e);
}
};
Model = model;
}
public IList<string> ItemsSource
{
get
{
var pickerModel = Model as PickerModel;
return (pickerModel != null) ? pickerModel.Items : null;
}
set
{
var model = Model as PickerModel;
if (model != null)
{
model.Items = value;
}
}
}
public string SelectedItem
{
get { return (Model as PickerModel).SelectedItem; }
set { }
}
}
Класс MyUIPickerView
предоставляет ItemsSource
и SelectedItem
свойства, а также SelectedItemChanged
событие. Требуется UIPickerView
базовая UIPickerViewModel
модель данных, доступ к которой осуществляется свойствами и событием MyUIPickerView
. Модель UIPickerViewModel
данных предоставляется классом PickerModel
:
class PickerModel : UIPickerViewModel
{
int selectedIndex = 0;
public event EventHandler<EventArgs> ItemChanged;
public IList<string> Items { get; set; }
public string SelectedItem
{
get
{
return Items != null && selectedIndex >= 0 && selectedIndex < Items.Count ? Items[selectedIndex] : null;
}
}
public override nint GetRowsInComponent(UIPickerView pickerView, nint component)
{
return Items != null ? Items.Count : 0;
}
public override string GetTitle(UIPickerView pickerView, nint row, nint component)
{
return Items != null && Items.Count > row ? Items[(int)row] : null;
}
public override nint GetComponentCount(UIPickerView pickerView)
{
return 1;
}
public override void Selected(UIPickerView pickerView, nint row, nint component)
{
selectedIndex = (int)row;
if (ItemChanged != null)
{
ItemChanged.Invoke(this, new EventArgs());
}
}
}
Класс PickerModel
предоставляет базовое хранилище для MyUIPickerView
класса через Items
свойство. При каждом изменении выбранного элемента MyUIPickerView
Selected
метод выполняется, который обновляет выбранный индекс и запускает ItemChanged
событие. Это гарантирует, что SelectedItem
свойство всегда возвращает последний элемент, выбранный пользователем. Кроме того, PickerModel
класс переопределяет методы, используемые для настройки экземпляра MyUIPickerView
.
Android
Реализация Android классифицирует Spinner
представление и предоставляет свойства и событие, которое можно легко использовать из XAML:
class MySpinner : Spinner
{
ArrayAdapter adapter;
IList<string> items;
public IList<string> ItemsSource
{
get { return items; }
set
{
if (items != value)
{
items = value;
adapter.Clear();
foreach (string str in items)
{
adapter.Add(str);
}
}
}
}
public string SelectedObject
{
get { return (string)GetItemAtPosition(SelectedItemPosition); }
set
{
if (items != null)
{
int index = items.IndexOf(value);
if (index != -1)
{
SetSelection(index);
}
}
}
}
public MySpinner(Context context) : base(context)
{
ItemSelected += OnBindableSpinnerItemSelected;
adapter = new ArrayAdapter(context, Android.Resource.Layout.SimpleSpinnerItem);
adapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
Adapter = adapter;
}
void OnBindableSpinnerItemSelected(object sender, ItemSelectedEventArgs args)
{
SelectedObject = (string)GetItemAtPosition(args.Position);
}
}
Класс MySpinner
предоставляет ItemsSource
и SelectedObject
свойства, а также ItemSelected
событие. Элементы, отображаемые MySpinner
классом Adapter
, предоставляются связанным с представлением, а элементы заполняются Adapter
ItemsSource
при первом наборе свойства. Всякий раз, когда выбранный элемент в MySpinner
классе изменяется, OnBindableSpinnerItemSelected
обработчик событий обновляет SelectedObject
свойство.