Xamarin Forms -   Usando um Bindable Picker (MVVM)  

 Este artigo mostrar como estender a funcionaliade da view Picker criando um Bindable Picker que pemite usar diretamente a propriedade ItemsSource para popular a view usando o Visual Studio com Xamarin e a linguagem C#.

A view Picker permite que você selecione um elemento de uma lista de opções.

No entanto, ela não possui uma propriedade ItemsSource nem SelectedItem, existentes no ListView, e que permitem atribuir valores diretamente, bem como selecionar um item de forma bem simples.

A view Picker disponibiza somente a propriedade SelectedIndex, que é o índice do item selecionado; dessa forma, para obter o valor selecionado temos que usar as informações do SelectedIndex e da propriedade Items. Se nada for selecionado SelectedIndex retorna o valor -1.

Nosso objetivo neste artigo é implementar uma personalização da view Picker defindindo propriedades do tipo BindableProperty como ItemsSource e SelectedItem para que elas funcionem da mesma forma que na ListView.

Este artigo foi baseado no projeto original encontrado neste link :https://oceanware.wordpress.com/2016/06/13/xamarin-forms-bindable-picker/

Recursos usados:

Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.

Criando o projeto no Visual Studio 2015 Community

Abra o Visual Studio Community 2015 e clique em New Project;

Selecione Visual C#, o template Cross Plataform e a seguir Blank App (Xamarin.Forms Portable);

NotaA opção Portable (Portable Class Library - PCL ) - Inclui todo o código comum em uma biblioteca de vínculo dinâmico (DLL) que pode então ser referenciada a partir de outros projetos;

Informe o nome XF_Bindable_Picker e clique no botão OK;

Ao clicar no botão OK, será criada uma solução contendo 4 projetos. (Dependendo do seu ambiente pode haver alguma variação nos projetos.)

O projeto comum possui a classe App.cs que irá conter o código compartilhado e que vamos usar neste artigo.

Ao final teremos as referências incluídas em todos os projetos da nossa solução.

A seguir clique no menu Project e em Add New Item;

Selecione Cross Platform e o template Forms Xaml Page e informe o nome MainPage.xaml:

Esta será a página da nossa aplicação.

Então vamos abrir o arquivo App.cs e alterar o código conforme abaixo:

using Xamarin.Forms;
namespace XF_Bindable_Spinner
{
    public class App : Application
    {
        public App()
        {
            MainPage = new NavigationPage(new MainPage());
        }
        protected override void OnStart()
        {
            // Handle when your app starts
        }
        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }
        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

Aqui definimos a página MainPage como a página que vai iniciar a nossa aplicação.

Definindo a classe personalizada para criar o Bindable Picker

Vamos criar uma classe que herda da view Picker e vamos definir as propriedades ItemsSource e SelectedItem e eventos que irão tratar as modificações dos valores.

Selecione o projeto e no menu Project clique me New Folder e Informe o nome Extensions;

Clique com o botão direito do mouse sobre a pasta Extensions e a seguir em Add Class;

Informe nome BindablePicker e inclua o código abaixo neste classe:

using System;
using System.Collections;
using Xamarin.Forms;
namespace XF_Bindable_Spinner.Extensions
{
    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());
            }
        }
    }
}

Nesta classe (que foi obtida criada com base na original do link https://github.com/Oceanware/XamarinFormsBindablePicker) criamos duas BindableProperties :

Definimos também os seguintes eventos:

Definindo a ViewModel : MainPageViewModel

Vamos agora definir a ViewModel - MainPageViewModel - que é uma classe que orquestra entre a View e Model. As ViewModels são projetadas para serem tão simples quanto possível, sem lógica de negócio dentro delas, mas pouca lógica para lidar com o roteamento de mensagens de/para as Views e outros Modelos usados no aplicativos.

No menu Project clique em Add Class e informe o nome MainPageViewModel, a seguir inclua o código abaixo nesta classe:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Xamarin.Forms;
namespace XF_Bindable_Spinner
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public ICommand SelecionarCommand { get; set; }
        public MainPageViewModel()
        {
            ListaEstados = new ObservableCollection<string>();
            ListaEstados.Add("São Paulo");
            ListaEstados.Add("Rio de Janeiro");
            ListaEstados.Add("Espírito Santo");
            ListaEstados.Add("Minas Gerais");
            ListaEstados.Add("Paraná");
            ListaEstados.Add("Rio Grande do Sul");
            ListaEstados.Add("Santa Catarina");
            ListaEstados.Add("Rio Grande do Sul");
            SelecionarCommand = new Command(SelecionarCmd);
        }
        private void SelecionarCmd()
        {
            if (!string.IsNullOrEmpty(Estado))
            {
                EstadoSelecionado = Estado;
            }
            else
            {
                EstadoSelecionado = "Selecione um Estado";
            }
        }
        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();
            }
        }
    }
}

A nossa viewmodel implementa a interface INotifyPropertyChanged e define um comando usando a interface ICommand que permite fazer chamadas direta para a ViewModel.

Definimos as propriedades ListaEstados, Estado e EstadoSelecionado que iremos usar para fazer a vinculação dos dados no Picker, e obter o item selecionado.

No construtor da classe estamos populando a view Picker com nomes de alguns estados.

Definindo o código da View MainPage

Vamos agora definir o código da MainPage onde iremos criar dois namespaces no código XAML:

  1.  xmlns:control="clr-namespace:XF_Bindable_Spinner.Extensions"  => namespace definido para usar a classe BindablePicker na pasta Extensions;
  2.  xmlns:local="clr-namespace:XF_Bindable_Spinner" => namespace definido para usar a nossa ViewModel referenciando-a no código XAML;

Abaixo temos o código completo da página MainPage:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:control="clr-namespace:XF_Bindable_Spinner.Extensions"
             xmlns:local="clr-namespace:XF_Bindable_Spinner"
             x:Class="XF_Bindable_Spinner.MainPage"
             Title="Usando Picker">
    <ContentPage.BindingContext>
        <local:MainPageViewModel />
    </ContentPage.BindingContext>
    
    <StackLayout>
        <Picker x:Name="pckSexo" Title="Selecione o sexo"/>
        <control:BindablePicker  x:Name="pckEstados" Title="Selecione um estado" 
              ItemsSource="{Binding ListaEstados}" 
              SelectedItem="{Binding Estado, Mode=TwoWay}" />
        <Button x:Name="btnItem" Text="Obter Item Selecionado" Command="{Binding SelecionarCommand}" />
        <Label x:Name="lblItemSelecionado" Text="{Binding EstadoSelecionado}" />
    </StackLayout>
</ContentPage>

Definimos uma instância do nosso ViewModel atribuindo à propriedade BindingContext.

A seguir definimos um StackLayout onde usamos um controle Picker normal e a seguir usamos o controle personalizado BindablePicker onde definimos a propriedade ItemsSource vinculando-a a ListaEstados, e o SelectedItem á propriedade Estado usando o databinding TwoWay.

A seguir definimos um Button onde usamos o comando SelecionarCommand e uma Label onde vinculamos a propriedade EstadoSelecinado.

Para concluir temos o código do arquivo MainPage.xaml.cs onde definimos os itens da view Picker pckSexo:

using Xamarin.Forms;
namespace XF_Bindable_Spinner
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            pckSexo.Items.Add("Masculino");
            pckSexo.Items.Add("Feminino");
        }
    }
}

Executando o projeto iremos obter o seguinte resultado:

A tela de apresentação

O picker normal exibindo as opções de sexo

O picker personalizado exibindo a lista de Estados

Pegue o projeto completo aqui :  XF_Bindable_Picker.zip (sem as referências)

"Porque a lei foi dada por Moisés; a graça e a verdade vieram por Jesus Cristo."
Joao 1:17

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti