Borland DevCon - USA

Report #10

VCL.NET

 

Criado - 9 de Novembro de 2005 – 09:45 p.m. (local time)

Atualizado – 9 de Novembro de 2005 – 09:45 p.m. (local time)

 

Marco Cantu, personagem que dispensa apresentações, ministrou uma excelente palestra sobre a VCL.NET, a versão adaptada da nossa conhecida VCL para o .NET Framework. Marco falou da arquitetura geral da VCL.NET, diferenças para a VCL Win32 e apresentou cuidados na migração de aplicações Win32 para .NET. A seguir mostro um sumário do que foi apresentado.

Antes de sua palestra, fiquei honrado em almoçar com Marco Cantu. Quando comecei a trabalhar com o Delphi, há uns 10 anos, lembro-me que foi através das “Bíblias” que consegui todo o progresso e aprendizado na ferramenta, sempre tive o Marco como um ídolo! Jamais imaginaria que um dia poderia compartilhar a mesma mesa de almoço com uma pessoa que considero ser uma das maiores celebridades Delphi do planeta. Coisas que só a DevCon poderia proporcionar.

O que é VCL.NET?

A VCL.NET é um subconjunto das classes da “VCL Win32” adaptadas para o .NET. Um dos principais objetivos é permitir que desenvolvedores se adaptem à nova plataforma fazendo uso do conhecimento adquirido durante anos com o desenvolvimento Delphi, e que possam realizar de forma mais suave a migração para o .NET.  É possível recompilar suas aplicações criadas em versões antigas do Delphi com alterações mínimas (ou mesmo com nenhuma mudança).

Para criar aplicações VCL.NET no Delphi 8/2005/2006, acesse a opção VCL Forms Application dentro do grupo Delphi for .NET Projects no Object Repository.

 

DevCon2005RP10_ image001.jpg

 

Por que VCL.NET?

Vamos responder a pergunta, por que usar VCL.NET?

·         Preservar seu código-fonte existente, porém fazendo uso da nova plataforma .NET;

·         Preservar seu conhecimento - não é somente a Delphi Language ou o IDE que ajudam você desenvolver no futuro mantendo seu conhecimento do passado, mas um rico e produtivo conjunto de classes usado por todos;

·         Um framework maduro: a VCL tem 10 anos, enquanto a FCL tem apenas 5;

·         E minha opinião pessoal: A Borland firmou um compromisso com a VCL para os próximos anos: teremos a VCL adaptada para o Compact Framework, de forma que aplicações possam rodar em Pocket PCs por exemplo; VCL para Avalon e .NET 2.0, mesmo código usando novas tecnologias em novas versões do Windows e .NET Framework;

·         Com a VCL.NET, basicamente você pode abrir seus projetos Win32 no Delphi 8/2005/2006 e recompilar, fazendo mudanças mínimas, conforme destacarei a seguir.

VCL.NET Overview

As classes da VCL.NET estão no namespace Borland.Vcl. Classes relacionadas a banco de dados estão no namespace Borland.Vcl.DB, enquanto as da RTL (Runtime Library) podem ser encontradas no namespace Borland.Vcl.Rtl. No entanto, você não precisa especificar o nome completo do namespace ao incluí-lo em uma cláusula uses, por exemplo, o que ajuda muito na migração de aplicações (defina o namespace default para o projeto).

A VCL para o .NET, ao contrário do que estava previsto no primeiro Preview que veio no compilador do Delphi 7, não é uma “casca fina” sobre a biblioteca de classes do .NET Framework. As primeiras versões da VCL adaptada consistiam basicamente de aliases de tipo, como:

 

TForm = Sistem.Windows.Forms.Form;

 

A Borland decidiu manter sua hierarquia de classes, preservando nomenclatura de métodos, propriedades, tipos e eventos. Para que qualquer objeto da VCL pudesse ser considerado um objeto .NET, TObject na VCL.NET é um alias de tipo para a classe System.Object, declarado em Borland.Delphi.System.pas:

 

TObject = System.Object;

 

Existe um Class Helper (TObjectHelper) que adiciona os métodos padrão de TObject para compatibilidade com código já existente. De forma semelhante, TPersistent e TComponent (declarados em Borland.Vcl.Classes) também são aliases para classes do .NET Framework (e também possuem class-helpers):

 

TPersistent = System.MarshalByRefObject;

TComponent = System.ComponentModel.Component;

Wrappers

Existem algumas classes, no entanto, que não mantém a sua hierarquia e funcionalidade da VCL, porém fazem uso de classes do .NET Framework “por baixo” para simular sua funcionalidade original. Como fazem uso de uma classe interna, permitindo o mesmo acesso através de membros públicos que mapeiam para métodos do objeto interno, são classes “wrappers”. Alguns exemplos desse tipo de classe na VCL.NET:

 

·         TList é um Wrapper, veja que internamente temos um FList de um tipo nativo da FCL (System.Collections.ArrayList)

 

  TList = class(TObject)

  private

    FList: System.Collections.ArrayList;

  protected

    function Get(Index: Integer): TObject;

    function GetCount: Integer;

    function GetCapacity: Integer;

    procedure Grow; virtual;

    procedure Put(Index: Integer; Item: TObject);

    procedure Notify(Instance: TObject; Action: TListNotification); virtual;

    procedure SetCapacity(NewCapacity: Integer);

    procedure SetCount(NewCount: Integer);

  public

    constructor Create;

    function Add(Item: TObject): Integer;

    procedure Clear; virtual;

    procedure Delete(Index: Integer);

                                     

    class procedure Error(const Msg: string; Data: Integer); overload; //virtual;

    procedure Exchange(Index1, Index2: Integer);

    function Expand: TList;

    function Extract(Item: TObject): TObject;

    function First: TObject;

    function GetEnumerator: TListEnumerator;

    function IndexOf(Item: TObject): Integer;

    procedure Insert(Index: Integer; Item: TObject);

    function Last: TObject;

    procedure Move(CurIndex, NewIndex: Integer);

    function Remove(Item: TObject): Integer;

    procedure Pack;

    procedure Sort(Compare: TListSortCompare);

    procedure Assign(ListA: TList; AOperator: TListAssignOp = laCopy; ListB: TList = nil);

    property Capacity: Integer read GetCapacity write SetCapacity;

    property Count: Integer read GetCount write SetCount;

    property Items[Index: Integer]: TObject read Get write Put; default;

    property List: System.Collections.ArrayList read FList;

  end;

 

·         TThread é um Wrapper para System.Threading.Thread, veja:

 

  TThread = class

  private

    FHandle: System.Threading.Thread;

    FCreateSuspended: Boolean;

    FStarted: Boolean;

    FSuspendCount: Integer;

    FTerminated: Boolean;

    FSuspended: Boolean;

    FFreeOnTerminate: Boolean;

    FFinished: Boolean;

    FReturnValue: Integer;

    FOnTerminate: TNotifyEvent;

    FSynchronize: TSynchronizeRecord;

    FFatalException: TObject;

    procedure ThreadError(O: TObject);

    procedure CallOnTerminate;

    function GetPriority: TThreadPriority;

    procedure SetPriority(Value: TThreadPriority);

{$IFNDEF CF}

    procedure SetSuspended(Value: Boolean);

{$ENDIF}

    class procedure Synchronize(ASyncRec: TSynchronizeRecord; QueueEvent: Boolean = False); overload;

  protected

    procedure Initialize; virtual;

    procedure DoTerminate; virtual;

    procedure Execute; virtual; abstract;

    procedure Queue(AMethod: TThreadMethod); overload;

    procedure Synchronize(Method: TThreadMethod); overload;

    property ReturnValue: Integer read FReturnValue write FReturnValue;

    property Terminated: Boolean read FTerminated;

  public

    constructor Create(CreateSuspended: Boolean);

    destructor Destroy; override;

{$IFNDEF CF}

    procedure Resume;

    procedure Suspend;

{$ENDIF}

    procedure Terminate;

    function WaitFor: LongWord; overload;

    function WaitFor(TimeOut: Integer; var ReturnValue: LongWord): Boolean; overload;

    class procedure Queue(AThread: TThread; AMethod: TThreadMethod); overload;

    class procedure RemoveQueuedEvents(AThread: TThread; AMethod: TThreadMethod);

    class procedure StaticQueue(AThread: TThread; AMethod: TThreadMethod);

    property FatalException: TObject read FFatalException;

    property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;

    property Handle: System.Threading.Thread read FHandle;

    property Priority: TThreadPriority read GetPriority write SetPriority;

{$IFNDEF CF}

    property Suspended: Boolean read FSuspended write SetSuspended;

{$ENDIF}

    property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;

  end;

Migração

Algumas dicas para migração de aplicações de VCL Win32 para VCL.NET:

·         Consulte as muitas dicas disponíveis no tópico “Porting VCL Applications” do Help do Delphi;

·         Use o “Upgrade Wizard” da IDE, disparado quando abrimos um projeto Win32;

·         Será necessário converter os arquivos .DFM para .NFM (basicamente renomear);

·         Use um “Default Project Namespace” para não modificar cláusulas uses;

Cuidados

Na migração, atentar para alguns detalhes diferentes entre .NET e Win32:

·         Gerenciamento de Memória é diferente, temos um Garbage Collector;

·         Chamadas a API são feitas de forma diferente. Saiba usar o DLLImport;

·         Procure não usar Pointers e classes “Hacks”;

·         A propriedade Tag é um Variant e não Integer;

·         OldCreateOrder não existe mais;

·         Use StringBuilder para concatenar strings, aqui tem um exemplo:

 

procedure TWebForm1.Button2_Click(sender: System.Object; e: System.EventArgs);

var

  sb: StringBuilder;

begin

  sb := StringBuilder.Create;

  sb.Append('Teste 1');

  sb.Append('Teste 2');

  sb.Append('Teste 3');

  Label2.Text := sb.ToString();

end;

Um código-fonte, duas plataformas

Usando VCL, você pode ter um único código-fonte que pode ser compilado tanto para Win32 quanto .NET. Coloquei um exemplo abaixo de como usar diretivas de compilação caso você precise detectar se o seu código está sendo compilado em Win32 ou .NET:

 

   {$IFDEF MSWINDOWS} // Delphi/Windows

   // Código Win32

  {$ENDIF}

  {$IFDEF CLR} // Delphi for .NET

   // Código .NET

  {$ENDIF};

Windows Forms

Marco depois comparou Windows Forms com a VCL:

·         É similiar VCL, um conjunto de classes sobre a API Win32;

·         Tem muitos menos recursos e classes visuais, se comparado a VCL;

·         Não tem o conceito de arquivo DFM;

·         Componentes não-visuais aparecem em parte separada do formulário;

·         Uma exclusividade: WinForms tem controles de validação;

·         Vantagem do WinForms: todos os controles são “Data-Aware” (data-bound), através do uso da propriedade DataBindings;

·         Existe a propriedade Language, para feitos de tradução para outros idiomas.

O que só existe na VCL.NET

·         ActionList;

·         Data Modules;

·         A capacidade de referenciar componentes em outros formulários/DataModules em tempo de design;

·         Suporte a Docking;

·         Conceito de TGraphicControl;

·         A VCL.NET permite o uso de WinForms controls, caso queira;

·         DFMS e component Streaming;

·         É distribuída com o código-fonte;

Novidades no Delphi 2005/2006

·         TButtonGroup, TCategoryButtons;

·         TCaptionedDockTree, TDockTabSheet;

·         OnMouseActive;

·         PopupParent e PopupMode para formulários;

·         TGridPanel, TFlowPanel;

·         Componente TTrayIcon! (finalmente);

Links

Why VCL for .NET? - by Danny Thorpe

http://bdn.borland.com/article/0,1410,31983,00.html

 

Overview of the VCL for .NET - by John Kaster

http://bdn.borland.com/article/0,1410,29460,00.html

 

Marco Cantu Web Site

http://www.marcocantu.com/

 

 

DevCon2005RP10_ image002.jpg

Dominando a VCL.NET com Marco Cantu

 

Guinther Pauli

Editor Geral Revista ClubeDelphi