Sdílet prostřednictvím


Nativní zobrazení v jazyce XAML

Nativní zobrazení z iOSu, Androidu a Univerzální platforma Windows lze přímo odkazovat ze Xamarin.Forms souborů XAML. Vlastnosti a obslužné rutiny událostí lze nastavit v nativních zobrazeních a můžou pracovat se zobrazeními Xamarin.Forms . Tento článek ukazuje, jak využívat nativní zobrazení ze Xamarin.Forms souborů XAML.

Vložení nativního zobrazení do Xamarin.Forms souboru XAML:

  1. xmlns Přidejte deklaraci oboru názvů do souboru XAML pro obor názvů, který obsahuje nativní zobrazení.
  2. Vytvořte instanci nativního zobrazení v souboru XAML.

Důležité

Zkompilovaný XAML musí být zakázán pro všechny stránky XAML, které používají nativní zobrazení. Toho lze dosáhnout dekorací třídy kódu pro vaši stránku XAML atributem [XamlCompilation(XamlCompilationOptions.Skip)] . Další informace o kompilaci XAML naleznete v tématu Kompilace XAML v Xamarin.Forms.

Pokud chcete odkazovat na nativní zobrazení ze souboru kódu, musíte použít projekt sdíleného assetu (SAP) a zabalit kód specifický pro platformu direktivami podmíněné kompilace. Další informace naleznete v tématu Odkaz na nativní zobrazení z kódu.

Využívání nativních zobrazení

Následující příklad kódu ukazuje využití nativních zobrazení pro každou platformu Xamarin.FormsContentPagena:

<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>

Stejně jako určení clr-namespace a assembly pro nativní obor názvů targetPlatform zobrazení musí být také zadán. Toto nastavení by mělo být nastaveno na iOS, , Android, UWP( Windows které je ekvivalentní UWP), macOS, GTK, Tizennebo WPF. Analyzátor XAML bude za běhu ignorovat všechny předpony oboru názvů XML, které nemají targetPlatform shodu s platformou, na které je aplikace spuštěná.

Každá deklarace oboru názvů se dá použít k odkazování na libovolnou třídu nebo strukturu ze zadaného oboru názvů. Deklarace oboru názvů lze například ios použít k odkazování na libovolnou třídu nebo strukturu z oboru názvů iOS UIKit . Vlastnosti nativního zobrazení lze nastavit prostřednictvím XAML, ale vlastnosti a typy objektů se musí shodovat. UILabel.TextColor Například vlastnost je nastavena na UIColor.Red použití x:Static rozšíření značek a ios oboru názvů.

Vlastnosti s možností vazby a připojené vlastnosti bindable lze také nastavit v nativních zobrazeních pomocí Class.BindableProperty="value" syntaxe. Každé nativní zobrazení je zabaleno do instance specifické pro NativeViewWrapper platformu, která je odvozena od Xamarin.Forms.View třídy. Nastavení vlastnosti bindable nebo připojené bindable vlastnost v nativním zobrazení přenese hodnotu vlastnosti do obálky. Například vodorovné rozložení na střed lze určit nastavením View.HorizontalOptions="Center" nativního zobrazení.

Poznámka:

Všimněte si, že styly nelze použít s nativními zobrazeními, protože styly můžou cílit pouze na vlastnosti, které jsou podporovány BindableProperty objekty.

Konstruktory widgetu pro Android obecně vyžadují objekt Androidu Context jako argument, který lze zpřístupnit prostřednictvím statické vlastnosti ve MainActivity třídě. Proto při vytváření widgetu Android v XAML musí Context být objekt obecně předán konstruktoru widgetu pomocí x:Arguments atributu s rozšířením x:Static značek. Další informace najdete v tématu Předání argumentů nativním zobrazením.

Poznámka:

Všimněte si, že pojmenování nativního zobrazení pomocí x:Name není možné v projektu knihovny .NET Standard ani v projektu sdíleného assetu (SAP). Tím se vygeneruje proměnná nativního typu, která způsobí chybu kompilace. Nativní zobrazení se ale dají zabalit do ContentView instancí a načíst do souboru kódu za předpokladu, že se používá SAP. Další informace naleznete v tématu Odkaz na nativní zobrazení z kódu.

Nativní vazby

Datová vazba se používá k synchronizaci uživatelského rozhraní se zdrojem dat a zjednodušuje zobrazení Xamarin.Forms a interakci s daty aplikace. Za předpokladuINotifyPropertyChanged, že zdrojový objekt implementuje rozhraní, změny ve zdrojovém objektu se automaticky vloží do cílového objektu rozhraním vazby a změny v cílovém objektu lze volitelně odeslat do zdrojového objektu.

