MVVM

Usando o padrão MVVM no Windows 8

Laurent Bugnion

Baixar o código de exemplo

Qualquer programador com experiência anterior em qualquer estrutura baseada em XAML provavelmente já ouviu falar do padrão MVVM (Model-View-ViewModel). Alguns o têm usado extensivamente em todos os aplicativos do Windows Presentation Foundation (WPF), Silverlight ou Windows Phone. Outros o têm evitado, ou porque não sabem exatamente o que o padrão faz, ou porque não querem acrescentar que consideram um novo nível de complexidade aos seus aplicativos.

Você não tem de usar o padrão MVVM para criar aplicativos baseados em XAML. É absolutamente possível usar padrões tradicionais, tais como interações baseadas em eventos, para criar aplicativos atraentes. No entanto, padrões dissociados como o MVVM oferecem algumas vantagens. Notavelmente, o padrão MVVM pode melhorar imensamente a experiência no Expression Blend e facilitar o fluxo de trabalho designer-desenvolvedor.

Recentemente — e especialmente com a extensão do XAML para novas plataformas, como Windows Phone e, claro, Windows 8 — o uso do MVVM evoluiu para um nível totalmente novo, de um padrão de nicho que apenas alguns codificadores entusiastas usavam, para uma prática de mainstream incentivada pela Microsoft.

Pré-condições

Este artigo demonstra como usar o padrão MVVM juntamente com o MVVM Light Toolkit, um conjunto de ferramentas de código aberto que facilita operações comuns em aplicativos baseados em XAML. Para seguir os exemplos, é necessário ter o Visual Studio 2012 e a versão mais recente do MVVM Light Toolkit. Observe que você pode usar a edição Express do Visual Studio 2012, que está disponível gratuitamente. É claro que qualquer outra edição também pode ser usada.

O Visual Studio 2012 pode ser baixado do site bit.ly/vs12rc (edições Ultimate, Premium ou Professional). A edição Express gratuita pode ser baixada do site bit.ly/vs12express.

O instalador do MVVM Light Toolkit pode ser baixado da seção Download do site mvvmlight.codeplex.com. Depois de instalar o MSI, uma página de arquivo Leiame será aberta e você poderá optar por instalar os modelos de projeto e item da versão do Visual Studio que está usando.

O padrão MVVM no Windows 8

O Windows 8 conta com um novo conjunto de APIs chamado Tempo de Execução do Windows (WinRT). Há três maneiras possíveis (às vezes chamadas de "projeções") de se programar aplicativos executando o Tempo de Execução do Windows.

A primeira maneira é provavelmente a mais intuitiva para pessoas com conhecimento em outras estruturas baseadas em XAML, como WPF, Silverlight ou Windows Phone. Ela usa XAML como front-end, e C# ou Visual Basic para sua lógica. Embora haja poucas diferenças entre a projeção XAML/C#/Visual Basic do Silverlight e do WinRT, as habilidades e a maioria dos conceitos são os mesmos. Na verdade, o MVVM é o padrão preferencial para essa projeção, pelas mesmas razões das estruturas mais antigas.

Em segundo lugar, os desenvolvedores familiarizados com HTML e JavaScript também podem codificar aplicativos da Windows Store com uma projeção baseada em HTML. Com a crescente popularidade do MVVM em XAML, desenvolvedores de HTML também quiseram usar a associação de dados em HTML/JavaScript. No entanto, devido à falta de mecanismos de associação de dados, foi necessário começar do zero e recriar essa funcionalidade. Isso é o que estruturas como knockout.js (knockoutjs.com) estão fazendo. Essas estruturas MVVM também podem ser usadas para desenvolver aplicativos da Windows Store.

Também é possível usar uma estrutura própria da Microsoft chamada WinJS. Os controles em WinJS (como GridView, SemanticZoom e assim por diante) são semelhantes aos em XAML e suporta associações de dados também. Para obter mais informações sobre WinJS, consulte bit.ly/winjsbinding. Mais estruturas de associação de dados para JavaScript são detalhadas em bit.ly/jsbinding.

Projeto Hilo (C++ e XAML)

A terceira projeção do WinRT usa XAML como front-end e C++ não gerenciado (sem o Microsoft .NET Framework) para sua lógica. Hilo (bit.ly/hilocode) é um projeto de exemplo dos padrões e práticas da Microsoft que tem o objetivo de demonstrar os vários aspectos da criação de um aplicativo da Windows Store com C++ e XAML.

Devido à disponibilidade de XAML e associação de dados, você pode usar o padrão MVVM com C++ não gerenciado. O Hilo demonstra como usar o MVVM em C++, entre outros temas, como programação assíncrona em C++; como usar blocos; navegação de página; como usar o toque; manipulação de ativação, suspensão e retomada; como criar uma experiência de alto desempenho; como testar o aplicativo; e certificação.

O Hilo vem com o código-fonte integral e a documentação completa. É um bom estudo de caso para desenvolvedores de C++ tradicionais que querem começar no Windows 8 com padrões de desenvolvimento modernos, e para desenvolvedores de C#/Visual Basic que querem usar o desempenho extra da pilha C++.

Um lembrete sobre o MVVM

O padrão MVVM é uma variação de outro padrão de separação bem conhecido chamado Model-View-Controller, ou MVC. Esse padrão é usado em uma infinidade de estruturas, notavelmente a estrutura de aplicativo Web amplamente usada Ruby on Rails, bem como o ASP.NET MVC by Microsoft. Ele é usado não só em aplicativos Web, mas também amplamente de aplicativos de desktop a aplicativos móveis (em iOS, por exemplo).

A principal vantagem de um padrão de separação é que ele atribui responsabilidades claramente definidas para cada uma das camadas. O modelo é a origem dos dados; a exibição é que o usuário vê e usa. Quanto ao controlador, ele é um pouco como o maestro de uma orquestra e coordena as ações e reações do aplicativo. Por exemplo, o controlador é muitas vezes responsável pela coordenação de ações como exibir dados em resposta à entrada do usuário, iniciar e interromper animações e assim por diante.

Com essas responsabilidades claramente definidas, os membros da equipe de desenvolvimento podem se concentrar em cada parte sem pisar um no calo do outro. Da mesma forma, um designer de interação não precisa se preocupar com a criação ou a persistência dos dados e assim por diante.

Uma agradável consequência da separação de preocupações é que aplicativos dissociados também são mais fáceis de testar. Por exemplo, as classes do modelo podem ter suas unidades testadas sem ter de levar em conta o modo de exibição. Como a interação entre o modelo e a exibição é claramente definida e coordenada pelo controlador, é possível simular algumas dessas interações quando necessário para criar condições de teste consistentes. É por isso que a capacidade de teste é frequentemente mencionada como uma das vantagens de se usar o padrão MVVM em aplicativos baseados em XAML.

De MVC para MVVM

Embora o padrão MVC tenha vantagens claras para muitas estruturas, ele não é o mais adequado para estruturas baseadas em XAML devido (ou graças) ao sistema de associação de dados. Essa poderosa infraestrutura pode associar as propriedades de objetos diferentes e mantê-las sincronizadas. Embora isso soe como um simples feito, as implicações são enormes: deixando o sistema de associação de dados cuidar dessa sincronização, o desenvolvedor pode se concentrar na computação do valor das propriedades de objeto dos dados sem ter de se preocupar como atualizar a interface do usuário.

