WPF - Usando o padrão MVVM


 Neste artigo vou mostrar como usar o padrão de projeto MVVM em aplicações WPF.

O padrão MVVM é um padrão de design de interface de usuário criado por John Gossman com base no padrão Presenter Model de Martin Fowler. Este padrão também é usado em aplicações Xamarin.

O padrão Model-View-ViewModel permite aos desenvolvedores separar completamente a interface do usuário lógica de negócios que acessa os dados. A separação da interface do usuário da lógica de negócios e dos dados permitem criar um projeto robusto, limpo e testável.

O DataBinding da WPF é extremamente poderoso porque permite separar a interface de usuário da lógica de negócios.

Neste artigo veremos um exemplo que não usa o código no code-behind. No entanto, isso não é necessário para implementar o padrão MVVM. O que importa para o MVVM é que você quer desacoplar sua View do seu Model fazendo com que a comunicação entre os dois sejam feita via ViewModel.

O propósito desta arquitetura desacoplada é permitir que você altere facilmente a View ou o modelo sem quebrar o código existente. Você também quer poder testar completamente todo o seu código sem se preocupar com o uso de ferramentas difíceis porque você criou uma View XAML fortemente acoplada com a sua logíca de negócios.

Recursos Usados

Criando o projeto WPF

Abra o VS 2015 Community e crie um novo projeto (File-> New Project) usando a linguagem C# e o template Windows Classic Desktop e a seguir WPF Application;

Informe um nome a seu gosto. Eu vou usar o nome Wpf_Mvvm:

Definindo o Model

Crie uma pasta chamada Model no projeto e nesta pasta inclua a classe Contato.cs e inclua o código a seguir nesta classe:

using System.ComponentModel;
namespace Wpf_Mvvm.Model
{
    public class Contato : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        // Esta rotina é chamada cada vez que o valor da propridade 
        // for definida. Isso vai disparar um evento para notificar 
        // a WPF via data binding que algo mudou
        private void OnPropertyChanged(string nomePropriedade)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nomePropriedade));
        }
        private string _nome;
        private string _sobrenome;
        private string _telefone;
        private string _email;
        public string Nome
        {
            get { return _nome; }
            set
            {
                _nome = value;
                OnPropertyChanged("Nome");
            }
        }
        public string Email
        {
            get { return _email; }
            set
            {
                _email = value;
                OnPropertyChanged("Email");
            }
        }
        public string Sobrenome
        {
            get { return _sobrenome; }
            set
            {
                _sobrenome = value;
                OnPropertyChanged("Sobrenome");
            }
        }
        public string Telefone
        {
            get { return _telefone; }
            set
            {
                _telefone = value;
                OnPropertyChanged("Telefone");
            }
        }
    }
}

Temos na classe Contato uma objeto CLR simples que implementa a interface INotifyPropertyChanged e que representa o Model no MVVM. A implementação da interface vai fazer com que toda vez que ocorrer uma alteração o nos valores das propriedades o evento PropertyChangedEventHandler seja disparado.

Definindo a ViewModel

Crie uma pasta chamada ViewModel no projeto e nesta pasta inclua a classe ContatoViewModel.cs e inclua o código a seguir nesta classe:

using System.Collections.ObjectModel;
using Wpf_Mvvm.Model;
namespace Wpf_Mvvm.ViewModel
{
    public class ContatoViewModel : ObservableCollection<Contato>
    {
        public ContatoViewModel()
        {
            PreparaContatoCollection();
        }
        private void PreparaContatoCollection()
        {
            var Contato1 = new Contato
            {
                Nome = "Jose Carlos",
                Sobrenome = "Macoratti",
                Email = "macoratti@yahoo.com",
                Telefone = "012-8789-0200"
            };
            Add(Contato1);
            var Contato2 = new Contato
            {
                Nome = "Bruno",
                Sobrenome = "Silveira",
                Email = "brunosilv@email.com",
                Telefone = "021-9987-3458"
            };
            Add(Contato2);
            var Contato3 = new Contato
            {
                Nome = "Jonatas",
                Sobrenome = "Sanches",
                Email = "jonsanch@email.com",
                Telefone = "011-8975-57898"
            };
            Add(Contato3);
        }
    }
}

 

A nossa classe ContatoViewModel obterá os dados do nosso modelo e apresentará os dados para a view através do databinding.