Vlastnosti nativních zobrazení můžou také používat datová vazba. Následující příklad kódu ukazuje datovou vazbu pomocí vlastností nativních zobrazení:

<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>

Stránka obsahuje vlastnost, jejíž Entry IsEnabled vlastnost je vázána na NativeSwitchPageViewModel.IsSwitchOn vlastnost. Stránka BindingContext je nastavena na novou instanci NativeSwitchPageViewModel třídy v souboru kódu za, s ViewModel třídy implementuje INotifyPropertyChanged rozhraní.

Stránka obsahuje také nativní přepínač pro každou platformu. Každý nativní přepínač používá TwoWay vazbu k aktualizaci hodnoty NativeSwitchPageViewModel.IsSwitchOn vlastnosti. Proto když je přepínač vypnutý, Entry je zakázán a když je přepínač zapnutý, Entry je povoleno. Následující snímky obrazovky znázorňují tuto funkci na jednotlivých platformách:

Nativní přepínač zakázánNativní přepínač povoleno

Obousměrné vazby jsou automaticky podporovány za předpokladu, že nativní vlastnost implementuje INotifyPropertyChangednebo podporuje funkci KVO (Key-Value Observing) v iOSu nebo je v DependencyProperty UPW. Mnoho nativních zobrazení však nepodporuje oznámení o změně vlastnosti. Pro tato zobrazení můžete jako součást vazbového výrazu zadat UpdateSourceEventName hodnotu vlastnosti. Tato vlastnost by měla být nastavena na název události v nativním zobrazení, který signalizuje, když se cílová vlastnost změnila. Když se pak změní hodnota nativního přepínače, Binding třída je upozorněna, že uživatel změnil hodnotu přepínače a NativeSwitchPageViewModel.IsSwitchOn hodnota vlastnosti se aktualizuje.

Předání argumentů nativním zobrazením

Argumenty konstruktoru lze předat nativním zobrazením pomocí x:Arguments atributu s rozšířením x:Static značek. Kromě toho lze nativní metody objektu pro zobrazení (public static metody, které vracejí objekty nebo hodnoty stejného typu jako třída nebo struktura definující metody) volat zadáním názvu metody pomocí atributu x:FactoryMethod a jeho argumenty pomocí atributu x:Arguments .

Následující příklad kódu ukazuje obě techniky:

<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>

Metoda UIFont.FromName továrny se používá k nastavení UILabel.Font vlastnosti na novou UIFont v iOSu. Název UIFont a velikost jsou určeny argumenty metody, které jsou podřízené atributu x:Arguments .

Metoda Typeface.Create továrny se používá k nastavení TextView.Typeface vlastnosti na nový Typeface v Androidu. Název Typeface a styl rodiny jsou určeny argumenty metody, které jsou podřízené atributu x:Arguments .

Konstruktor FontFamily slouží k nastavení TextBlock.FontFamily vlastnosti na novou FontFamily v Univerzální platforma Windows (UPW). Název FontFamily je určen argumentem metody, který je podřízený atribut.x:Arguments

Poznámka:

Argumenty musí odpovídat typům požadovaným konstruktorem nebo metodou továrny.

Následující snímky obrazovky ukazují výsledek zadání argumentů metody továrny a konstruktoru pro nastavení písma v různých nativních zobrazeních:

Nastavení písem v nativních zobrazeních

Další informace o předávání argumentů v XAML naleznete v tématu Předávání argumentů v XAML.

Odkaz na nativní zobrazení z kódu

I když není možné pojmenovat nativní zobrazení pomocí atributu x:Name , je možné načíst instanci nativního zobrazení deklarovanou v souboru XAML ze souboru kódu v projektu sdíleného přístupu za předpokladu, že nativní zobrazení je podřízeným objektem ContentView , který určuje x:Name hodnotu atributu. Pak uvnitř direktiv podmíněné kompilace v souboru s kódem byste měli:

  1. ContentView.Content Načtěte hodnotu vlastnosti a přetypujte ji na typ specifický pro NativeViewWrapper platformu.
  2. NativeViewWrapper.NativeElement Načtěte vlastnost a přetypujte ji na nativní typ zobrazení.

Nativní rozhraní API se pak dá vyvolat v nativním zobrazení a provést požadované operace. Tento přístup také nabízí výhodu, že více nativních zobrazení XAML pro různé platformy může být podřízené stejné ContentView. Následující příklad kódu ukazuje tuto techniku:

<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>

V předchozím příkladu jsou nativní zobrazení pro každou platformu podřízenými ContentView ovládacími prvky s x:Name hodnotou atributu, která se používá k načtení ContentView v kódu na pozadí:

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;
    }
}