Além disso, a associação é um componente solto. A associação é avaliada apenas sob demanda, e o aplicativo não é corrompido se o resultado da associação for inválido. Essa "liberdade" às vezes pode causar dores de cabeça para os desenvolvedores, pois fica difícil descobrir porque algumas associações não são avaliadas corretamente. É, no entanto, uma vantagem para facilitar o trabalho na interface do usuário sem estar fortemente acoplada a uma estrutura de dados. Com associações soltas, é muito fácil mover os elementos da interface do usuário na exibição e até mesmo alterar completamente a aparência do aplicativo, sem tocar as camadas subjacentes.

Para facilitar a associação de dados e evitar objetos muito grandes, o controlador é dividido em objetos menores, mais finos, chamados ViewModels, ou modelos de apresentação. Um uso comum é combinar uma exibição com um ViewModel, definindo o ViewModel como DataContext da exibição. Na prática, no entanto, esse não é sempre o caso; não é incomum ter várias exibições associadas a determinado ViewModel, ou ter uma exibição complexa dividida em vários ViewModels.

Graças ao uso do XAML para criar a interface do usuário, a associação de dados pode ser expressa de maneira declarada, diretamente no corpo do documento XAML. Isso permite que um processo dissociado, onde o desenvolvedor se preocupa com o modelo e o ViewModel, enquanto um designer de interação assume a criação da experiência do usuário ao mesmo tempo, ou até mesmo em um momento posterior.

Finalmente, como o XAML é baseado em XML, ele funciona bem com ferramentas visuais como o Expression Blend. Quando configurado corretamente, o MVVM permite visualizar dados de tempo de design na tela, o que permite que o designer da experiência do usuário trabalhe sem ter de executar o aplicativo, como mostrado na Figura 1.


Figura 1 Expression Blend para aplicativos da Windows Store com dados de tempo de design

O MVVM Light Toolkit

Uma desvantagem do padrão MVVM é que parte do código necessário é o que às vezes chamamos de "código clichê" — código de infraestrutura que não executa uma função diretamente, mas é necessário para o "encanamento" interno funcionar. Provavelmente o melhor exemplo de código clichê é o código necessário para tornar uma propriedade observável com a implementação da interface INotifyPropertyChanged e seu evento PropertyChanged, como mostrado na Figura 2. Este código mostra que as propriedades automáticas (propriedades com um getter e um setter sem corpo) não podem ser usadas. Em vez disso, a propriedade tem um campo existente. Para evitar a geração do evento PropertyChanged muitas vezes, é feita uma verificação no setter. Depois, se o valor da propriedade mudar, o evento PropertyChanged será gerado.

Figura 2 Propriedade observável

private string _firstName;
public string FirstName
{
  get
  {
    return _firstName;
  }
  set
  {
    if (_firstName == value)
    {
      return;
    }
    _firstName = value;
    var handler = PropertyChanged;
    if (handler != null)
    {
      handler(this, new PropertyChangedEventArgs("FirstName"));
    }
  }
}

Esse é, evidentemente, o pior cenário, onde cada propriedade de um objeto precisa de cerca de 20 linhas de código. Além disso, "cadeias de caracteres mágicas" são usadas para identificar o nome da propriedade, o que pode causar problemas se houver um erro de digitação. Para resolver esse problema, o MVVM Light propõe algumas soluções:

  • A lógica necessária para gerar o evento PropertyChanged pode ser armazenada em uma classe ViewModelBase herdada de cada ViewModel.
  • Propriedades podem ser identificadas por uma expressão lambda em vez de uma cadeia de caracteres. Isso evita erros de digitação ou outros erros quando o nome da propriedade muda.
  • As linhas restantes podem ser automatizadas usando um trecho de código no Visual Studio.

O MVVM Light tem alguns componentes que são úteis para tornar a criação de aplicativos dissociados mais rápida e fácil, como você verá no aplicativo de exemplo proposto ainda neste artigo.

O Windows 8 também apresenta algumas novas classes para ajudar nesse problema, como a classe BindableBase e o atributo CallerMemberName. Infelizmente, eles não estão disponíveis para outras estruturas baseadas em XAML e não podem ser usados em código compartilhado.

