msdn16_capa.jpg

Clique aqui para ler todos os artigos desta edição

 

Forms Designer sob medida com o .NET

por Sayed Y. Hashimi

Este artigo discute

Este artigo usa as seguintes tecnologias:

  • Fundamentos do ambiente de projeto
  • Arquitetura do forms designer

·          A implementação do forms designer no Visual Studio .NET

·          Serviços que devem ser implementados para criar forms designers para o seu aplicativo

.NET Framework and C#

 

Download:

CustomFormsDesigner.exe (157KB)

Chapéu

Forms Designer

 

 

Por muitos anos, o MFC foi a estrutura popular de construção de aplicativos baseados no Windows®. O MFC contém um form designer para facilitar a criação de formulários, ligar eventos e outras tarefas de programação baseadas em formulários. Embora o MFC seja amplamente utilizado, sempre foi criticado por suas desvantagens, a maioria delas em áreas resolvidas pelo Microsoft® .NET Framework. Realmente, a arquitetura de projeto expansível e adaptável do Windows Forms no .NET Framework tornou o desenvolvimento muito mais flexível do que com o MFC.

Com o Windows Forms, por exemplo, você pode arrastar um dos seus controles personalizados da caixa de ferramentas e soltá-lo sobre a superfície de projeto do Visual Studio®. Surpreendentemente, o Windows Forms não tem qualquer conhecimento sobre o controle e, mesmo assim, é capaz de hospedá-lo e permitir que você manipule suas propriedades. Nada disso era possível com o MFC.

Neste artigo, descreverei o que acontece nos bastidores quando você projeta seus formulários. Depois mostrarei como você poderá construir seus próprios forms designers simplificados, que permitirão que os usuários criem formulários de uma maneira parecida com a que usam para criar formulários no forms designer do Visual Studio. Para isso, você terá que entender exatamente que recursos são oferecidos pelo .NET Framework.

 

Algumas informações básicas sobre o Windows

Antes de eu iniciar a descrição do projeto, há diversos conceitos básicos cujo entendimento é importante. Vamos começar pela definição de um designer. Um designer oferece a UI do modo de design e o comportamento de um componente. Por exemplo, quando você solta um botão sobre um formulário, o designer do botão é a entidade que determina a aparência e o comportamento do botão. O ambiente de design oferece um forms designer e um editor de propriedades para permitir que você manipule os componentes e construa as interface de usuário. O ambiente de design também oferece serviços que podem ser usados para interagir, personalizar e ampliar o suporte ao design.

Um forms designer oferece serviços de design e recursos para que os desenvolvedores projetem formulários. O host do designer funciona com o ambiente de design para gerenciar o estado do designer, suas atividades (como as transações) e seus componentes. Além disso, há vários conceitos relacionados aos próprios componentes e é importante entendê-los. Por exemplo, um componente é descartável, pode ser gerenciado por um container e oferece uma propriedade Site. Ele obtém essas características implementando o IComponent, como mostrado aqui:

 

public interface System.ComponentModel.IComponent : IDisposable

{

    ISite Site { get; set; }

    public event EventHandler Disposed;

}

 

A interface do IComponent é o contrato fundamental entre o ambiente de design e um elemento a ser hospedado em uma superfície de design (como o forms designer do Visual Studio). Por exemplo, um botão pode ser hospedado no Windows Forms designer porque implementa o IComponent.

O .NET Framework implementa dois tipos de componentes: visual e não visual. Um componente visual é um elemento de interface de usuário, como um Control, e um componente não visual é aquele sem a interface de usuário, como um que crie uma conexão com um banco de dados do SQL Server™. O form designer do Visual Studio .NET distingue entre componentes visuais e não visuais quando os componentes são arrastados e soltos sobre a superfície de design. A Figura 1 mostra um exemplo dessa distinção.

 

image001.gif

Figura 1 Componentes visuais e não visuais

 

Um container contém componentes e permite que os componentes contidos acessem uns aos outros. Quando um container gerencia um componente, o container fica responsável por descartar o componente quando o container for descartado, o que é uma boa idéia, já que um componente pode usar recursos não gerenciados, que não são descartados automaticamente pelo coletor de lixo. O container implementa o IContainer, que nada mais é que alguns métodos que permitem que você adicione e remova componentes do container:

 

public interface IContainer : IDisposable

{

 

    ComponentCollection Components { get; }

    void Add(IComponent component);

    void Add(IComponent component, string name);

    void Remove(IComponent component);

}

 

Não deixe que a simplicidade da interface o engane. O conceito de um container é crítico durante o projeto e é também é útil em outras situações. Por exemplo, com certeza você já criou lógicas comerciais que instanciavam vários componentes descartáveis. Geralmente isto apresenta o seguinte formato:

 

using(MyComponent a = new MyComponent())

{

    // a.do();

}

using(MyComponent b = new MyComponent())

{

    // b.do();

}

using(MyComponent c = new MyComponent())

{

    // c.do();

}

 

Usando um objeto de Container, essas linhas são reduzidas ao seguinte:

using(Container cont = new Container())

 

{

    MyComponent a = new MyComponent(cont);

    MyComponent b = new MyComponent(cont);

    MyComponent c = new MyComponent(cont);

    // a.do();

    // b.do();

    // c.do();

}

 

Há mais coisas relacionadas a um container do que o descarte automático de seus componentes. O .NET Framework define o que é chamado de site, que está relacionado a um container e a um componente. A relação entre os três está ilustrada na Figura 2. Como você pode ver, um componente é gerenciado por exatamente um container e cada componente tem exatamente um site. Ao construir um forms designer, o mesmo componente não pode aparecer em mais de uma superfície de design. Contudo, vários componentes podem ser associados ao mesmo container.

 

image002.gif

Figura 2 Relacionamentos

 

O ciclo de vida de um componente pode ser controlado por seu container. Em troca pelo gerenciamento do tempo de vida, um componente ganha acesso aos serviços oferecidos pelo container. Essa relação é análoga a um componente COM+ que vive dentro do container COM+. Permitindo que o container COM+ o gerencie, o componente COM+ pode participar de transações e usar outros serviços oferecidos pelo container COM+. Em um contexto de design, a relação entre um componente e seu container é estabelecida por meio de um site. Quando você coloca um componente em um formulário, o host do designer cria uma instância de site para o componente e seu container. Quando essa relação é estabelecida, o componente foi "colocado no site" e usa sua propriedade ISite para ter acesso aos serviços oferecidos por seu container.

 

Serviços e Containers

Quando um componente permite que um container assuma a sua propriedade, o componente ganha o acesso aos serviços fornecidos por esse container. Um serviço, neste contexto, pode ser encarado como uma função que possui uma interface bem conhecida, pode ser obtida de um provedor de serviços, fica armazenada em containers de serviço e pode ser referenciada por seu tipo. Os provedores de serviços implementam o IServiceProvider como mostrado aqui:

 

public interface IServiceProvider

{

    object GetService(Type serviceType);

}

 

Os clientes obtêm um serviço fornecendo ao método GetService do provedor de serviços o tipo de serviço que desejam. Os containers de serviço agem como um repositório de serviços e implementam o IServiceContainer, dessa forma fornecendo meios para adicionar ou remover serviços. O código a seguir mostra a definição do IServiceContainer. Observe que a definição do serviço contém somente métodos para adicionar e remover um serviço.

 

public interface IServiceContainer : IServiceProvider

{

...

Quer ler esse conteúdo completo? Tenha acesso completo