A ViewModel herda de uma classe chamada ObservableCollection<>. que é uma classe genérica que aceita nosso modelo como o tipo genérico.

Ela basicamente transforma nosso ViewModel em uma coleção de objetos Contato com notificações de alteração incorporadas para facilitar os mecanismos de databinding do WPF. Quando usamos ObservableCollection, o databinding sabe quando itens são adicionados ou removidos.

Neste código definimos o método PreparaContatoCollection() que cria 3 instãncias da classe Contato e as adiciona à coleção interna da ViewModel. Vamos vincular uma propriedade ItemsSource do controle ListView ao ViewModel e também vincular a propriedade DataContext da Grid com a ViewModel.

Ao configurar a propriedade DataContext da Grid faremos com que os controles filhos herdam o DataContext para fazer o DataBinding.

A propriedade ItemsSource do ListView vai preencher o controle com cada item existente em nosso ObservableCollection<Contato>.

Definindo a View

Vamos agora definir a View da nossa aplicação abrindo o arquivo MainWindow.xaml e incluir o código abaixo neste arquivo:

<Window x:Class="Wpf_Mvvm.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        xmlns:viewModel="clr-namespace:Wpf_Mvvm.ViewModel"
        Title="ContatoMVVM" Height="300" Width="300">
    
    <Window.Resources>
        <viewModel:ContatoViewModel x:Key="contatoViewModel" />
    </Window.Resources>
    <Grid DataContext="{StaticResource ResourceKey=contatoViewModel}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="93*" />
            <RowDefinition Height="29*" />
            <RowDefinition Height="27*" />
            <RowDefinition Height="30*" />
            <RowDefinition Height="81*" />
        </Grid.RowDefinitions>
        <ListView Grid.ColumnSpan="2" BorderThickness="2" x:Name="lstContatos" 
                  IsSynchronizedWithCurrentItem="True" 
                  ItemsSource="{StaticResource ResourceKey=contatoViewModel}" 
                  DisplayMemberPath="Nome" 
                  Margin="0,0,0,28" 
        Grid.RowSpan="2" />
        <TextBlock Grid.Column="0" Grid.Row="1" Text="Nome" />
        <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding Path=Nome}" />
        <TextBlock Grid.Column="0" Grid.Row="2" Text="Sobrenome" />
        <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Path=Sobrenome}" />
        <TextBlock Grid.Column="0" Grid.Row="3" Text="Email" />
        <TextBox Grid.Column="1" Grid.Row="3" Text="{Binding Path=Email}" />
        <TextBlock Grid.Column="0" Grid.Row="4" Text="Telefone" />
        <TextBox Grid.Column="1" Grid.Row="4" Text="{Binding Path=Telefone}" />
    </Grid>
</Window>

 

Observe que definimos a propriedade DataContext da Grid vinculada ao recurso estático do ViewModel que criamos no dicionário. O DataContext fornece um contexto vinculativo para os controles WPF e  quando configuramos o DataContext na Grid, esse valor se propagará para os elementos filhos através da herança de propriedade - é por isso que todos os valores vinculados ao TextBox podem ser configurados para propriedades do modelo.

Isso ocorre porque o DataContext está definido para o nosso ViewModel, que é um ObservableCollection<Contato>. Então, quando estabelecemos nossos caminhos de ligação, a WPF sabe estamos tratando com um objeto Contato e os valores são mapeados para as propriedades corretas.

Executando o projeto iremos obter o resultado abaixo:

Criamos uma janela WPF vinculada aos dados do nosso objeto Contato. Você pode atualizar os valores dos TextBox e eles serão alterados no ListView, e ao clicar no ListView os valores sreão atualizados com base na sua seleção.

Assim a interface do usuário esta 100% vinculada aos dados e não escrevemos nenhum manipulador de eventos no code-behind, fizemos isso usando código XAML. Note que o resource dictionaries não esta limitado aos objetos CLR podemos usar controles de terceiros, styles, type converters ou qualquer outro tipo de objeto na marcação XAML.

Pegue o projeto completo aqui :  Wpf_Mvvm.zip

"Se dissermos que temos comunhão com ele (Deus), e andarmos em trevas, mentimos, e não praticamos a verdade."
1 João 1:6

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 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

 

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

 

Referências:


José Carlos Macoratti