Vues natives en XAML
Les vues natives iOS, Android et les plateforme Windows universelle peuvent être directement référencées à partir de Xamarin.Forms fichiers XAML. Les propriétés et les gestionnaires d’événements peuvent être définis sur des vues natives, et ils peuvent interagir avec Xamarin.Forms les vues. Cet article montre comment utiliser des vues natives à partir de Xamarin.Forms fichiers XAML.
Pour incorporer une vue native dans un Xamarin.Forms fichier XAML :
- Ajoutez une déclaration d’espace
xmlns
de noms dans le fichier XAML de l’espace de noms qui contient la vue native. - Créez une instance de la vue native dans le fichier XAML.
Important
Le code XAML compilé doit être désactivé pour toutes les pages XAML qui utilisent des vues natives. Pour ce faire, décorez la classe code-behind de votre page XAML avec l’attribut [XamlCompilation(XamlCompilationOptions.Skip)]
. Pour plus d’informations sur la compilation XAML, consultez Compilation XAML dans Xamarin.Forms.
Pour référencer une vue native à partir d’un fichier code-behind, vous devez utiliser un projet sap (Shared Asset Project) et encapsuler le code spécifique à la plateforme avec des directives de compilation conditionnelle. Pour plus d’informations, consultez Reportez-vous aux vues natives à partir du code.
Consommer des vues natives
L’exemple de code suivant illustre l’utilisation de vues natives pour chaque plateforme à un 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>
En plus de spécifier l’espace de noms et assembly
pour clr-namespace
un espace de noms d’affichage natif, il targetPlatform
doit également être spécifié. Cela doit être défini sur iOS
, , UWP
Android
, ( Windows
qui est équivalent à UWP
), macOS
, GTK
, , Tizen
ou WPF
. Au moment de l’exécution, l’analyseur XAML ignore les préfixes d’espace de noms XML dont targetPlatform
la plateforme ne correspond pas à la plateforme sur laquelle l’application s’exécute.
Chaque déclaration d’espace de noms peut être utilisée pour référencer n’importe quelle classe ou structure à partir de l’espace de noms spécifié. Par exemple, la ios
déclaration d’espace de noms peut être utilisée pour référencer n’importe quelle classe ou structure à partir de l’espace de noms iOS UIKit
. Les propriétés de la vue native peuvent être définies via XAML, mais les types de propriété et d’objet doivent correspondre. Par exemple, la UILabel.TextColor
propriété est définie à UIColor.Red
l’aide de l’extension x:Static
de balisage et de l’espace ios
de noms.
Les propriétés pouvant être liées et les propriétés pouvant être jointes peuvent également être définies sur des vues natives à l’aide de la Class.BindableProperty="value"
syntaxe. Chaque vue native est encapsulée dans une instance spécifique NativeViewWrapper
à la plateforme, qui dérive de la Xamarin.Forms.View
classe. La définition d’une propriété pouvant être liée ou d’une propriété pouvant être liée sur une vue native transfère la valeur de propriété au wrapper. Par exemple, une disposition horizontale centrée peut être spécifiée en définissant View.HorizontalOptions="Center"
sur la vue native.
Remarque
Notez que les styles ne peuvent pas être utilisés avec des vues natives, car les styles ne peuvent cibler que les propriétés sauvegardées par BindableProperty
des objets.
Les constructeurs de widgets Android nécessitent généralement l’objet Android Context
en tant qu’argument, et cela peut être rendu disponible via une propriété statique dans la MainActivity
classe. Par conséquent, lors de la création d’un widget Android en XAML, l’objet Context
doit généralement être transmis au constructeur du widget à l’aide de l’attribut x:Arguments
avec une x:Static
extension de balisage. Pour plus d’informations, consultez Passer des arguments aux vues natives.
Remarque
Notez que le nommage d’une vue native avec x:Name
n’est pas possible dans un projet de bibliothèque .NET Standard ou dans un projet sap (Shared Asset Project). Cela génère une variable du type natif, ce qui entraîne une erreur de compilation. Toutefois, les vues natives peuvent être encapsulées dans ContentView
des instances et récupérées dans le fichier code-behind, à condition qu’un SAP soit utilisé. Pour plus d’informations, consultez Reportez-vous à la vue native à partir du code.
Liaisons natives
La liaison de données est utilisée pour synchroniser une interface utilisateur avec sa source de données et simplifie l’affichage et l’interaction d’une Xamarin.Forms application avec ses données. À condition que l’objet source implémente l’interface INotifyPropertyChanged
, les modifications apportées à l’objet source sont automatiquement envoyées à l’objet cible par l’infrastructure de liaison, et les modifications apportées à l’objet cible peuvent éventuellement être envoyées (push) à l’objet source .
Les propriétés des vues natives peuvent également utiliser la liaison de données. L’exemple de code suivant illustre la liaison de données à l’aide des propriétés des vues natives :
<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 page contient une Entry
propriété dont IsEnabled
la propriété est liée à la NativeSwitchPageViewModel.IsSwitchOn
propriété. La BindingContext
page est définie sur une nouvelle instance de la NativeSwitchPageViewModel
classe dans le fichier code-behind, avec la classe ViewModel implémentant l’interface INotifyPropertyChanged
.
La page contient également un commutateur natif pour chaque plateforme. Chaque commutateur natif utilise une TwoWay
liaison pour mettre à jour la valeur de la NativeSwitchPageViewModel.IsSwitchOn
propriété. Par conséquent, lorsque le commutateur est désactivé, il Entry
est désactivé et lorsque le commutateur est activé, il Entry
est activé. Les captures d’écran suivantes montrent cette fonctionnalité sur chaque plateforme :
Les liaisons bidirectionnelle sont automatiquement prises en charge, à condition que la propriété native implémente INotifyPropertyChanged
, ou prend en charge l’observation clé-valeur (KVO) sur iOS, ou est une DependencyProperty
sur UWP. Toutefois, de nombreuses vues natives ne prennent pas en charge la notification de modification de propriété. Pour ces vues, vous pouvez spécifier une UpdateSourceEventName
valeur de propriété dans le cadre de l’expression de liaison. Cette propriété doit être définie sur le nom d’un événement dans la vue native qui signale lorsque la propriété cible a changé. Ensuite, lorsque la valeur du commutateur natif change, la Binding
classe est avertie que l’utilisateur a modifié la valeur du commutateur et que la valeur de propriété NativeSwitchPageViewModel.IsSwitchOn
est mise à jour.
Passer des arguments aux vues natives
Les arguments du constructeur peuvent être passés à des vues natives à l’aide de l’attribut x:Arguments
avec une x:Static
extension de balisage. En outre, les méthodes de fabrique d’affichage natif (public static
méthodes qui retournent des objets ou des valeurs du même type que la classe ou la structure qui définit les méthodes) peuvent être appelées en spécifiant le nom de la méthode à l’aide de l’attribut x:FactoryMethod
et ses arguments à l’aide de l’attribut x:Arguments
.
L’exemple de code suivant illustre les deux techniques :
<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>
La UIFont.FromName
méthode de fabrique est utilisée pour définir la UILabel.Font
propriété sur un nouveau UIFont
sur iOS. Le UIFont
nom et la taille sont spécifiés par les arguments de méthode qui sont des enfants de l’attribut x:Arguments
.
La Typeface.Create
méthode de fabrique est utilisée pour définir la TextView.Typeface
propriété sur un nouveau Typeface
sur Android. Le Typeface
nom de famille et le style sont spécifiés par les arguments de méthode qui sont des enfants de l’attribut x:Arguments
.
Le FontFamily
constructeur est utilisé pour définir la TextBlock.FontFamily
propriété sur une nouvelle FontFamily
propriété sur le plateforme Windows universelle (UWP). Le FontFamily
nom est spécifié par l’argument de méthode qui est un enfant de l’attribut x:Arguments
.
Remarque
Les arguments doivent correspondre aux types requis par le constructeur ou la méthode de fabrique.
Les captures d’écran suivantes montrent le résultat de la spécification des arguments de méthode et de constructeur de fabrique pour définir la police sur différentes vues natives :
Pour plus d’informations sur le passage d’arguments en XAML, consultez Passage d’arguments en XAML.
Reportez-vous aux vues natives à partir du code
Bien qu’il ne soit pas possible de nommer une vue native avec l’attribut x:Name
, il est possible de récupérer une instance de vue native déclarée dans un fichier XAML à partir de son fichier code-behind dans un projet d’accès partagé, à condition que la vue native soit un enfant d’une ContentView
valeur d’attribut x:Name
. Ensuite, dans les directives de compilation conditionnelle dans le fichier code-behind, vous devez :
- Récupérez la valeur de la propriété et convertissez-la
ContentView.Content
en type spécifiqueNativeViewWrapper
à la plateforme. - Récupérez la propriété et convertissez-la
NativeViewWrapper.NativeElement
en type d’affichage natif.
L’API native peut ensuite être appelée sur la vue native pour effectuer les opérations souhaitées. Cette approche offre également l’avantage que plusieurs vues natives XAML pour différentes plateformes peuvent être des enfants du même ContentView
. L’exemple de code suivant illustre cette technique :
<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>
Dans l’exemple ci-dessus, les vues natives pour chaque plateforme sont des enfants de ContentView
contrôles, avec la x:Name
valeur d’attribut utilisée pour récupérer le ContentView
code-behind :
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;
}
}
La ContentView.Content
propriété est accessible pour récupérer la vue native encapsulée en tant qu’instance spécifique à NativeViewWrapper
la plateforme. La NativeViewWrapper.NativeElement
propriété est ensuite accessible pour récupérer la vue native en tant que type natif. L’API de la vue native est ensuite appelée pour effectuer les opérations souhaitées.
Les boutons natifs iOS et Android partagent le même OnButtonTap
gestionnaire d’événements, car chaque bouton natif consomme un EventHandler
délégué en réponse à un événement tactile. Toutefois, l’plateforme Windows universelle (UWP) utilise à son tour un gestionnaire d’événements distinctRoutedEventHandler
, qui consomme à son tour le OnButtonTap
gestionnaire d’événements dans cet exemple. Par conséquent, lorsqu’un bouton natif est cliqué, le OnButtonTap
gestionnaire d’événements s’exécute, ce qui met à l’échelle et fait pivoter le contrôle natif contenu dans le ContentView
nom contentViewTextParent
. Les captures d’écran suivantes illustrent ce problème sur chaque plateforme :
Vues natives de sous-classes
De nombreuses vues natives iOS et Android ne conviennent pas à l’instanciation en XAML, car elles utilisent des méthodes, plutôt que des propriétés, pour configurer le contrôle. La solution à ce problème consiste à sous-classer des vues natives dans des wrappers qui définissent une API plus conviviale XAML qui utilise des propriétés pour configurer le contrôle et qui utilise des événements indépendants de la plateforme. Les vues natives encapsulées peuvent ensuite être placées dans un projet sap (Shared Asset Project) et entourées de directives de compilation conditionnelle, ou placées dans des projets spécifiques à la plateforme et référencées à partir de XAML dans un projet de bibliothèque .NET Standard.
L’exemple de code suivant illustre une Xamarin.Forms page qui consomme des vues natives sous-classifiées :
<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 page contient un Label
qui affiche les fruits choisis par l’utilisateur à partir d’un contrôle natif. L’objet Label
est lié à la SubclassedNativeControlsPageViewModel.SelectedFruit
propriété. La BindingContext
page est définie sur une nouvelle instance de la SubclassedNativeControlsPageViewModel
classe dans le fichier code-behind, avec la classe ViewModel implémentant l’interface INotifyPropertyChanged
.
La page contient également un affichage sélecteur natif pour chaque plateforme. Chaque vue native affiche la collection de fruits en liant sa ItemSource
propriété à la SubclassedNativeControlsPageViewModel.Fruits
collection. Cela permet à l’utilisateur de choisir un fruit, comme illustré dans les captures d’écran suivantes :
Sur iOS et Android, les sélecteurs natifs utilisent des méthodes pour configurer les contrôles. Par conséquent, ces sélecteurs doivent être sous-classés pour exposer les propriétés pour les rendre compatibles XAML. Sur le plateforme Windows universelle (UWP), il ComboBox
est déjà convivial en XAML, et ne nécessite donc pas de sous-classe.
iOS
L’implémentation iOS sous-classe la UIPickerView
vue et expose les propriétés et un événement qui peut être facilement consommé à partir de 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
classe expose et SelectedItem
répertorie ItemsSource
les propriétés et un SelectedItemChanged
événement. Un UIPickerView
modèle de données sous-jacent UIPickerViewModel
est requis, accessible par les propriétés et l’événement MyUIPickerView
. Le UIPickerViewModel
modèle de données est fourni par la PickerModel
classe :
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
classe fournit le stockage sous-jacent pour la MyUIPickerView
classe, via la Items
propriété. Chaque fois que l’élément sélectionné dans les MyUIPickerView
modifications, la Selected
méthode est exécutée, ce qui met à jour l’index sélectionné et déclenche l’événement ItemChanged
. Cela garantit que la SelectedItem
propriété retourne toujours le dernier élément sélectionné par l’utilisateur. En outre, la PickerModel
classe remplace les méthodes utilisées pour configurer l’instance MyUIPickerView
.
Android
L’implémentation Android sous-classe la Spinner
vue et expose les propriétés et un événement qui peut être facilement consommé à partir de 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
classe expose et SelectedObject
répertorie ItemsSource
les propriétés et un ItemSelected
événement. Les éléments affichés par la MySpinner
classe sont fournis par l’élément Adapter
associé à la vue, et les éléments sont renseignés dans le moment où la ItemsSource
propriété est définie pour la Adapter
première fois. Chaque fois que l’élément sélectionné dans la MySpinner
classe change, le OnBindableSpinnerItemSelected
gestionnaire d’événements met à jour la SelectedObject
propriété.