Visualizzazioni native in XAML
È possibile fare riferimento direttamente alle visualizzazioni native da iOS, Android e dal piattaforma UWP (Universal Windows Platform) dai Xamarin.Forms file XAML. Le proprietà e i gestori eventi possono essere impostati nelle visualizzazioni native e possono interagire con Xamarin.Forms le visualizzazioni. Questo articolo illustra come usare le visualizzazioni native dai Xamarin.Forms file XAML.
Per incorporare una visualizzazione nativa in un Xamarin.Forms file XAML:
- Aggiungere una
xmlns
dichiarazione dello spazio dei nomi nel file XAML per lo spazio dei nomi che contiene la visualizzazione nativa. - Creare un'istanza della visualizzazione nativa nel file XAML.
Importante
Xaml compilato deve essere disabilitato per tutte le pagine XAML che usano visualizzazioni native. A tale scopo, è possibile decorare la classe code-behind per la pagina XAML con l'attributo [XamlCompilation(XamlCompilationOptions.Skip)]
. Per altre informazioni sulla compilazione XAML, vedere Compilazione XAML in Xamarin.Forms.
Per fare riferimento a una visualizzazione nativa da un file code-behind, è necessario usare un progetto di asset condiviso (SAP) ed eseguire il wrapping del codice specifico della piattaforma con direttive di compilazione condizionale. Per altre informazioni, vedere Fare riferimento alle visualizzazioni native dal codice.
Utilizzare le visualizzazioni native
Nell'esempio di codice seguente viene illustrato l'utilizzo di viste native per ogni piattaforma in un Xamarin.FormsContentPage
oggetto :
<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>
Oltre a specificare e clr-namespace
assembly
per uno spazio dei nomi di visualizzazione nativa, è necessario specificare anche un oggetto targetPlatform
. Deve essere impostato su , , , (equivalente a UWP
), macOS
, GTK
Tizen
, o WPF
. Windows
UWP
Android
iOS
In fase di esecuzione, il parser XAML ignorerà tutti i prefissi dello spazio dei nomi XML con un targetPlatform
oggetto che non corrisponde alla piattaforma in cui è in esecuzione l'applicazione.
Ogni dichiarazione dello spazio dei nomi può essere usata per fare riferimento a qualsiasi classe o struttura dallo spazio dei nomi specificato. Ad esempio, la ios
dichiarazione dello spazio dei nomi può essere usata per fare riferimento a qualsiasi classe o struttura dallo spazio dei nomi iOS UIKit
. Le proprietà della visualizzazione nativa possono essere impostate tramite XAML, ma i tipi di proprietà e di oggetto devono corrispondere. Ad esempio, la UILabel.TextColor
proprietà è impostata su UIColor.Red
usando l'estensione x:Static
di markup e lo ios
spazio dei nomi .
Le proprietà associabili e le proprietà associabili associate possono essere impostate anche nelle viste native usando la Class.BindableProperty="value"
sintassi . Ogni visualizzazione nativa viene sottoposta a wrapping in un'istanza specifica NativeViewWrapper
della Xamarin.Forms.View
piattaforma, che deriva dalla classe . L'impostazione di una proprietà associabile o associabile associata in una visualizzazione nativa trasferisce il valore della proprietà al wrapper. Ad esempio, è possibile specificare un layout orizzontale centrato impostando View.HorizontalOptions="Center"
nella visualizzazione nativa.
Nota
Si noti che gli stili non possono essere usati con le visualizzazioni native, perché gli stili possono essere destinati solo alle proprietà supportate dagli BindableProperty
oggetti .
I costruttori di widget Android richiedono in genere l'oggetto Android Context
come argomento e questo può essere reso disponibile tramite una proprietà statica nella MainActivity
classe . Pertanto, quando si crea un widget Android in XAML, l'oggetto Context
deve in genere essere passato al costruttore del widget usando l'attributo con un'estensione x:Arguments
x:Static
di markup. Per altre informazioni, vedere Passare argomenti a viste native.
Nota
Si noti che la denominazione di una visualizzazione nativa con x:Name
non è possibile in un progetto di libreria .NET Standard o in un progetto di asset condiviso (SAP). In questo modo verrà generata una variabile del tipo nativo, che causerà un errore di compilazione. Tuttavia, le viste native possono essere sottoposte a wrapping in ContentView
istanze e recuperate nel file code-behind, purché venga usato un sap. Per altre informazioni, vedere Fare riferimento alla visualizzazione nativa dal codice.
Associazioni native
Il data binding viene usato per sincronizzare un'interfaccia utente con l'origine dati e semplifica la visualizzazione e l'interazione di un'applicazione Xamarin.Forms con i relativi dati. A condizione che l'oggetto di origine implementi l'interfacciaINotifyPropertyChanged
, le modifiche apportate all'oggetto di origine vengono automaticamente inserite nell'oggetto di destinazione dal framework di associazione e le modifiche apportate all'oggetto di destinazione possono essere eventualmente spostate nell'oggetto di origine.
Le proprietà delle viste native possono anche usare il data binding. Nell'esempio di codice seguente viene illustrato il data binding usando le proprietà delle viste native:
<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 pagina contiene un oggetto Entry
la NativeSwitchPageViewModel.IsSwitchOn
cui IsEnabled
proprietà è associata alla proprietà . La BindingContext
proprietà della pagina è impostata su una nuova istanza della NativeSwitchPageViewModel
classe nel file code-behind, con la classe ViewModel che implementa l'interfaccia INotifyPropertyChanged
.
La pagina contiene anche un commutatore nativo per ogni piattaforma. Ogni opzione nativa usa un'associazione TwoWay
per aggiornare il valore della NativeSwitchPageViewModel.IsSwitchOn
proprietà. Pertanto, quando l'interruttore è spento, l'oggetto Entry
è disabilitato e, quando l'opzione Entry
è attivata, è abilitata. Gli screenshot seguenti mostrano questa funzionalità in ogni piattaforma:
Le associazioni bidirezionali sono supportate automaticamente a condizione che la proprietà nativa implementi INotifyPropertyChanged
o supporti L'osservazione chiave-valore (KVO) in iOS o sia una piattaforma DependencyProperty
UWP. Tuttavia, molte viste native non supportano la notifica delle modifiche alle proprietà. Per queste viste, è possibile specificare un UpdateSourceEventName
valore della proprietà come parte dell'espressione di associazione. Questa proprietà deve essere impostata sul nome di un evento nella visualizzazione nativa che segnala quando la proprietà di destinazione è stata modificata. Quindi, quando il valore dell'opzione nativa cambia, la Binding
classe riceve una notifica che indica che l'utente ha modificato il valore dell'opzione e il valore della NativeSwitchPageViewModel.IsSwitchOn
proprietà viene aggiornato.
Passare argomenti a viste native
Gli argomenti del costruttore possono essere passati alle viste native usando l'attributo con un'estensione x:Arguments
x:Static
di markup. Inoltre, i metodi della factory di visualizzazione nativa (public static
metodi che restituiscono oggetti o valori dello stesso tipo della classe o della struttura che definisce i metodi) possono essere chiamati specificando il nome del metodo usando l'attributo x:FactoryMethod
e i relativi argomenti usando l'attributo x:Arguments
.
L'esempio di codice seguente illustra entrambe le tecniche:
<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>
Il UIFont.FromName
metodo factory viene usato per impostare la UILabel.Font
proprietà su un nuovo UIFont
in iOS. Il UIFont
nome e le dimensioni vengono specificati dagli argomenti del metodo figlio dell'attributo x:Arguments
.
Il Typeface.Create
metodo factory viene usato per impostare la TextView.Typeface
proprietà su un nuovo Typeface
in Android. Il Typeface
nome e lo stile della famiglia vengono specificati dagli argomenti del metodo figlio dell'attributo x:Arguments
.
Il FontFamily
costruttore viene usato per impostare la TextBlock.FontFamily
proprietà su un nuovo FontFamily
oggetto nella piattaforma UWP (Universal Windows Platform) (UWP). Il FontFamily
nome viene specificato dall'argomento del metodo figlio dell'attributo x:Arguments
.
Nota
Gli argomenti devono corrispondere ai tipi richiesti dal costruttore o dal metodo factory.
Gli screenshot seguenti mostrano il risultato della specifica di argomenti del metodo factory e del costruttore per impostare il tipo di carattere in visualizzazioni native diverse:
Per altre informazioni sul passaggio di argomenti in XAML, vedere Passaggio di argomenti in XAML.
Fare riferimento alle visualizzazioni native dal codice
Sebbene non sia possibile denominare una visualizzazione nativa con l'attributo , è possibile recuperare un'istanza x:Name
di visualizzazione nativa dichiarata in un file XAML dal file code-behind in un progetto di accesso condiviso, purché la visualizzazione nativa sia un elemento figlio di un ContentView
oggetto che specifica un x:Name
valore di attributo. Quindi, all'interno delle direttive di compilazione condizionale nel file code-behind è necessario:
- Recuperare il valore della proprietà ed eseguirne il
ContentView.Content
cast in un tipo specificoNativeViewWrapper
della piattaforma. - Recuperare la
NativeViewWrapper.NativeElement
proprietà ed eseguirne il cast nel tipo di visualizzazione nativa.
L'API nativa può quindi essere richiamata nella visualizzazione nativa per eseguire le operazioni desiderate. Questo approccio offre anche il vantaggio che più visualizzazioni native XAML per piattaforme diverse possono essere elementi figlio dello stesso ContentView
. L'esempio di codice seguente illustra questa tecnica:
<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>
Nell'esempio precedente, le visualizzazioni native per ogni piattaforma sono elementi figlio di controlli, con il x:Name
valore dell'attributo ContentView
ContentView
usato per recuperare in 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;
}
}
È ContentView.Content
possibile accedere alla proprietà per recuperare la visualizzazione nativa di cui è stato eseguito il wrapping come istanza specifica NativeViewWrapper
della piattaforma. Viene NativeViewWrapper.NativeElement
quindi eseguito l'accesso alla proprietà per recuperare la visualizzazione nativa come tipo nativo. L'API della visualizzazione nativa viene quindi richiamata per eseguire le operazioni desiderate.
I pulsanti nativi iOS e Android condividono lo stesso OnButtonTap
gestore eventi, perché ogni pulsante nativo usa un EventHandler
delegato in risposta a un evento di tocco. Tuttavia, il piattaforma UWP (Universal Windows Platform) (UWP) usa un oggetto separatoRoutedEventHandler
, che a sua volta usa il OnButtonTap
gestore eventi in questo esempio. Pertanto, quando si fa clic su un pulsante nativo, viene eseguito il OnButtonTap
gestore eventi, che ridimensiona e ruota il controllo nativo contenuto all'interno dell'oggetto ContentView
denominato contentViewTextParent
. Gli screenshot seguenti illustrano questa situazione in ogni piattaforma:
Viste native della sottoclasse
Molte visualizzazioni native iOS e Android non sono adatte per creare un'istanza in XAML perché usano metodi, anziché proprietà, per configurare il controllo. La soluzione a questo problema consiste nella sottoclasse delle visualizzazioni native nei wrapper che definiscono un'API più semplice da XAML che usa le proprietà per configurare il controllo e che usa eventi indipendenti dalla piattaforma. Le visualizzazioni native di cui è stato eseguito il wrapping possono quindi essere inserite in un progetto di asset condiviso (SAP) e racchiuse con direttive di compilazione condizionale oppure inserite in progetti specifici della piattaforma e a cui viene fatto riferimento da XAML in un progetto di libreria .NET Standard.
Nell'esempio di codice seguente viene illustrata una Xamarin.Forms pagina che utilizza viste native sottoclassate:
<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 pagina contiene un oggetto Label
che visualizza la frutta scelta dall'utente da un controllo nativo. L'oggetto Label
viene associato alla SubclassedNativeControlsPageViewModel.SelectedFruit
proprietà . La BindingContext
proprietà della pagina è impostata su una nuova istanza della SubclassedNativeControlsPageViewModel
classe nel file code-behind, con la classe ViewModel che implementa l'interfaccia INotifyPropertyChanged
.
La pagina contiene anche una visualizzazione selezione nativa per ogni piattaforma. Ogni visualizzazione nativa visualizza la raccolta di frutti associandone la ItemSource
SubclassedNativeControlsPageViewModel.Fruits
proprietà alla raccolta. In questo modo l'utente può scegliere un frutto, come illustrato negli screenshot seguenti:
In iOS e Android gli strumenti di selezione nativi usano metodi per configurare i controlli. Pertanto, questi picker devono essere sottoclassati per esporre le proprietà per renderle compatibili con XAML. Nella piattaforma UWP (Universal Windows Platform) (UWP), è ComboBox
già compatibile con XAML e quindi non richiede la sottoclasse.
iOS
L'implementazione di iOS sottoclasse la UIPickerView
visualizzazione ed espone le proprietà e un evento che può essere facilmente utilizzato da 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 espone ItemsSource
le proprietà e SelectedItem
e un SelectedItemChanged
evento. Un UIPickerView
oggetto richiede un modello di dati sottostante UIPickerViewModel
, accessibile dalle proprietà e dall'evento MyUIPickerView
. Il UIPickerViewModel
modello di dati viene fornito dalla 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 fornisce l'archiviazione sottostante per la MyUIPickerView
classe tramite la Items
proprietà . Ogni volta che l'elemento selezionato viene MyUIPickerView
modificato, viene eseguito il Selected
metodo che aggiorna l'indice selezionato e genera l'evento ItemChanged
. In questo modo, la SelectedItem
proprietà restituirà sempre l'ultimo elemento selezionato dall'utente. Inoltre, la classe esegue l'override PickerModel
dei metodi utilizzati per configurare l'istanza MyUIPickerView
.
Android
L'implementazione di Android sottoclasse la Spinner
visualizzazione ed espone le proprietà e un evento che può essere facilmente utilizzato da 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 espone ItemsSource
le proprietà e SelectedObject
e un ItemSelected
evento. Gli elementi visualizzati dalla MySpinner
classe vengono forniti dall'oggetto Adapter
associato alla visualizzazione e gli elementi vengono popolati in Adapter
quando la ItemsSource
proprietà viene impostata per la prima volta. Ogni volta che l'elemento selezionato nella MySpinner
classe cambia, il OnBindableSpinnerItemSelected
gestore eventi aggiorna la SelectedObject
proprietà.