Criando um novo aplicativo no Windows 8

A maneira mais fácil de criar um novo aplicativo é iniciar o Visual Studio 12 e selecionar o modelo de projeto MvvmLight (Win8). Depois que o aplicativo é criado, é possível iniciá-lo imediatamente, pressionando Ctrl-F5. A página principal é mínima e simplesmente exibe a mensagem de boas-vindas do MVVM Light, como mostrado na Figura 3.


Figura 3 Criando o novo aplicativo MVVM Light

O mais interessante é abrir o mesmo aplicativo no Visual Studio Designer: No Gerenciador de Soluções, clique com botão direito em MainPage.xaml e selecione Exibir Designer. Carregar as imagens pela primeira vez demora um pouco, mas depois que tudo estiver pronto, a tela mostra “Bem-vindo ao MVVM Light [design]”. Abrir o aplicativo no Expression Blend também mostra o mesmo resultado: clique com o botão direito no mesmo arquivo e selecione Abrir no Blend para ver o texto do tempo de design na janela. Observe que o Expression Blend para aplicativos da Windows Store é instalado junto com o Visual Studio 2012 (até mesmo na edição Express). Assim como no Windows Phone antes, agora é possível usar o Expression Blend sem custo.

O que acaba de acontecer tem algumas implicações interessantes: O Visual Designer executa partes do aplicativo e não há uma maneira de descobrir se o aplicativo está sendo executado no designer ou não. Ver uma exibição diferente no Visual Designer do que no tempo de execução é um requisito fundamental para uma boa experiência durante o design de interação. Isso permitirá ignorar chamadas de serviço Web ou conexões de banco de dados que não funcionariam no tempo de design. Isso também permite a criação de dados conhecidos — por exemplo, textos muito longos para verificar como o layout ficaria em diferentes orientações ou resoluções sem ter de executar o aplicativo. Isto poupa tempo e muitos problemas durante a fase do design de interação.

O aplicativo que está sendo desenvolvido é um visualizador para os amigos de um usuário, conectando a um serviço Web inspirado pelo Facebook (mas bem mais simplificado). O serviço Web retorna uma cadeia de caracteres formatada em JSON com informações sobre o amigo do usuário, como nome e sobrenome, data de nascimento, URI para uma foto de perfil e assim por diante. Essas informações são armazenadas em uma instância do tipo Friend criada na camada de modelo (o primeiro "M" em MVVM). A classe Friend é herdada da classe ObservableObject fornecida pelas bibliotecas do MVVM Light (referenciadas pelo novo aplicativo). Isso permite que a classe Friend gere facilmente o evento PropertyChanged. Note que isso faz sentido mesmo que Friend pertença à camada de modelo — permite que a interface do usuário seja associadas aos dados das propriedades de Friend sem ter de duplicar essas propriedades na camada ViewModel.

Como mencionei anteriormente, a implementação de propriedades observáveis requer um código clichê, que é irritante porém mitigado pelo MVVM Light: Use um trecho de código para adicionar uma propriedade INPC (para INotifyPropertyChanged, a interface que define o evento PropertyChanged). Simplesmente digite mvvminpcset e pressione Tab para expandir o trecho de código. Use Tab para ir de campo em campo: digite o nome da propriedade (FirstName), seu tipo (string), nome do campo existente (_firstName) e, finalmente, o valor padrão (string.Empty). Digite Esc para sair do modo de edição do trecho. Além disso, o trecho adiciona uma constante com nome da propriedade. Isso será útil mais tarde quando registrarmos um evento PropertyChanged.

Todos os trechos do MVVM Light começam com mvvm, o que torna conveniente encontrá-los no IntelliSense. Existem alguns outros trechos mvvminpc, para variações de implementação da propriedade. Usando mvvminpcset, você também pode implementar uma propriedade observável denominada LastName do tipo string.