Vlastnost ContentView.Content je přístupná k načtení zabaleného nativního zobrazení jako instance specifické pro NativeViewWrapper platformu. K NativeViewWrapper.NativeElement této vlastnosti se pak přistupuje k načtení nativního zobrazení jako jeho nativního typu. Rozhraní API nativního zobrazení se pak vyvolá za účelem provedení požadovaných operací.

Nativní tlačítka pro iOS a Android sdílejí stejnou obslužnou OnButtonTap rutinu události, protože každé nativní tlačítko využívá EventHandler delegáta v reakci na dotykovou událost. Nicméně Univerzální platforma Windows (UPW) používá samostatnou RoutedEventHandler, která zase využívá obslužnou rutinu OnButtonTap události v tomto příkladu. Proto se při kliknutí na OnButtonTap nativní tlačítko spustí obslužná rutina události, která škáluje a otočí nativní ovládací prvek obsažený v pojmenovaném ContentView contentViewTextParent. Následující snímky obrazovky ukazují, že k tomu dochází na jednotlivých platformách:

ContentView obsahující nativní ovládací prvek

Nativní zobrazení podtřídy

Mnoho nativních zobrazení pro iOS a Android není vhodné pro vytvoření instance v jazyce XAML, protože k nastavení ovládacího prvku používají metody, nikoli vlastnosti. Řešením tohoto problému je podtřída nativních zobrazení v obálkách, které definují popisnější rozhraní API XAML, které používá vlastnosti k nastavení ovládacího prvku a které používají události nezávislé na platformě. Zabalená nativní zobrazení se pak dají umístit do projektu sdíleného assetu (SAP) a být obklopena direktivami podmíněné kompilace nebo umístěná v projektech specifických pro platformu a odkazovaná z XAML v projektu knihovny .NET Standard.

Následující příklad kódu ukazuje Xamarin.Forms stránku, která využívá podtřídě nativní zobrazení:

<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>

Stránka obsahuje Label ovoce vybrané uživatelem z nativního ovládacího prvku. Vazby Label na SubclassedNativeControlsPageViewModel.SelectedFruit vlastnost. Stránka BindingContext je nastavena na novou instanci SubclassedNativeControlsPageViewModel třídy v souboru kódu za, s ViewModel třídy implementuje INotifyPropertyChanged rozhraní.

Stránka obsahuje také nativní zobrazení pro výběr pro každou platformu. Každé nativní zobrazení zobrazí kolekci ovoce vazbou jeho ItemSource vlastnosti na kolekci SubclassedNativeControlsPageViewModel.Fruits . To uživateli umožňuje vybrat ovoce, jak je znázorněno na následujících snímcích obrazovky:

Podtříděná nativní zobrazení

V iOSu a Androidu používají nativní výběrové metody k nastavení ovládacích prvků. Proto musí být tyto nástroje pro výběr podtříděny, aby byly vystaveny vlastnosti, aby byly přívětivé pro XAML. U Univerzální platforma Windows (UPW) ComboBox je už přívětivý pro XAML, takže nevyžaduje podtřídy.

iOS

Implementace iOS podtřídy UIPickerView zobrazení a zveřejňuje vlastnosti a událost, kterou lze snadno využívat z 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 { }
    }
}

Třída MyUIPickerView zveřejňuje ItemsSource a SelectedItem vlastnosti a SelectedItemChanged událost. A UIPickerView vyžaduje podkladový UIPickerViewModel datový model, ke kterému MyUIPickerView přistupuje vlastnosti a událost. Datový UIPickerViewModel model poskytuje PickerModel třída:

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());
        }
    }
}

Třída PickerModel poskytuje podkladové úložiště pro MyUIPickerView třídu prostřednictvím Items vlastnosti. Pokaždé, když se vybraná položka ve MyUIPickerView změnách provede, Selected spustí se metoda, která aktualizuje vybraný index a aktivuje ItemChanged událost. Tím se zajistí, že SelectedItem vlastnost vždy vrátí poslední položku, kterou vybral uživatel. Kromě toho PickerModel třída přepisuje metody, které se používají k nastavení MyUIPickerView instance.

Android

Implementace Androidu Spinner podtřídy zobrazení a zveřejňuje vlastnosti a událost, kterou lze snadno využívat z 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);
    }
}

Třída MySpinner zveřejňuje ItemsSource a SelectedObject vlastnosti a ItemSelected událost. Položky zobrazené MySpinner třídou jsou poskytovány Adapter přidruženým k zobrazení a položky jsou naplněny do Adapter při ItemsSource prvním nastavení vlastnosti. Kdykoli se vybraná položka ve MySpinner třídě změní, obslužná rutina OnBindableSpinnerItemSelected události aktualizuje SelectedObject vlastnost.