Xamarin Forms Picker

Criando opções de Bindings no componente Picker com Xamarin Forms

Fala galera!

Depois de um dúvida que surgiu no Github a respeito de implementar propriedades de Binding no Picker, decidimos mostrar algumas abordagens para pegar e setar valores nele.

Nesse post vamos implementar Binding com Picker com três abordagens diferentes.

Infelizmente o controle (View) Picker no Xamarin Forms não tem propriedades do tipo BindableProperty que permitem setar e pegar valores direto como o ItemsSource e SelectedItem do ListView, e isso é uma coisa que a comunidade está cobrando e muito à Xamarin.

Existem algumas alternativas para fazer essa funcionalidade, vou mostrar algumas abordagens, desde a direta até Binding com MVVM! =]

Enfim, vamos à implementação:

 

Abordagem #1 – Xamarin Forms puro

Nessa abordagem, para setar os valores dos itens do Picker, temos que acessar a propriedade pckEstado.Items e adicionar com o método “.Add()” cada item que será mostrado.

 

pckEstado = new Picker { Title = "Estado" };
pckEstado.Items.Add("SP");
pckEstado.Items.Add("RJ");
pckEstado.Items.Add("DF");
pckEstado.Items.Add("RS");

 

O problema dessa abordagem é a forma que se pega o item selecionado, pois o Picker só disponibiliza a propriedade SelectedIndex, ou seja, apenas o índice do item selecionado, lembrando que o primeiro item é 0 (zero), e incremental de um em um, onde se não for selecionado retornará -1.

Para pegarmos o valor/texto selecionado você pode juntar a informação do SelectedIndex com a propriedade Items passando o índice da seleção e ai retornando o “valor  selecionado”.

 

 var itemSelecionado = pckEstado.Items[pckEstado.SelectedIndex];

 

Ou com LINQ (lembre-se de utilizar a biblioteca System.Linq nesse caso.)

 

 var itemSelecionado = pckEstado.ElementAt(pckEstado.SelectedIndex);

 

Abordagem #2 – XAML + MVVM + Binding + Custom Control

Nessa abordagem vamos implementar uma customização do Picker nativo do Xamarin.Forms, e codificarmos nossas propriedades BindableProperty acrescentando o ItemsSource e o SelectedItem com as mesmas funcionalidades do ListView.

Para customizar é só criar uma classe e herdar do controle (View) que desejar, no caso o Picker:

 

public class BindablePicker : Picker
{
   ...
}

 

Dentro dessa classe vamos codificar nossas duas novas propriedades e eventos responsáveis pelas modificações dos valores:

 

public class BindablePicker : Picker
    {
        public BindablePicker()
        {
            this.SelectedIndexChanged += OnSelectedIndexChanged;
        }

        public static BindableProperty ItemsSourceProperty =
            BindableProperty.Create<bindablepicker, ienumerable="">(o => o.ItemsSource, default(IEnumerable), propertyChanged: OnItemsSourceChanged);

        public static BindableProperty SelectedItemProperty =
            BindableProperty.Create<bindablepicker, object="">(o => o.SelectedItem, default(object), propertyChanged: OnSelectedItemChanged);


        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public object SelectedItem
        {
            get { return (object)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }

        private static void OnItemsSourceChanged(BindableObject bindable, IEnumerable oldvalue, IEnumerable newvalue)
        {
            var picker = bindable as BindablePicker;
            picker.Items.Clear();
            if (newvalue != null)
            {
                foreach (var item in newvalue)
                {
                    picker.Items.Add(item.ToString());
                }
            }
        }

        private void OnSelectedIndexChanged(object sender, EventArgs eventArgs)
        {
            if (SelectedIndex < 0 || SelectedIndex > Items.Count - 1)
            {
                SelectedItem = null;
            }
            else
            {
                SelectedItem = Items[SelectedIndex];
            }
        }
        private static void OnSelectedItemChanged(BindableObject bindable, object oldvalue, object newvalue)
        {
            var picker = bindable as BindablePicker;
            if (newvalue != null)
            {
                picker.SelectedIndex = picker.Items.IndexOf(newvalue.ToString());
            }
        }
    }

 

Para usarmos nosso novo BindablePicker no XAML temos que referenciar o namespace e assembly na notação do XAML:

 

xmlns:control="clr-namespace:AppsBindable.Constrols;assembly=AppsBindable"

 

Ficando assim na página XAML:

 

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="AppsBindable.Views.TestePage"
             xmlns:control="clr-namespace:AppsBindable.Constrols;assembly=AppsBindable"
             xmlns:Local="clr-namespace:AppsBindable.ViewModel;assembly=AppsBindable">

 

Agora é só utilizar nosso controle e configurarmos da forma que possamos utilizar via Binding:

 

<control:BindablePicker  x:Name="pckEstado" Title="Estado" ItemsSource="{Binding ListaEstados}" SelectedItem="{Binding Estado, Mode=TwoWay}" />

 

Como nessa abordagem utilizaremos o MVVM, aconselho fortemente o estudo desse Post feito pelo Rafael aqui no Studyxnet!

 

Dito isso, vamos utilizar nosso MVVM! =]

Primeiramente definiremos nossa ViewModel da seguinte maneira:

 