Propriedades como FirstName e LastName são bastante simples. Às vezes, no entanto, o formato de dados que o aplicativo obtém do serviço Web não é o ideal, e uma conversão precisa ser feita. No desenvolvimento convencional baseado em XAML, os desenvolvedores às vezes usam um conversor (implementação de IValueConverter). No MVVM, no entanto, a maioria dos conversores pode ser substituída por propriedades simples. Por exemplo, vamos considerar a data de nascimento. O campo JSON está no formato “MM/DD/AAAA” que é a forma de expressar datas nos EUA. No entanto, o aplicativo pode ser executado em qualquer localidade. Portanto, é necessária uma conversão.

Vamos começar adicionando uma propriedade observável do tipo string, denominada DateOfBirthString, usando o mesmo trecho mvvminpcset que foi usado antes. Em seguida, adicione outra propriedade, como mostrado aqui (esta propriedade usa DateOfBirthString como campo existente; é responsável por converter o valor em um DateTime adequado):

public DateTime DateOfBirth
{
  get
  {
    if (string.IsNullOrEmpty(_dateOfBirthString))
    {
      return DateTime.MinValue;
    }
    return DateTime.ParseExact(DateOfBirthString, "d",
      CultureInfo.InvariantCulture);
  }
  set
  {
    _dateOfBirthString = value.ToString("d",
      CultureInfo.InvariantCulture);
  }
}

Mais uma coisa é necessária, porém: Sempre que DateOfBirthString muda, o evento PropertyChanged precisa ser gerado para DateOfBirth também. Dessa forma, as associações de dados consultarão o valor e forçarão uma conversão novamente. Para fazer isso, modifique o setter da propriedade DateOfBirthString, conforme mostrado no código a seguir:

set
{
  if (Set(DateOfBirthStringPropertyName, 
    ref _dateOfBirthString, value))
  {
    RaisePropertyChanged(() => DateOfBirth);
  }
}

O método ObservableObject Set do MVVM Light retorna true se o valor mudar. Esta é a sugestão para gerar o evento PropertyChanged para a propriedade DateOfBirth também! Esse mecanismo de conversão é bastante conveniente. O aplicativo de exemplo usa-o em alguns lugares, como para converter a URL da imagem do perfil (salva como uma cadeia de caracteres) em URI, por exemplo.

Implementação e simulação do serviço de dados

O aplicativo já tem um simples DataService que pode ser reutilizado para se conectar ao serviço de dados reais. O serviço Web é um simples manipulador HTTP .NET que retorna um arquivo no formato JSON. Graças ao uso do padrão de programação assíncrona introduzido no .NET Framework 4.5 (palavra-chave async/await), conectar ao serviço Web é muito simples, como mostra a Figura 4 (junto com a interface IDataService). A conexão acontece de maneira assíncrona, como a mostra o nome do método SendAsync. No entanto, graças à palavra-chave await, o método não precisa de um retorno de chamada que tornaria o código mais complexo.

Figura 4 Conectando ao serviço Web e desserializando o resultado JSON<

public interface IDataService
{
  Task<IList<Friend>> GetFriends();
}
public class DataService : IDataService
{
  private const string ServiceUrl
    = "http://www.galasoft.ch/labs/json/JsonDemo.ashx";
  private readonly HttpClient _client;
  public DataService()
  {
    _client = new HttpClient();
  }
  public async Task<IList<Friend>> GetFriends()
  {
    var request = new HttpRequestMessage(
      HttpMethod.Post,
      new Uri(ServiceUrl));
    var response = await _client.SendAsync(request);
    var result = await response.Content.ReadAsStringAsync();
    var serializer = new JsonSerializer();
    var deserialized = serializer.Deserialize<FacebookResult>(result);
    return deserialized.Friends;
  }
}

Finalmente, depois de a cadeia de caracteres JSON ter sido recuperada, um serializador JSON é usado para desserializar a cadeia de caracteres em um objeto .NET do tipo FacebookResult. Essa classe é apenas um auxiliar que será descartado quando o método retornar.

