Back-End

23 mar, 2017

C# – Apresentando a interface INotifyPropertyChanged

Publicidade

Você sabe o que faz a interface INotifyPropertyChanged? Ela apenas notifica os clientes que um valor de uma propriedade foi alterado.

Acha pouco? Mas ela vai um pouco além… A interface INotifyPropertyChanged proporciona um mecanismo unificado para definir em um único evento as propriedades Changed que queremos definir em nosso objetos.

Vamos pensar um pouco mais sobre isso…

Quando criamos um objeto, um controle ou um componente, geralmente implementamos um sistema para notificar o cliente (aquele que vai usar o controle/objeto) quando alguma de suas propriedades for alterada. Isso é feito escrevendo eventos do tipo PropriedadeChanged para cada propriedade passível de alteração. Ora, isso poderia nos levar a ter que definir uma lista muito extensa de eventos, e todos com a mesma finalidade: notificar que o conteúdo de uma certa propriedade foi alterada.

Pensando nisso, foi introduzida na versão 2.0 da plataforma .NET a interface System.ComponentModel.INotifyPropertyChanged, que proporciona uma mecanismo para reunir em um único evento todos os eventos ‘changed’ de um objeto.

Vamos ver como isso funciona…

Implementando a interface INotifyPropertyChanged

Vamos criar uma aplicação Console Application usando o Visual Studio 2015 Community com o nome UsandoINotifyPropertyChanged.

A seguir, vamos criar uma classe Aluno com duas propriedades: Nome e Nota, um método AlterarNota(), e um construtor.

Abaixo temos o código da classe Aluno:

    public class Aluno
    {
        public string Nome { get; set; }
        public int Nota { get; set; }
        Aluno(string nome, int nota)
        {
            Nome = nome;
            Nota = nota;
        }
        public void AlterarNota()
        {
            Nota++;
        }
    }

Muito simples, não é mesmo? Agora, vamos implementar a interface INotifyPropertyChanged para esta classe.

Obs: Existem outras maneiras de implementar a interface.

using System.ComponentModel;
namespace UsandoINotifyPropertyChanged
{
    public class Aluno : INotifyPropertyChanged
    {
        private string nome;
        public string Nome
        {
            get { return nome; }
            set
            {
                if (nome != value)
                {
                    nome = value;
                    RaisePropertyChanged("Nome");
                }
            }
        }
        private int nota;
        public int Nota
        {
            get { return nota; }
            set
            {
                if (nota != value)
                {
                    nota = value;
                    RaisePropertyChanged("Nota");
                }
            }
        }
        public Aluno(string nome, int nota)
        {
            Nome = nome;
            Nota = nota;
        }
        public void AlterarNota()
        {
            Nota++;
        }
        //-- implementação da interface INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));        
        }
    }
}

Nessa classe, implementamos a interface e definimos um evento (RaisePropertyChanged) que será disparado sempre que o valor de uma propriedade for alterada.

Recebendo notificações

Uma vez que implementamos a interface INotifyPropertyChanged em uma classe, podemos subescrever o evento PropertyChanged para uma instância da sua classe.

Se a implementação da interface foi feita corretamente, o evento será disparado sempre que o valor da propriedade do objeto for alterado.

Para testar vamos incluir o código abaixo no arquivo Program.cs do projeto:

using System;
using System.ComponentModel;
namespace UsandoINotifyPropertyChanged
{
    class Program
    {
        static void Main(string[] args)
        {
            Aluno aluno = new Aluno("Macoratti", 7);
            aluno.PropertyChanged += aluno_PropertyChanged;
            aluno.Nome = "Jose Carlos Macoratti";
            aluno.AlterarNota();
            aluno.Nota = 6;
            Console.ReadLine();
        }
        private static void aluno_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            Console.WriteLine(string.Format("Propriedade {0} acabou de ser alterada...", e.PropertyName));
        }
    }
}

O manipulador de eventos PropertyChanged recebe uma instância de um um objeto PropertyChangedEventArgs, que contém apenas uma propriedade PropertyName que lhe diz que a propriedade mudou.

Ele passa qualquer informação sobre o valor antigo ou sobre os novos valores da propriedade. A suposição é que o código do cliente pode ler o valor da propriedade atualizada por conta própria.

Para o exemplo, estamos alterando o Nome e depois a propriedade Nota duas vezes.

Executando o projeto, iremos obter o seguinte resultado:

Para que a notificação de alteração possa ocorrer em uma ligação entre um cliente e uma fonte de dados, o tipo vinculado deverá:

  • Implementar a interface INotifyPropertyChanged (preferencial)

ou

  • Fornecer um evento de alteração para cada propriedade do tipo vinculado

Nota: A partir da versão 5.0 da linguagem C#, podemos usar o atributo CallerMemberName, do namespace System.Runtime.CompilerServices, para evitar ter que passar o nome da propriedade como  uma string.

Abaixo, temos um exemplo de implementação da interface INotifyPropertyChanged em uma classe Pessoa que tem apenas a propriedade Idade usando o atributo CallerMemberName:

using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace UsandoINotifyPropertyChanged
{
    public class Pessoa : INotifyPropertyChanged
    {
        private int idade;
        public int Idade
        {
            get { return idade; }
            set
            {
                if (idade != value)
                {
                    idade = value;
                    RaisePropertyChanged();
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged([CallerMemberName]string prop = "")
        {
             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
       }
    }
}

Usando este recurso, o código fica mais simples.

Espero que você tenha entendido os fundamentos dessa importante interface.

Pegue o projeto aqui: UsandoINotifyPropertyChanged.zip