Composite Application Guidance for WPF - Parte 2

Olá pessoal, tudo certo?

Continuando nosso estudo sobre Composite Application Guidance for WPF, vamos olhar um pouco mais sobre sua estrutura e principais recursos da CAL - Composite Application Library. Existe um conjunto básico de componentes que estão envolvidos na construção de uma aplicação de composição com essa biblioteca. Esses componentes são baseados nos conceitos:

  • Bootstrapper
  • Containers
  • Módulos e Serviços
  • Regiões
  • Visualizações
  • Eventos e Comandos

Cada conceito envolve uma etapa do processo de construção de uma interface de composição. Vejamos:

Bootstrapper É a classe principal de uma aplicação composta, onde podemos inserir as ações de inicialização de componentes como containers, regiões, views, etc. É o ponto de entrada da aplicação. De fato, existe uma classe maior App da aplicação, que usamos para instanciar a classe Bootstrapper.
Containers Para que módulos de funcionalidades possam ser relacionados numa interface de forma desacoplada, ou seja, sem relações de dependências diretas entre si, a biblioteca CAL utiliza o conceito de containers. Containers encapsulam módulos e oferecem serviços, que permitem a injeção de funcionalidades na interface Shell.
Módulos e Serviços Numa aplicação composta, grande parte da lógica do aplicativo reside nos módulos e serviços, visíveis pela classe bootstrapper através de containers de injeção.
Regions São as áreas especificas de mapeamento e renderização de funcionalidades na interface. No projeto, uma region é definida em XAML, através do controle RegionManager, que relaciona as regiões do layout presente em cada formulário de composição.
Views Dentro da interface da aplicação, usamos o controle ViewBox para inserir uma View numa região. Cada módulo define sua View, relacionando a região alvo para renderização.
Events/Commands Comandos são as atividades mais simples que definem o comportamento da interface, enquanto que eventos capturam os disparos realizados pelo usuário na interface. Uma aplicação de composição permite que os módulos assinem os eventos desejados, através do pattern de subscrição de eventos.

Vejamos um exemplo. Um projeto básico de aplicação com o Composite Application Guidance for WPF contém os seguinte componentes:

image Exemplo "HelloWorld Solution".

A solução acima é composta por 5 projetos: 3 projetos da Composite Application Library (Composite, Composite.WPF e Composite.UnityExtensions), 1 projeto de módulo de funcionalidades (HelloWorld) e 1 projeto principal da interface Shell da aplicação (HelloWorldSample).

Portanto, podemos iniciar a construção da aplicação em 2 frentes: o projeto principal da Shell e o projeto de cada módulo independente.

Para o projeto principal da Shell, notamos o arquivo Shell.xaml, que contém a chamada para a classe BootStrapper, responsável pela inicialização dos demais serviços da biblioteca CAL. Uma classe bootstrapper para nosso exemplo seria:

    1: using System.Windows;
    2: using Microsoft.Practices.Composite.Modularity;
    3: using Microsoft.Practices.Composite.UnityExtensions;
    4:  
    5: // Módulo de funcionalidades para a interface de composição.
    6: using HelloWorld;
    7:  
    8: namespace HelloWorldSample
    9: {
   10:     internal class Bootstrapper : UnityBootstrapper
   11:     {
   12:         protected override IModuleEnumerator GetModuleEnumerator()
   13:         {
   14:         // Adicionando o módulo a interface.
   15:             return new StaticModuleEnumerator()
   16:                 .AddModule(typeof(HelloWorldModule));
   17:         }
   18:  
   19:         protected override DependencyObject CreateShell()
   20:         {
   21:             Shell shell = new Shell();
   22:             shell.Show();
   23:  
   24:             return shell;
   25:         }
   26:     }
   27: }

No método GetModuleEnumerator() acima, vemos a adição do módulo "HelloWorldModule" como funcionalidade cadastrada na Shell. Isso é feito através da chamada .AddModule. Para aplicações com vários módulos de funcionalidades, podemos adicionar várias chamadas AddModule, determinando ainda uma hierarquia entre os módulos, para sua apresentação e navegação do usuário.

No projeto do módulo, adicionamos um UserControl que conterá o controle ViewBox para renderização de funcionalidades implementadas pelo módulo. Veja o exemplo de User Control e View "HelloWorldView" a seguir (arquivo "HelloWorldView.xaml":

    1: <UserControl x:Class="HelloWorld.Views.HelloWorldView"
    2:     xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3:     xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
    4:     <Grid>
    5:         <TextBlock Text="Hello World" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>
    6:     </Grid>
    7: </UserControl>

Na sequência, definimos um controle RegionManager no arquivo "Shell.xaml" do projeto da Shell. O controle RegionManager será responsável pela coleção de regiões que poderemos ter em nossa interface.

    1: <Window x:Class="HelloWorldSample.Shell"
    2:     xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3:     xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    4:     xmlns:cal="https://www.codeplex.com/CompositeWPF"
    5:     Title="Composite Application Library Sample" Width="400" Height="300">
    6:     <ItemsControl cal:RegionManager.RegionName="MainRegion"/>
    7: </Window>

A seguir, vemos a classe principal de módulo "HelloWorldModule", relacionando a região alvo para renderização de sua funcionalidade, em nosso exemplo, a região "MainRegion":

    1: using HelloWorld.Views;
    2: using Microsoft.Practices.Composite.Modularity;
    3: using Microsoft.Practices.Composite.Regions;
    4:  
    5: namespace HelloWorld
    6: {
    7:     public class HelloWorldModule : IModule
    8:     {
    9:         private readonly IRegionManager regionManager;
   10:  
   11:         public HelloWorldModule(IRegionManager regionManager)
   12:         {
   13:             this.regionManager = regionManager;
   14:         }
   15:  
   16:         public void Initialize()
   17:         {
   18:             IRegion mainRegion = this.regionManager.Regions["MainRegion"];
   19:             mainRegion.Add(new HelloWorldView());
   20:         }
   21:     }
   22: }

Assim, cercamos alguns dos principais conceitos envolvidos na CAL. Esses componentes são representados de forma organizada na figura a seguir:

image

Então é isso: quando usamos a CAL para construir uma aplicação composta, pensamos na interface principal chamada Shell e nos vários módulos componentes. Assim, precisamos definir quais são as regiões existentes na interface principal Shell. Cada módulo contém funcionalidades que serão apresentadas em regiões da interface Shell. Essa apresentação é feita através do componente View, que adicionamos em cada módulo. Todo o módulo é contido num container, que encapsula e oferece recursos para a cola com a interface Shell. Essa cola é feita através do injection do módulo junto a aplicação Shell. Por fim, podemos realizar o desenvolvimento de módulos e Shell de forma desacoplada e em paralelo, uma necessidade que é características de interfaces compostas.

Esse post fez apenas uma introdução sobre os principais aspectos da CAL, estudando uma aplicação composta muito básica. Claro que o objetivo do pacote é construir interfaces mais complexas, com um grande número de módulos, funcionalidades e eventos associados. Outro assunto importante no estudo da CAL é o pattern de subscrição de eventos. Cada módulo também pode assinar os eventos desejados para o disparo de funcionalidades específicas.

Em posts futuros, vamos continuar discutindo alguns exemplos, enquanto aumentamos a complexidade de nossas composições sobra a Composite Application Library.

Por enquanto é só! Até o próximo post :)

Waldemir.