Vistas nativas en XAML
Se puede hacer referencia directamente a las vistas nativas de iOS, Android y Windows Platform universal desde Xamarin.Forms archivos XAML. Las propiedades y los controladores de eventos se pueden establecer en vistas nativas y pueden interactuar con vistas nativas desde iOS, Android y la Plataforma Windows universal, a las que se puede hacer referencia directamente desde Xamarin.FormsXamarin.Forms las vistas. En este artículo se muestra cómo consumir vistas nativas de Xamarin.Forms archivos XAML.
Para insertar una vista nativa en un Xamarin.Forms archivo XAML:
- Agregue una
xmlnsdeclaración de espacio de nombres en el archivo XAML para el espacio de nombres que contiene la vista nativa. - Cree una instancia de la vista nativa en el archivo XAML.
Importante
Xaml compilado debe deshabilitarse para cualquier página XAML que use vistas nativas. Esto se puede lograr si se decora la clase de código subyacente de la página XAML con el [XamlCompilation(XamlCompilationOptions.Skip)] atributo . Para obtener más información sobre la compilación XAML, vea XAML Compilation in Xamarin.Forms .
Para hacer referencia a una vista nativa desde un archivo de código subyacente, debe usar un recurso compartido Project (SAP) y encapsular el código específico de la plataforma con directivas de compilación condicional. Para obtener más información, vea Consulte las vistas nativas desde el código.
Consumo de vistas nativas
En el ejemplo de código siguiente se muestra el consumo de vistas nativas para cada plataforma a 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>
Además de especificar y para un espacio de nombres de vista nativo, también clr-namespaceassembly se debe especificar targetPlatform . Debe establecerse en iOS , Android , , UWPWindows (que equivale a ), UWP , , o macOSGTKTizenWPF . En tiempo de ejecución, el analizador XAML omitirá los prefijos de espacio de nombres XML que tengan un que no coincida con la plataforma en la que targetPlatform se ejecuta la aplicación.
Cada declaración de espacio de nombres se puede usar para hacer referencia a cualquier clase o estructura del espacio de nombres especificado. Por ejemplo, la declaración ios de espacio de nombres se puede usar para hacer referencia a cualquier clase o estructura del espacio de nombres de UIKit iOS. Las propiedades de la vista nativa se pueden establecer a través de XAML, pero los tipos de propiedad y objeto deben coincidir. Por ejemplo, la UILabel.TextColor propiedad se establece en mediante la extensión de marcado y el espacio de nombres UIColor.Redx:Staticios .
Las propiedades enlazables y las propiedades enlazables adjuntas también se pueden establecer en vistas nativas mediante la Class.BindableProperty="value" sintaxis . Cada vista nativa se encapsula en una instancia específica de la NativeViewWrapper plataforma, que deriva de la Xamarin.Forms.View clase . Al establecer una propiedad enlazable o una propiedad enlazable adjunta en una vista nativa, se transfiere el valor de propiedad al contenedor. Por ejemplo, se puede especificar un diseño horizontal centrado estableciendo View.HorizontalOptions="Center" en la vista nativa.
Nota:
Tenga en cuenta que los estilos no se pueden usar con vistas nativas, ya que los estilos solo pueden tener como destino propiedades que están copiadas por BindableProperty objetos .
Por lo general, los constructores de widget de Android requieren el objeto de Android como argumento y esto se puede hacer disponible a través de una Context propiedad estática en la clase MainActivity . Por lo tanto, al crear un widget de Android en XAML, el objeto generalmente debe pasarse al constructor del widget mediante el Context atributo con una extensión de x:Argumentsx:Static marcado. Para obtener más información, vea Pasar argumentos a vistas nativas.
Nota:
Tenga en cuenta que no es posible asignar un nombre a una vista nativa con un proyecto de biblioteca .NET Standard o un recurso x:Name compartido Project (SAP). Al hacerlo, se generará una variable del tipo nativo, lo que provocará un error de compilación. Sin embargo, las vistas nativas se pueden encapsular en instancias y recuperarse en el archivo de código subyacente, siempre que se esté ContentView utilizando un SAP. Para obtener más información, vea Hacer referencia a la vista nativa desde el código.
Enlaces nativos
El enlace de datos se usa para sincronizar una interfaz de usuario con su origen de datos y simplifica la forma en que una aplicación muestra e Xamarin.Forms interactúa con sus datos. Siempre que el objeto de origen implemente la interfaz , el marco de enlace inserta automáticamente los cambios en el objeto de origen y, opcionalmente, los cambios en el objeto de destino se pueden insertar en el objeto de INotifyPropertyChanged origen. INotifyPropertyChanged
Las propiedades de las vistas nativas también pueden usar el enlace de datos. En el ejemplo de código siguiente se muestra el enlace de datos mediante propiedades de vistas nativas:
<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>
La página contiene un Entry objeto cuya propiedad Xamarin_Forms Entry _VisualElement_IsEnabled" data-linktype="absolute-path">enlaza a la propiedad IsEnabledNativeSwitchPageViewModel.IsSwitchOn . El Xamarin_Forms _BindableObject_BindingContext" data-linktype="absolute-path">de la página se establece en una nueva instancia de la clase en el archivo de código subyacente, con la BindingContextNativeSwitchPageViewModel clase ViewModel INotifyPropertyChanged que implementa la interfaz .
La página también contiene un conmutador nativo para cada plataforma. Cada modificador nativo usa un enlace Xamarin_Forms _BindingMode_TwoWay" data-linktype="absolute-path">para actualizar el valor TwoWay de la NativeSwitchPageViewModel.IsSwitchOn propiedad. Por lo tanto, cuando el modificador está desactivado, se deshabilita y, cuando el conmutador está Entry activado, Entry se habilita . En las capturas de pantalla siguientes se muestra esta funcionalidad en cada plataforma:


Los enlaces de dos vías se admiten automáticamente siempre que la propiedad nativa implemente o admita INotifyPropertyChanged Key-Value Observing (KVO) en iOS o sea un elemento en DependencyProperty UWP. Sin embargo, muchas vistas nativas no admiten la notificación de cambio de propiedad. Para estas vistas, puede especificar un valor de propiedad Xamarin_Forms _Binding_UpdateSourceEventName" data-linktype="absolute-path">como parte de la expresión UpdateSourceEventName de enlace. Esta propiedad debe establecerse en el nombre de un evento en la vista nativa que indica cuándo ha cambiado la propiedad de destino. A continuación, cuando cambia el valor del modificador nativo, se notifica a la clase que el usuario ha cambiado el valor del modificador y se actualiza BindingNativeSwitchPageViewModel.IsSwitchOn el valor de propiedad.
Pasar argumentos a vistas nativas
Los argumentos de constructor se pueden pasar a vistas nativas mediante el x:Arguments atributo con una extensión de x:Static marcado. Además, se puede llamar a los métodos de generador de vistas nativos (métodos que devuelven objetos o valores del mismo tipo que la clase o estructura que define los métodos) especificando el nombre del método mediante el atributo y sus argumentos mediante el public staticx:FactoryMethod atributo x:Arguments .
En el ejemplo de código siguiente se muestran ambas técnicas:
<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>
El UIFont.FromName método factory se usa para establecer la propiedad en un nuevo en UILabel.FontUIFont iOS. Los argumentos de método que son secundarios del atributo especifican el nombre UIFont y el x:Arguments tamaño.
El Typeface.Create método factory se usa para establecer la propiedad en un nuevo en TextView.TypefaceTypeface Android. Los argumentos de método que son secundarios del atributo especifican el nombre de familia Typeface y el x:Arguments estilo.
El constructor se usa para establecer la propiedad en un nuevo en la Plataforma FontFamilyTextBlock.FontFamily Windows universal FontFamily (UWP). El FontFamily nombre se especifica mediante el argumento de método que es un elemento secundario del atributo x:Arguments .
Nota:
Los argumentos deben coincidir con los tipos requeridos por el constructor o el método de generador.
En las capturas de pantalla siguientes se muestra el resultado de especificar argumentos de constructor y método de generador para establecer la fuente en diferentes vistas nativas:

Para obtener más información sobre cómo pasar argumentos en XAML, vea Pasar argumentos en XAML.
Hacer referencia a vistas nativas desde el código
Aunque no es posible nombrar una vista nativa con el atributo , es posible recuperar una instancia de vista nativa declarada en un archivo XAML de su archivo de código subyacente en un Project de acceso compartido, siempre que la vista nativa sea un elemento secundario de que especifique un valor x:NameContentView de x:Name atributo. A continuación, dentro de las directivas de compilación condicional en el archivo de código subyacente, debe:
- Recupere el Xamarin_Forms _ContentView_Content" data-linktype="absolute-path">valor de propiedad y conéctelo a un tipo específico
ContentView.Contentde laNativeViewWrapperplataforma. - Recupere la
NativeViewWrapper.NativeElementpropiedad y conéctela al tipo de vista nativa.
A continuación, la API nativa se puede invocar en la vista nativa para realizar las operaciones deseadas. Este enfoque también ofrece la ventaja de que varias vistas nativas XAML para distintas plataformas pueden ser elementos secundarios de la misma ContentView . En el ejemplo de código siguiente se muestra esta técnica:
<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>
En el ejemplo anterior, las vistas nativas de cada plataforma son secundarios de los controles, con el valor de atributo que se usa para recuperar en ContentViewx:Name el código ContentView subyacente:
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;
}
}
Se tiene acceso Xamarin_Forms _ContentView_Content" data-linktype="absolute-path">para recuperar la vista nativa ajustada como una instancia específica de ContentView.Content la NativeViewWrapper plataforma. A NativeViewWrapper.NativeElement continuación, se obtiene acceso a la propiedad para recuperar la vista nativa como su tipo nativo. A continuación, se invoca la API de la vista nativa para realizar las operaciones deseadas.
Los botones nativos de iOS y Android comparten el mismo controlador de eventos, ya que cada botón nativo consume un delegado OnButtonTap en respuesta a un evento EventHandler táctil. Sin embargo, la Plataforma Windows universal (UWP) usa un independiente, que a su vez consume el controlador de RoutedEventHandlerOnButtonTap eventos en este ejemplo. Por lo tanto, cuando se hace clic en un botón nativo, se ejecuta el controlador de eventos, que escala y gira el control nativo contenido OnButtonTap en el objeto con nombre ContentViewcontentViewTextParent . En las capturas de pantalla siguientes se muestra lo que ocurre en cada plataforma:

Vistas nativas de subclase
Muchas vistas nativas de iOS y Android no son adecuadas para crear instancias en XAML porque usan métodos, en lugar de propiedades, para configurar el control. La solución a este problema es crear subclases de vistas nativas en contenedores que definen una API más sencilla para XAML que usa propiedades para configurar el control y que usa eventos independientes de la plataforma. A continuación, las vistas nativas ajustadas se pueden colocar en un recurso compartido Project (SAP) y rodearse con directivas de compilación condicional, o colocarse en proyectos específicos de la plataforma y hacer referencia a él desde XAML en un proyecto de biblioteca .NET Standard.
En el ejemplo de código siguiente se muestra Xamarin.Forms una página que consume vistas nativas con subclases:
<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>
La página contiene un Label objeto que muestra el resultado elegido por el usuario a partir de un control nativo. enlaza Label a la propiedad SubclassedNativeControlsPageViewModel.SelectedFruit . El Xamarin_Forms _BindableObject_BindingContext" data-linktype="absolute-path">de la página se establece en una nueva instancia de la clase en el archivo de código subyacente, con la BindingContextSubclassedNativeControlsPageViewModel clase ViewModel INotifyPropertyChanged que implementa la interfaz .
La página también contiene una vista de selector nativo para cada plataforma. Cada vista nativa muestra la colección de hadas enlazando su ItemSource propiedad a la SubclassedNativeControlsPageViewModel.Fruits colección. Esto permite al usuario elegir una fruta, como se muestra en las capturas de pantalla siguientes:

En iOS y Android, los selectores nativos usan métodos para configurar los controles. Por lo tanto, estos selectores deben tener subclases para exponer propiedades para que sean fáciles de usar en XAML. En la Plataforma Windows aplicaciones universales (UWP), el ya es descriptivo para XAML, por lo que no ComboBox requiere subclases.
iOS
La implementación de iOS crea subclases en la vista y expone las propiedades y un evento que se UIPickerView puede consumir fácilmente desde 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 { }
}
}
La MyUIPickerView clase expone las propiedades y , y un evento ItemsSourceSelectedItemSelectedItemChanged . Requiere UIPickerView un modelo de datos subyacente al que UIPickerViewModel acceden las propiedades y el evento MyUIPickerView . La UIPickerViewModel clase proporciona el modelo de PickerModel datos:
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());
}
}
}
La PickerModel clase proporciona el almacenamiento subyacente para la MyUIPickerView clase, a través de la propiedad Items . Cada vez que cambia el elemento seleccionado en el , se ejecuta el método , que actualiza MyUIPickerView el índice seleccionado y activa el SelectedItemChanged evento. Esto garantiza que la SelectedItem propiedad siempre devolverá el último elemento seleccionado por el usuario. Además, la clase PickerModel invalida los métodos que se usan para configurar la MyUIPickerView instancia.
Android
La implementación de Android crea subclases en la vista y expone las propiedades y un evento que se Spinner puede consumir fácilmente desde 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);
}
}
La MySpinner clase expone las propiedades y , y un evento ItemsSourceSelectedObjectItemSelected . Los elementos mostrados por la clase los proporciona el asociado a la vista y los elementos se rellenan en cuando se establece MySpinner la propiedad por primera AdapterAdapterItemsSource vez. Cada vez que cambia el elemento seleccionado en MySpinner la clase , el controlador de eventos actualiza la propiedad OnBindableSpinnerItemSelectedSelectedObject .
Descarga del ejemplo