O MVVM Light também inclui um simples contêiner de inversão de controle (IOC) chamado SimpleIoc. Um contêiner IOC é um componente útil não só em aplicativos MVVM, mas em qualquer arquitetura dissociada. O contêiner IOC atua como cache para instâncias que podem ser criadas sob demanda e resolvidas em vários locais no aplicativo.

O DataService implementa a interface IDataService. Graças ao contêiner IOC, é fácil simular o serviço de dados e criar dados de tempo de design usados no designer. Essa classe chama-se DesignDataService, conforme mostrado na Figura 5.

Figura 5 Serviço de dados de tempo de design

public class DesignDataService : IDataService
{
  public async Task<IList<Friend>> GetFriends()
  {
    var result = new List<Friend>();
    for (var index = 0; index < 42; index++)
    {
      result.Add(
        new Friend
        {
          DateOfBirth = (DateTime.Now - TimeSpan.FromDays(index)),
          FirstName = "FirstName" + index,
          LastName = "LastName" + index,
          ImageUrl = "http://www.galasoft.ch/images/el20110730009_150x150.jpg"
        });
    }
    return result;
  }
}

Como registrar e chamar os serviços

Agora que os serviços foram implementados, está na hora de instanciá-los e criar os ViewModels. Essa é a tarefa da classe ViewModelLocator. Essa classe é muito importante para a estrutura de aplicativo habilitada pelo MVVM Light. Ela é criada como um recurso XAML no arquivo App.xaml. Isso cria o vínculo importante entre a marcação XAML e o código-fonte, permitindo que os designers visuais criem os ViewModels e executem o código de tempo de design. O registro é mostrado na Figura 6.

Figura 6 Registrando os serviços e ViewModels

static ViewModelLocator()
{
  ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  if (ViewModelBase.IsInDesignModeStatic)
  {
    SimpleIoc.Default.Register<IDataService, 
      Design.DesignDataService>();
    SimpleIoc.Default.Register<INavigationService,
      Design.DesignNavigationService>();
  }
  else
  {
    SimpleIoc.Default.Register<IDataService, DataService>();
    SimpleIoc.Default.Register<INavigationService>(() => 
      new NavigationService());
  }
  SimpleIoc.Default.Register<MainViewModel>();
}

Como o construtor MainViewModel usa IDataService e INavigationService como parâmetros, o contêiner SimpleIoc é capaz de criar todos os objetos automaticamente. O MainViewModel é exposto como uma propriedade do ViewModelLocator e os dados são associados em XAML no DataContext da MainPage. Essa associação já é criada no modelo de projeto do MVVM Light. Quando a página é aberta no Expression Blend, a associação de dados é resolvida, a instância do MainViewModel é criada (se necessário) e o construtor é executado, com a instância correta do DataService (no tempo de execução ou em tempo de design).

A ação de chamar o serviço de dados é exposta com um RelayCommand, mostrado na Figura 7. Essa classe é um componente do MVVM Light Toolkit que implementa a interface ICommand e oferece uma maneira fácil para associar a propriedade Command de um elemento de interface do usuário (como um botão) a um método implementado no ViewModel.

Figura 7 A classe RelayCommand

private RelayCommand _refreshCommand;
public RelayCommand RefreshCommand
{
  get
  {
    return _refreshCommand
      ?? (_refreshCommand = 
      new RelayCommand(ExecuteRefreshCommand));
  }
}
private async void ExecuteRefreshCommand()
{
  var friends = await _dataService.GetFriends();
  if (friends != null)
  {
    Friends.Clear();
    foreach (var friend in friends)
    {
      Friends.Add(new FriendViewModel(friend, _schema));
    }
  }
}

A coleção Friends à qual são adicionados os amigos é do tipoObservableCollection<FriendViewModel>. Esse tipo de coleção é usado frequentemente em estruturas baseadas em XAML, porque qualquer controle de lista associado a dados dessa coleção automaticamente atualiza sua exibição quando seu conteúdo é alterado. Em vez de armazenar diretamente a instância da classe Friend do modelo na coleção, eles são envolvidos em outra classe da camada ViewModel chamada FriendViewModel. Isso permite adicionar propriedades específicas de exibição que não persistirão no modelo. Por exemplo, a classe FriendViewModel expõe uma propriedade chamada FullName. Dependendo das configurações do aplicativo, ela pode retornar uma cadeia de caracteres no formato “FirstName, LastName” ou “LastName, FirstName”. Esse tipo de lógica é típico de classes ViewModel e não deve ser armazenada nas camadas inferiores do aplicativo.

Para retornar a propriedade FullName no formato correto, o FriendViewModel ouve uma mensagem do tipo ChangeFullName SchemaMessage. Isso é feito graças ao componente Messenger do MVVM, um barramento de evento livremente acoplado ligando um remetente e uma série de destinatários sem criar uma forte ligação entre eles. Observe que o Messenger pode enviar qualquer tipo de mensagem, de valores simples, como um int, a objetos complexos com informações adicionais.

Quando essa mensagem é recebida, o evento PropertyChanged é gerado para a propriedade FullName. A classe FriendViewModel é mostrada na Figura 8.

Figura 8 A classe FriendViewModel

public class FriendViewModel : ViewModelBase
{
  private FullNameSchema _schema = FullNameSchema.FirstLast;
  public Friend Model
  {
    get;
    private set;
  }
  public FriendViewModel(Friend model, FullNameSchema schema)
  {
    Model = model;
    Model.PropertyChanged += (s, e) =>
    {
      if (e.PropertyName == Friend.FirstNamePropertyName
          || e.PropertyName == Friend.LastNamePropertyName)
      {
        RaisePropertyChanged(() => FullName);
        return;
      }
      if (e.PropertyName == Friend.DateOfBirthPropertyName)
      {
        RaisePropertyChanged(() => DateOfBirthFormatted);
      }
    };
    Messenger.Default.Register<ChangeFullNameSchemaMessage>(
      this,
      msg =>
      {
        _schema = msg.Schema;
        RaisePropertyChanged(() => FullName);
      });
  }
  public string DateOfBirthFormatted
  {
    get
    {
      return Model.DateOfBirth.ToString("d");
    }
  }
  public string FullName
  {
    get
    {
      switch (_schema)
      {
        case FullNameSchema.LastFirstComma:
          return string.Format(
            "{0}, {1}",
            Model.LastName, Model.FirstName);
        default:
          return string.Format(
            "{0} {1}",
            Model.FirstName, Model.LastName);
      }
    }
  }
}

A instrução para mudar de “FirstName, LastName” para “LastName, FirstName” é enviada pelo MainViewModel conforme mostrado aqui:

private void SetSchema(FullNameSchema schema)
{
  _schema = schema;
  Messenger.Default.Send(new 
    ChangeFullNameSchemaMessage(_schema));
}

Por causa da maneira dissociada com a qual a classe Messenger funciona, seria muito fácil para movê-la do MainViewModel; para uma classe Settings posteriormente, por exemplo.

Configurando a navegação

A navegação entre páginas no Windows 8 é muito fácil quando iniciada do codebehind da exibição, graças à propriedade NavigationService que cada página expõe. Para navegar no ViewModel, contudo, é necessário um pouco de configuração. É muito fácil, porque o quadro que é responsável pela navegação é exposto de forma estática como ((Frame)Window.Current.Content). O aplicativo pode expor um serviço de navegação autônomo: 

public class NavigationService : INavigationService
{
  public void Navigate(Type sourcePageType)
  {
    ((Frame)Window.Current.Content).Navigate(sourcePageType);
  }
  public void Navigate(Type sourcePageType, object parameter)
  {
    ((Frame)Window.Current.Content).Navigate(sourcePageType, parameter);
  }
  public void GoBack()
  {
    ((Frame)Window.Current.Content).GoBack();
  }
}

O código na Figura 8 mostra como o serviço de navegação está registrado com o contêiner SimpleIoc. Ele é injetado como parâmetro no construtor MainViewModel e pode ser usado para iniciar convenientemente uma navegação na interface do usuário diretamente da camada ViewModel.

No MainViewModel, a navegação é iniciada quando a propriedade chamada SelectedFriend muda. Essa propriedade é uma propriedade observável como as outras que foram configuradas anteriormente. Essa propriedade será associada aos dados na interface do usuário, para que a navegação seja iniciada pelas ações do usuário. Para exibir os amigos, um GridView é usado, que é associado aos dados da coleção Friends do MainViewModel. Porque esse ViewModel é configurado como DataContext da MainPage, a associação é fácil de criar, conforme mostrado aqui:

<GridView
  ItemsSource="{Binding Friends}"
  ItemTemplate="{StaticResource FriendTemplate}"
  SelectedItem="{Binding SelectedFriend, Mode=TwoWay}"/>

Outra associação TwoWay é criada entre as propriedades GridView SelectedItem e a propriedade MainViewModel SelectedFriend listadas na Figura 9.

Figura 9 A propriedade MainViewModel SelectedFriend

public const string 
  SelectedFriendPropertyName = "SelectedFriend";
private FriendViewModel _selectedFriend;
public FriendViewModel SelectedFriend
{
  get
  {
    return _selectedFriend;
  }
  set
  {
    if (Set(SelectedFriendPropertyName, 
      ref _selectedFriend, value)
        && value != null)
    {
      _navigationService.Navigate(typeof (FriendView));
    }
  }
}

Finalmente, a navegação leva o usuário a uma página de detalhes do amigo selecionado. Nessa página, o DataContext está associado à propriedade MainViewModel SelectedFriend. Isso, novamente, garante uma boa experiência de tempo de design. Naturalmente, no tempo de design o RefreshCommand é executado quando o MainViewModel é construído, e a propriedade SelectedFriend é configurada:

#if DEBUG
private void CreateDesignTimeData()
{
  if (IsInDesignMode)
  {
    RefreshCommand.Execute(null);
    SelectedFriend = Friends[0];
  }
}
#endif

Nesse momento, a experiência do usuário pode ser criada no Expression Blend. Como o código de tempo de design é executado, o Blend exibe todos os amigos do tempo de design em um GridView adicionado à MainPage, conforme mostrado na Figura 1. É claro que criar modelos de dados requer algum tempo e habilidade, mas pode isso ser facilmente feito de forma visual sem ter de executar o aplicativo.

Conclusão

Tudo isso pode parecer bastante familiar para os desenvolvedores familiarizados com o padrão MVVM no WPF, Silverlight ou Windows Phone. Isso é porque as coisas são semelhantes ao Tempo de Execução do Windows. As competências adquiridas nessas estruturas anteriores são facilmente transferíveis para desenvolvimento de aplicativos da Windows Store. Evidentemente, alguns conceitos (como a programação assíncrona com async/await) são novos, e é necessário certo trabalho para converter o código no Tempo de Execução do Windows. Mas com o padrão MVVM e auxiliares como o MVVM Light Toolkit, os desenvolvedores têm uma boa vantagem e podem aproveitar os benefícios de um padrão de aplicativo dissociado.

Laurent Bugnion é diretor sênior da IdentityMine Inc., parceira da Microsoft, que trabalha com tecnologias como Windows Presentation Foundation, Silverlight, Surface, Windows 8, Windows Phone e UX. Ele mora em Zurique, na Suíça.

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: Karl Erickson e Rohit Sharma