public class TesteViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public TesteViewModel()
        {
            ListaEstados = new ObservableCollection<string>();
            ListaEstados.Add("DF");
            ListaEstados.Add("SP");
            ListaEstados.Add("RJ");
            ListaEstados.Add("BH");
            ListaEstados.Add("RS");

            Pegar = new Command(OnPegar);
        }

        private void OnPegar(object obj)
        {
            if (!string.IsNullOrEmpty(Estado))
            {
                EstadoSelecionado = Estado;
            }
            else
            {
                EstadoSelecionado = "Selecione um Estado";
            }
        }

        public ICommand Pegar { get; set; }

        ObservableCollection<string> _listaEstados;
        public ObservableCollection<string> ListaEstados
        {
            get
            {
                return _listaEstados;
            }
            set
            {
                _listaEstados = value;
                OnPropertyChanged();
            }
        }

        string _estado;
        public string Estado
        {
            get
            {
                return _estado;
            }
            set
            {
                _estado = value;
                OnPropertyChanged();
            }
        }
        string _estadoSelecionado;
        public string EstadoSelecionado
        {
            get
            {
                return _estadoSelecionado;
            }
            set
            {
                _estadoSelecionado = value;
                OnPropertyChanged();
            }
        }
    }

 

Agora é só referenciar nossa ViewModel como BindingContext na página XAML:

 

<ContentPage.BindingContext>
    <Local:TesteViewModel />
  </ContentPage.BindingContext>

 

Agora vamos colocar mais alguns controles na tela para testarmos sua funcionalidade:

 

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="AppsBindable.Views.TestePage"
             xmlns:control="clr-namespace:AppsBindable.Constrols;assembly=AppsBindable"
             xmlns:Local="clr-namespace:AppsBindable.ViewModel;assembly=AppsBindable">
  <ContentPage.BindingContext>
    <Local:TesteViewModel />
  </ContentPage.BindingContext>
  <ContentPage.Resources>
    <ResourceDictionary>

    </ResourceDictionary>
  </ContentPage.Resources>
  <StackLayout>
    <control:BindablePicker  x:Name="pckEstado" Title="Estado" ItemsSource="{Binding ListaEstados}" SelectedItem="{Binding Estado, Mode=TwoWay}" />
    <Button x:Name="btnValor" Text="Pegar Valor" Command="{Binding Pegar}"></Button>
    <Label x:Name="lblValorSelecionado" Text="{Binding EstadoSelecionado}"></Label>
  </StackLayout>

 

Pronto, agora é só chamar essa tela no App.cs para teste e ser feliz!

 

public App()
        {
            // The root page of your application
            MainPage = new TestePage();
        }

 

Abordagem #3 – XAML + Binding (Sem custom control)

Nessa abordagem, vamos utilizar o Picker nativo fazendo o Binding apenas com a propriedade SelectedIndex:

 

<Picker x:Name="pckEstado" SelectedIndex="{Binding EstadoID}" Title="Estado">

 

E atribuirmos os valores dos itens de forma iterativa no construtor da página ou no evento OnBindingContext, da seguinte maneira:

 

public RegistrarPage()
        {
            InitializeComponent();

            RegistrarViewModel registrarVM = BindingContext as TesteViewModel;
            if (registrarVM != null)
            {
                this.pckEstado.Items.Clear();
                foreach (var estado in registrarVM.ListaEstado)
                {
                    pckEstado.Items.Add(estado);
                }
            }
        }  

 

Para isso funcionar temos que definir na nossa ViewModel as seguintes propriedades, lembrando que a ViewModel nesse caso deve implementar a interface INotifyPropertyChanged:

 

List<string> _listaEstado;
        public List<string> ListaEstado
        {
            get
            {
                return _listaEstado;
            }
            set
            {
                _listaEstado = value;
                OnPropertyChanged();
            }
        }

public int EstadoID
        {
            get
            {
                return usuario.EstadoID;
            }
            set
            {
                usuario.EstadoID = value;
                usuario.Estado = ListaEstado[value];
                OnPropertyChanged();
            }
        }

public string Estado
        {
            get
            {
                return usuario.Estado;
            }
            set
            {
                usuario.Estado = value;
                OnPropertyChanged();
            }
        }

 

Espero que esse post possa retirar suas dúvidas a respeito do comportamento do Picker que é um controle muito utilizado nos nossos aplicativos.

 

Até o próximo post!

 

Você pode conferir o código em nosso Github:

https://github.com/Studyxnet/AppsBindable

Criando opções de Bindings no componente Picker com Xamarin Forms
5 (100%) 6 votos

Vinicius Reis

Xamarin Student Partner, Xamarin Certified Mobile Developer, MCT, MCSD e apaixonado por novas tecnologias!

7 comentários em “Criando opções de Bindings no componente Picker com Xamarin Forms

  1. Utilizei o tema Material.Light é o meu picker ficou com a letra branca, ficando complicado para ler. TEm como colocar um cor mais escura? O meu layout é feito no Xaml.

  2. Eu estou terminando meu aplicativo e tenho notado que quando clico em botão que inicia uma navegação para outra view, ele da um travadinha e segundos depois abre a proxima view. Minhas views possuem muitos stacklayout, controles e um grid. Você acha que isto pode estar fazendo demorar(leves travadas) a renderizar a view?

    O curioso tb é que estas travadas ocorrem apenas no inicio, apos o uso continua fica normal. Ex: apos iniciar o app clico no botão, tem a travada e vai para a pagina. Se eu clicar nas proximas vezes o processo fica rapido.

  3. Se eu tiver um classe de objeto, exemplo:
    public class Carro
    {
    string Descricao {get;set;}
    int ano {get;set;}
    }

    e eu queria colocar num picker, esse meu objeto carro, como podeira fazer isso?

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

%d blogueiros gostam disto: