Descomplicando MVVM INotifyPropertyChanged no Xamarin Forms

O objetivo é descomplicar a parte do MVVM INotifyPropertyChanged no Xamarin Forms para que não seja necessário ficar herdando de classes básicas e manipulando o setter de cada propriedade da ViewModel.

Lembre-se que o código exposto aqui é de carácter exemplificativo apenas para demonstrar uma alternativa aos métodos normais para trabalhar com MVVM.

Atualmente existem frameworks para trabalhar com MVVM no Xamarin Forms, o Prism é um deles. Aguardo com grande expectativa a palestra de Angelo Belchior no evento Xamarin Summit Brasil 2017.

 
Xamarin Summit Brasil 2017 Preview: Guia Completo

 

O que precisamos?

Visual Studio 2015 ou 2017, pode ser community mesmo não tem problema;
– Projeto CROSS Platform Xamarin Forms com XAML para as telas;
– Fody PropertyChanged que pode ser baixada via nuget;

Observação:
Esse artigo espera que você já fez alguma implementação com o design pattern MVVM no Xamarin Forms.

Modelo tradicional MVVM INotifyPropertyChanged no Xamarin Forms:

public class TradicionalPageViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private string _titulo;
        public string Titulo
        {
            get
            {
                return _titulo;
            }
            set
            {
                if (_titulo != value)
                {
                    _titulo = value;
                    NotifyPropertyChanged();
                }
            }
        }

        private string _nome;
        public string Nome
        {
            get
            {
                return _nome;
            }
            set
            {
                if (_nome != value)
                {
                    _nome = value;
                    NotifyPropertyChanged();
                }
            }
        }

        private int _idade;
        public int Idade
        {
            get
            {
                return _idade;
            }
            set
            {
                if (_idade != value)
                {
                    _idade = value;
                    NotifyPropertyChanged();
                }
            }
        }
    }

O código acima é o modelo tradicional, ou seja, o modelo “espartano” onde você precisará para cada propriedade, colocar todas as regras do setter de cada propriedade da sua ViewModel, além de implementar a interface INotifyPropertyChanged com o evento que notificará a tela de mudanças na ViewModel.

É claro que o modelo acima não segue os princípios de DRY (Don’t Repeat Yourself), então para facilitar isso temos algumas alternativas, uma delas é demonstrada abaixo pela galera da Maratona Xamarin Brasil, especificamente no vídeo de MVVM do Alexandre Chohfi.

Alternativas MVVM INotifyPropertyChanged no Xamarin Forms:

public class MaratonaPageViewModel : BaseViewModel
    {
        private string _titulo;
        public string Titulo
        {
            get
            {
                return _titulo;
            }
            set
            {
                SetProperty(ref _titulo, value);
            }
        }

        private string _nome;
        public string Nome
        {
            get
            {
                return _nome;
            }
            set
            {
                SetProperty(ref _nome, value);
            }
        }

        private int _idade;
        public int Idade
        {
            get
            {
                return _idade;
            }
            set
            {
                SetProperty(ref _idade, value);
            }
        }
    }

Alexandre Chohfi criou uma classe básica e alguns métodos para serem utilizados em cada propriedade da ViewModel facilitando assim o uso e repetindo menos código. Com certeza o código ficou bem clean e fácil de usar.


 

Classe BaseViewModel da Maratona Xamarin Brasil:

public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs((propertyName)));
        }

        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(storage, value))
            {
                return false;
            }
            storage = value;
            OnPropertyChanged(propertyName);

            return true;
        }
    }

Nessa madrugada tive uma ideia de simplificar essa parada de INotifyPropertyChanged, então acordei cedo e comecei a dar uma fuçada, e não fiquei surpreso, já existe algo prontinho para facilitar isso.

Então, para aqueles programadores mais ecléticos, existe uma alternativa mais simples ainda, estou falando da biblioteca Fody PropertyChanded.

MVVM INotifyPropertyChanged com Fody PropertyChanged no Xamarin Forms:

[ImplementPropertyChanged]
    public class HomePageViewModel
    {
        public string Titulo { get; set; }
        public string Nome { get; set; }
        public int Idade { get; set; }
    }

Como pode ver acima, mais simples que isso realmente eu não sei se existe. Basta colocarmos o atributo [ImplementPropertyChanged] na ViewModel e em tempo de compilação, o Fody PropertyChanged irá colocar o código necessário no setter de cada propriedade pública da ViewModel.

Lembre-se que essa parada aí não é dinâmica, ou seja, não afetará a performance do seu aplicativo pois é em tempo de compilação e não execução. Não acredita? Veja o código abaixo pego do .NET Reflector:

namespace FSL.XF5.ViewModels
{
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Threading;

    public class HomePageViewModel : INotifyPropertyChanged
    {
        [DebuggerBrowsable((DebuggerBrowsableState) DebuggerBrowsableState.Never), CompilerGenerated]
        private string <Titulo>k__BackingField;

        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if (propertyChanged != null)
            {
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public string Titulo
        {
            [CompilerGenerated]
            get
            {
                return this.<Titulo>k__BackingField;
            }
            [CompilerGenerated]
            set
            {
                if (!string.Equals(this.<Titulo>k__BackingField, value, (StringComparison) StringComparison.Ordinal))
                {
                    this.<Titulo>k__BackingField = value;
                    this.OnPropertyChanged("Titulo");
                }
            }
        }
    }
}

O código dessa implementação está no meu GitHub e você pode baixar logo abaixo.

Descomplicando INotifyPropertyChanged: Críticas ou sugestões são sempre bem vindas.

Para saber mais sobre o Fody PropertyChanged clique aqui.

Um feedback importante de um colega e membro da comunidade:

“Em adição ao bem disposto conteúdo, ressalto da existência de um procedimento que precisa ser executado quando utilizamos IDE como o Xamarin Studio. Neste, após a instalação do pacote Nuget e da criação do arquivo FodyWeavers.xml na raiz do projeto, faz-se necessário a adição de uma TAG XML simples, para que o processamento do PropertyChanged seja feito corretamente, é necessário incluir a TAG abaixo:

<PropertyChanged  />

Também importante estar atento nas atualizações do Fody e do pacote PropertyChanged, pois para aqueles focados no pacote PropertyChanged, atualizar o Fody somente quando a atualização for demandada pelo próprio PropertyChanged, do contrário manter a biblioteca Fody como está. Usuários das versões 5 e/ou superior do mono, obrigatoriamente precisam da última versão do pacote PropertyChanged (juntamente com a última do Fody – pela dependência), para resolução de conflitos com a dependência Cecil (do Mono).” Rodrigo Amaro

Para saber mais sobre a Maratona Xamarin Brasil, acesse o grupo no facebook , lembrando que ela está no nível intermediário. Salve salve Angelo Belchior, William S. Rodriguez, Alexandre Chohfi, William Barbosa e Valério Ferreira.

Boa sorte e bons estudos 😉

Faça download completo do código fonte no github.
Sobre o Autor:
Trabalha como arquiteto de soluções e desenvolvedor, tem mais de 16 anos de experiência em desenvolvimento de software em diversas plataformas sendo mais de 14 anos somente para o mercado de seguros.
Revisado por:
Apaixonado por tecnologia e sempre disposto a encarar novos desafios, atualmente trabalho focado em aplicações web e mobile com a plataforma .NET, e me aventurando nas diversas linguagens, desafios e experiências que a área nos proporciona.

Olá! Sou um entusiasta da tecnologia especialmente quando esta é usada para trazer soluções inteligentes a problemas comuns. Desenvolvedor de sistemas a 16 anos e destes os grandes desafios foram no mercado de seguros. Atuando com C#, MVC, SQL e ingressando no mercado de Xamarin.

  • Levy Furst Neto

    show!

  • Mariano Junior

    Show de bola! Menos código pra resolver o mesmo problema.

    • @marianojunior:disqus legal neh?! É ideia é essa mesmo. Aí fica a critério de quem quiser usar ou não 🙂

  • Alex Fabiano Ribeiro

    Ótimo artigo! Parabéns

  • Douglas Modesto

    Muito prático … Agiliza no dia a dia dando mais produtividade. Obrigado por compartilhar. Parabéns, ótimo artigo.