msdn09_capa.JPG

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

 

Migrando aplicações VB 6.0 para VB.NET

Parte II – Substituindo controles DAO e controles ActiveX.

por Renato Guimarães

Na parte I (edição 7) apresentei uma introdução sobre alguns dos motivos que levaram a Microsoft fazer mudanças radicais no Visual Basic. Além disso, mostrei a importância da análise da aplicação escrita em Visual Basic 6.0 com o Code Advisor. Com o Code Advisor vimos que é possível detectar pontos de atenção no código Visual Basic que devem ser corrigidos antes da migração para evitarmos problemas quando o Upgrade Wizard entrar em ação.

Nessa segunda parte irei mostrar algumas alterações manuais que devemos fazer no código antes da migração quando estamos usando ligação de dados com DAO e usando controles ActiveX. Para isso explicarei alguns detalhes sobre a necessidade de mudança do DAO para o ADO e mostrarei os passos necessários para migrar uma aplicação que usa controles DAO para ligação de dados. Em seguida, explicarei a necessidade de migrar controles ActiveX e mostrarei a migração de uma pequena aplicação.

As técnicas de acesso a dados em VB e VB .NET

A maioria das aplicações tem algum tipo de acesso a dados. Este fato não é surpresa quando você considera que conceitualmente a maioria dos negócios é baseada em dados: cliente, produto, vendas, estoque. Todas essas informações de negócios precisam ser armazenadas de uma forma que possam ser facilmente consultadas, alteradas e armazenadas novamente. É incontável o número de aplicações que têm sido desenvolvidas para fornecer cada vez mais interfaces amigáveis para exibir essas informações. Cada nova versão do Visual Basic tem feito melhorias para acessar esses dados. Com o Visual Basic .NET não será diferente. Com o VB.NET vemos um continuado suporte a código ActiveX Data Objects (ADO) e ligação de dados (data binding). O Visual Basic .NET suporta código Data Access Objects (DAO) e Remote Data Objects (RDO), mas não suporta ligação de dados usando DAO ou RDO. Além disso, introduz um novo tipo desconectado de acesso a dados chamado ADO.NET.

O acesso a dados é formado por três componentes: código que lida com os objetos de dados, ligação dos dados a controles e ferramentas em tempo de projeto, tal como ADO Data Environment. Veremos rapidamente onde esses três componentes são diferentes entre Visual Basic e Visual Basic .NET.

Código: DAO, RDO e ADO são implementados como bibliotecas COM, então a maior parte do código escrito funciona no VB.NET da mesma forma que funcionava no Visual Basic.

Ligação de Dados (data binding): Ligação de dados permite a você associar o valor de um controle no formulário a um campo no banco de dados. O Visual Basic 6.0 suporta ligação de dados usando ADO, DAO e RDO. Você pode associar a um controle um ADO Data Environment, um controle ADO, um controle DAO ou um controle RDO. O Visual Basic .NET , por outro lado, suporta somente ligação de dados com controle ADO, ou seja, não permite ligação com DAO ou RDO. Essa distinção vem da forma como os diferentes tipos de ligação de dados são implementados. DAO e RDO são tecnologias de acesso a dados antigas. DAO foi introduzido no Visaul Basic 3.0, e o RDO foi apresentado no Visual Basic 4.0. Quando o time de desenvolvimento do Visual Basic implementou essas formas antigas de acesso a dados pela primeira vez, eles as construíram embutidas dentro do pacote forms. Essa implementação permitiu uma integração, mas também amarrou a tecnologia de ligação de dados ao Visual Basic Forms. No Visual Basic .NET, o Visual Basic Forms foi substituído pelo Windows Forms. Os projetistas do Windows Forms decidiram não construir o DAO e RDO dentro do Windows Forms, conseqüentemente ambos não são suportados. A ligação de dados ADO é suportada porque não está construída dentro do pacote forms; ao invés disso, ele é implementado na biblioteca COM MSBind.dll. Essa biblioteca gerencia a ligação de dados ADO no Visual Basic 6.0, e a biblioteca atualizada Microsoft.VisualBasic.Compatibility.Data, gerencia a ligação de dados no Visual Basic .NET. O Upgrade Wizard atualiza ligação de dados para ambos ADO Data Control e ADO Data Envorinment.

ADO Data Environment: Permite que você construa visualmente conexões e comandos com banco de dados usando o ADO Data Environment Designer. Embora o Visual Basic .NET não suporte o ADO data environment, o Upgrade Wizard atualiza as conexões, comandos, e Recordsets para uma classe que tenha o mesmo comportamento que o ambiente do Visual Basic 6.0.

Os componentes que não podem ser atualizados automaticamente para o VB.NET causam erros no projeto que foi gerado na migração. Por exemplo, se um formulário no Visual Basic 6.0 tem um controle DAO, o controle é removido durante a migração e avisos são inseridos dentro do relatório de migração. Qualquer código que fizer referência ao controle causará erro de compilação.

O que você deve fazer se seu projeto usa RDO ou DAO para ligação de dados? Você tem duas soluções: reimplementar a ligação de dados no Visual Basic .NET usando ADO ou ADO.NET ou já fazer a alteração dos controles ainda no projeto Visual Basic 6.0 antes da migração. A vantagem de fazer ainda no Visual Basic 6.0 é que você terá um processo de migração com menos problemas e não haverá necessidade de mudança de código porque o Visual Basic . NET dá suporte a ADO na ligação de dados. Caso o prazo estimado pelo seu gerente de projeto seja bom, será melhor implementar no Visual Basic .NET usando ADO.NET para tirar proveito das melhorias trazidas pelo framework .NET. A Tabela 1 da uma visão geral das diferentes tecnologias de acesso a dados no Visual Basic 6.0 e mostra como foram atualizadas para Visual Basic .NET.

 

Tabela 1 Tecnologias do Visual Basic 6.0 e como foram migradas para Visual Basic .NET

 

Visual Basic 6.0

Visual Basic .NET

 

 

DAO

 

Código usando objetos de acesso a dados

Controle de ligação de dados

 

 

Código usando objetos de acesso a dados

Não suportado

 

 

 

RDO

 

Código usando objetos de acesso a dados

Controle de ligação de dados

Designer para conexão de dados

 

Código usando objetos de acesso a dados

Não suportado

Não suportado

 

ADO

 

Código usando objetos de acesso a dados

Controle de ligação de dados

Ambiente de Dados (Data Environment)

Classe de Fonte de Dados

 

 

Código usando objetos de acesso a dados

Controle de ligação de dados

Classe de Ambiente de Dados (Data Environment class)

Não suportado

 

 

ADO.NET é o futuro...

O futuro do acesso e ligação de dados é com ADO.NET, não com DAO, RDO ou ADO. No Visual Basic .NET, com Windows Forms e Web Forms, o ADO.NET oferece uma rica experiência em edição de dados, com designers para conexão, esquemas, e ligação dos mesmos. Infelizmente, a experiência na edição de dados com ADO não é tão rica quanto com ADO.NET.

É importante a ligação de dados com ADO para que você possa manter aplicações existentes, mas aconselho o uso do ADO.NET para novas aplicações que acessem dados, especialmente as que usam controles para ligação de dados.

O Upgrade Wizard não atualiza DAO, RDO e ADO para ADO.NET, porque infelizmente não existe um mapeamento direto para o ADO.NET. O ADO.NET é uma arquitetura desconectada e diferente o suficiente para não permitir migração automática. Por exemplo, o objeto RecordSet no ADO tem o conceito de linha corrente; é um cursor que aponta para linha corrente e que você pode navegar pelo Recordset usando os métodos MoveFirst, MoveNext, MoveLast e MovePrevious.         O semelhante ao Recordset no ADO.NET é o DataTable (ou o DataSet, que possui uma coleção de DataTable). Um DataTable não tem uma linha corrente, e não existe nenhum método equivalente ao Move do Recordset. Por esta razão, uma migração automática para ADO.NET não é possível.

Visão geral do ADO.NET   

Enquanto o ADO.NET apresenta um novo modelo de objeto para acesso a dados, partes dele são bem similares ao ADO que já conhecemos. Pense no ADO.NET como sendo o resultado da integração do ADO clássico e as tecnologias Microsoft XML, gerando um framework simples e coerente. Diferente do ADO, ele foi projetado para suportar uma arquitetura de dados generalizada que é abstraída do banco de dados. Em outras palavras, ADO.NET foi projetado para trabalhar com uma grande variedade de fontes de dados e, ele mesmo, pode funcionar como um repositório de dados. O framework possui objetos container de dados que suportam funções similares às encontradas nos bancos de dados (ordenação, indexação, visões) sem requerer trabalho para isso. Não esquecendo que o ADO.NET tem uma forte integração com XML, onde o ADO tem um suporte mínimo.

O ADO.NET possui um conjunto de classes específicas (xxxConnection, xxxCommand, xxxDataAdapter, xxxDataReader. Xxx irá representar a fonte de dados, por exemplo Sql), que estão dentro do namespace System.Data.xxxx para cada provedor de dados que você utilizar. Por exemplo, as classes para acessar o Sql Server 7.0 ou superior (até a versão 6.5 use System.Data.OleDb) estão no namespace System.Data.SqlClient. Além dessas, temos as classes que são independentes da fonte de dados (DataView, DataSet, DataTable) que estão dentro do namespace System.Data.

O RecordSet do ADO foi dividido em dois objetos menores e mais especializados: DataSet e xxxDataReader. Recordets somente de leitura são mapeados para xxxDataReader, enquanto que os RecordSets desconectados são mapeados para DataSet. A classe DataSet foi projetada de forma a solucionar os problemas de acesso a dados desconectado.

Integrando seu código ADO com a aplicação Visual Basic .NET     

Imagine que uma aplicação em VB 6.0 foi escrita usando ligação de dados com DAO. Antes de migrar, faça a troca dos controles DAO por controles ADO porque já se sabe que o ADO é suportado no VB.NET. Caso tente migrar a aplicação ainda usando DAO, verá que o Upgrade Wizard não colocará um componente de ligação de dados que dê a mesma funcionalidade em .NET. No lugar do componente DAO será colocado um Label com a cor de fundo vermelha.

Como tirar vantagem do código existente ADO e ainda usar os novos controles do VB.NET? Tudo que eu preciso é converter o RecordSet  para um DataSet ou um DataTable. Com um desses objetos do ADO.NET a ligação de dados fica bem fácil. Veja um exemplo do código na Listagem 1 usando OleDbDataAdapter.

OBS: O Visual Studio.NET fornece um Primary Interop Assembly (PIA) para ADO no diretório "Program Files\Microsoft.NET\Primary Interop Assemblies" que está no arquivo adodb.dll. Se você tiver uma cópia do Visual Studio .NET instalada é recomendado que você use este arquivo ao invés de importar o seu próprio usando a ferramenta Type Library Importer (tlbimp.exe). Por exemplo, existe um componente COM com um ProgId do ADOComponent.DataClass que está compilado dentro de ADOComponent.dll que tem métodos para retornar objetos do tipo ADODB.RecordSet. Para consumir este objeto no .NET, importe ambos ADOComponent.dll e msado15.dll, no qual contém os objetos ADODB.RecordSet e ADODB.Record. Para importar type libraries COM para .NET use a seguinte linha de comando.

TlbImp "C:\Program Files\Common Files\System\Ado\msado15.dll" /out:ADODB.dll

TlbImp ADOComponent.dll /out:ADOCOM.dll

 

Em seguida você pode utilizar as bibliotecas .NET resultantes, ADODB.dll e ADOCOM.dll, como referências quando compilar seu programa .NET com a seguinte linha de comando:

vbc MyVB.vb /r:system.dll /r:system.data.dll /r:system.xml.dll /r:ADODB.dll /r:ADOCOM.dll

 

Clique agora sobre o menu File | New | Project. Selecione Windows Application. Em seguida adicione um botão e um DataGrid ao formulário. O evento Click do botão deve ser de acordo com a Listagem 1. Para esse exemplo utilizarei o banco de dados Northwind que já vem instalado no Sql Server. Veja na Figura 1 como ficará o DataGrid antes e depois da ligação dos dados.

 

Listagem 1. Cria conexão ADO e, em seguida, cria um DataTable e OleDbDataAdapter para ligação de dados.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        'Código ADO familiar

        Dim con As New ADODB.Connection

        Dim rs As New ADODB.Recordset

        con.Open("Provider=SQLOLEDB;Integrated Security=SSPI;" & _

         "Persist Security Info=False;Initial Catalog=Northwind;" & _

         "Data Source=localhost")

        rs.Open("Select * from Employees", con)

 

        'Aqui é onde tudo começa a ficar interessante

        Dim oleAdp As New OleDbDataAdapter

        Dim tabela As New DataTable

 

        'Usa o DataAdapter para carregar o DataTable

        oleAdp.Fill(tabela, rs)

 

        'Faz a ligação com o controle DataGrid.

        'Poderia fazer a ligação tanto com o DataTable quanto com DataSet

        Me.DataGrid1.DataSource = tabela

 

        'Feche os objetos assim que possível

        rs.Close()

        con.Close()

End Sub

 

 

image002.jpg

Figura 1. Datagrid antes e depois da ligação de dados usando RecordSet, DataTable e OleDBDataAdapter.

Objetos Connection e Command           

Os objetos Connection e Command ainda existem no ADO.NET. Existem, portanto, diferenças significativas entre as classes do ADO e ADO.NET. No ADO o objeto Connection não somente representa sua conexão a um banco de dados mas também pode ser usado para executar comandos. Além disso, outros objetos ADO (RecordSet e Command) têm propriedades ActiveConnection que aceitam ou uma string de conexão ou uma conexão já existente. Isso pode ser meio confuso e gerar padrões de codificação diferentes no desenvolvimento de aplicação em equipe.

O ADO.NET é muito mais direto. Objeto xxxConnection (SqlConnection por exemplo) é usado especificamente para conectar a base de dados. Não existe uma forma de executar comandos usando um objeto xxxConnection. A forma de executar comandos é através do objeto xxxCommand (SqlCommand por exemplo). A classe xxxCommand é comparada a classe Command do ADO que pode ser usada para executar consultas e stored procedures em runtime através da configuração das propriedades CommandText e CommandType. A principal vantagem do ADO.NET é a possibilidade de explicitar o tipo de query que será executada. O método Execute do Command (ADO) foi substituído por quatro métodos que especificam o tipo de dado que você quer de volta, se este existir (Veja a Listagem 2):

·         ExecuteReader – Executa a query e retorna um objeto DataReader.

·         ExecuteScalar – Executa a query e retona o valor da primeira coluna da primeira linha.

·         ExecuteXmlReader – Executa uma query e retorna um objeto XmlReader.

·         ExecuteNonQuery – Executa a query e retorna o número de linhas afetadas.

 

Listagem 2. Exemplo de código para executar comando sql no Visual Basic 6.0 e no Visual Basic .NET

'Método usando ADO no Visual Basic 6.0

Sub ExecuteSql(stringConexao As String, sql As String)

   Dim conn As New ADODB.Connection

   Dim rs   As New ADODB.RecordSet

   conn.Open stringConexao

   Set rs = conn.Execute(sql)

End Sub

 

'Método usando ADO.NET equivalente ao ADO no VB 6.0

Sub ExecuteSql(stringConexao As String, sql As String)

   Dim conn As New OleDbConnection(stringConexao)

   Dim cmd As New OleDbCommand(sql, conn)

   conn.Open()

   Dim dr As OleDbDataReader = cmd.ExecuteReader()

End Sub

 

Recordsets somente de leitura (Forward-Only)

         O RecordSet Forward-only é o tipo de RecordSet gerado por default pelo ADO (devido a performance). Ele deve ser lido de forma continua e, somente após toda leitura é liberado.

         O equivalente no ADO.NET é o xxxDataReader. O xxxDataReader é somente de leitura, e diferente do RecordSet, nunca pode ser desconectado. Além disso não suporta acesso aleatório e mantém a conexão bloqueada enquanto estiver aberto. Sendo assim, após ler a informação que você deseja, feche-o imediatamente para liberar a conexão. Quando um objeto xxxDataReader é retornado o ponteiro do registro está apontando para antes do primeiro registro. Sendo assim, deve ser feita uma chamada ao método Read antes do primeiro registro ser carregado, e sucessivas chamadas ao método devem ser feitas para continuar a leitura dos outros registros até que o método Read retorne false. Ou seja, o fim dos registros foi alcançado (Veja a Listagem 3).

 

Listagem 3. RecordSet somente de leitura em ADO e ADO.NET

'Acesso usando RecordSet somente de leitura no VB 6.0

Sub VB6ExemploRecordSet(stringConexao As String, sql As String)

   Dim conn As New ADODB.Connection

   Dim rs   As New ADODB.RecordSet

   conn.Open stringConexao

   Set rs = conn.Execute(sql)

           

   Do Until rs.EOF

     Dim str As String

     Dim i As Integer

     For i = 0 To rs.Fields.Count -1

        Str = str & rs.Fields(i).Value

     Next

     Debug.Print str

     rs.MoveNext

   Loop

End Sub

 

'Acesso usando DataReader somente de leitura no VB.NET

Sub VBNETExemploDataReader(ByVal stringConexao As String, ByVal sql As String)

   Dim conn As New OleDbConnection(stringConexao)

   Dim cmd As New OleDbCommand(sql, conn)

   conn.Open()

   Dim dr As OleDbDataReader = cmd.ExecuteReader()

   While dr.Read()

      Dim str As String = “”, i As Integer

      For i = 0 To dr.FieldCount – 1

         Str &= dr(i)

      Next

      Debug.WriteLine(str)

   End While

End Sub

Recordsets desconectados e cursores dinâmicos

         Um RecordSet desconectado é retornado quase que da mesma forma de um RecordSet somente leitura. Sendo que o desconectado usa cursor dinâmico. Não é o que acontece com um DataSet, no qual requer no exemplo da Listagem 4, pelo menos um xxxDataAdapter para manipular a carga dos dados.

O ADO tem métodos comuns para criar diferentes tipos de RecordSet, ADO.NET tem métodos específicos para diferentes formas de repositório de dados.

 

Listagem 4. RecordSet desconectado em ADO e ADO.NET

'Exemplo de um cursor dinâmico no Visual Basic 6.0

Function VB6ExemploRSDinamico(stringConexao As String, sql As String) As RecordSet

   Dim conn As New ADODB.Connection

   conn.Open(stringConexao)

   Dim rs   As New ADODB.RecordSet

   rs.Open sql, stringConexao, adOpenDynamic

   Set rs = conn.Execute(sql)

   Set VB6ExemploRSDinamico = rs

   Set rs = Nothing

End Function

 

'Exemplo de um DataSet no VB.NET

Function VBNETExemploDataSet(ByVal stringConexao As String, ByVal sql As String)

   Dim adapter As New OleDbDataAdapter(sql, stringConexao)

   Dim dataset As New DataSet()

   adapter.Fill(dataset)

   return dataset

End Function

A principal diferença entre RecordSet desconectado e o DataSet é a forma de iteração. O RecordSet pode usar qualquer uma das funções Move (Move, MoveFirst, MoveLast, MoveNext, MovePrevious) ou pode acessar as linhas ordinalmente com o nome da coluna. Um DataTable (contido no DataSet) pode ser iterado usando a referência ordinal (linha(x).coluna(y)) ou usando For Each (Veja a Listagem 5).

 

Listagem 5. Formas de navegar no DataTable

'Usando For Each

For Each row In dataset.Tables(0).Rows

  'Faz alguma coisa

Next

 

'Usando referência ordinal

Dim i As Integer

Dim row As DataRow

For I = 0 To dataset.Tables(0).Rows.Count -1

  row = dataset.Tables(0).Rows(i)

  'Faz alguma coisa

Next

Usando DataView

         O DataView é um objeto que permite que se crie múltiplas visões dos seus dados e que pode ser usado para ligação de dados. A flexibilidade que ele introduz quando estamos manipulando os dados não os muda do DataTable de onde ele foi gerado. O código da Listagem 6 mostra como você pode usar o controle DataView para filtrar linhas baseado no valor de uma coluna (no exemplo irei usar as colunas FirstName e LastName).

 

Listagem 6. Filtra os dados do DataView mas não afeta o DataTable

Dim adapter As New OleDbDataAdapter(“Select * from Customers”, stringConexao)

Dim dataset As New DataSet()

 

adapter.Fill(dataset)

 

‘Recuperando a visão default para cada objeto DataView

Dim visao1 As DataView = dataset.Tables(0).DefaultView

Dim visao2 As DataView = dataset.Tables(0).DefaultView

 

‘Filtrando os dados por colunas diferentes em cada visão

visao1.RowFilter = FirstName Like O%’ ”

visao2.RowFilter = LastName Like ‘E%’ ”

 

Dim i As Integer

Debug.WriteLine(Todos que o nome comece por O))

For i = 0 to visao1.Count -1

   Debug.WriteLine(visao1(i)(FirstName))

Next

 

Debug.WriteLine(Todos que o sobrenome comece por E))

For i = 0 to visao2.Count -1

   Debug.WriteLine(visao2(i)(LastName))

Next

 

Aplicações VB 6.0 que usam controles ActiveX 

 

         O Visual Basic .NET oferece um novo modelo de controle chamado controles Windows Forms. Devido ao fato de existirem muitos controles Windows Forms que são equivalentes a controles ActiveX que você encontra no Visual Basic 6, você não é obrigado a substituir todos os controles ActiveX pelos do Windows Forms equivalentes. O Visual Basic .NET suporta controles ActiveX do jeito que são. Em algumas situações o Upgrade Wizard não substitui seus controles ActiveX pelos controles do  VB.NET, mesmo quando existem controles equivalentes.              

         Substituir os controles ActiveX por controles do Visual Basic .NET tem alguns benefícios. Entre eles temos: 100% de compatibilidade com o framework .NET, controle de versão melhorado e simples distribuição.

         Controles Windows Forms têm uma vantagem sobre controles ActiveX porque são nativos do ambiente .NET, e dessa forma são fortemente integrados ao .NET. Por exemplo, um controle Window Form pode suportar editores de propriedades personalizados – tal como editor de coleção de nós TreeView – para uso com o Property Browser.

         Como os controles ActiveX são baseados em COM e não são nativos ao ambiente .NET, você pode encontrar alguns problemas com eles. Por exemplo, o editor de propriedades personalizadas não está disponível para controles ActiveX. Um controle ActiveX pode depender de algumas funcionalidades fornecidas pelo ambiente do Visual Basic 6, nos quais não existem no Windows Forms. Sendo assim, o controle ActiveX pode degradar sua aplicação quando for colocado no formulário do VB.NET. Por exemplo, o controle ActiveX SSTab depende de uma interface  específica para dar suporte a controles filhos. Windows Forms não dá suporte a interface requerida pelo SSTab, então o controle não aceitará controles filhos no Windows Forms.

         Quando um controle ActiveX é registrado na sua máquina, todas as aplicações no qual o controle é usado compartilharão o controle no mesmo local onde foi instalado. Se você atualizar o controle, todas as aplicações que usam o controle sofrerão a atualização. Esse uso compartilhado é bom e ruim ao mesmo tempo. Ele é bom porque a correção de um bug afetará todas as aplicações, por outro lado é ruim porque a atualização do controle pode também introduzir novos bugs ou incompatibilidades que quebrem suas aplicações.

         Aplicações que são construídas com controles Windows Forms não correm esses riscos no momento da atualização de um controle. Isso porque os controles Windows Forms são locais para cada aplicação, significando que cada aplicação pode ser associada a uma versão específica do controle. Se um controle atualizado for disponibilizado no sistema, a aplicação não atualiza a referência automaticamente para esse novo controle. Ao contrário, a aplicação continua a usar a versão do controle que foi associado pela primeira vez. Em resumo, você pode ter seus controles com várias versões e independente de aplicação. Caso você queira compartilhar o controle para todas as aplicações, você irá instalar o controle no Global Assebly Cachê (GAC) usando a ferramenta gacutil.exe. Para mais detalhes, faça uma pesquisa no Help do Visual Studio.NET ou no site www.msdn.com.

         Quando você distribui uma aplicação completamente construída com controles Windows Forms e componentes .NET, você descobrirá que poucos arquivos são necessários. Se sua aplicação contém controles ActiveX, mais arquivos são instalados, desde que uma DLL extra é gerada para cada controle ActiveX. A DLL extra é o assembly COM necessário para facilitar a comunicação entre Windows Forms e controle ActiveX. Se você está usando controles Windows Forms que são equivalentes a controles ActiveX do Visual Basic 6 -  tais como RichText, ProgressBar, StatusBar, ToolBar, TreeView e ListView – os controles são fornecidos como parte do assemby do Windows Forms e nenhuma dll adicional é requerida quando você usa esses controles. Se você usa controles fornecidos por terceiros, você pode distribuir o controle copiando o assembly do controle para o diretório da sua aplicação, ou seja, o diretório onde está o arquivo executável. Não é preciso registrar os controles Windows Forms.

         Como o Upgrade Wizard não substitui automaticamente seus controles ActiveX por controles Windows Forms equivalentes, o processo de substituição dos controles no seu projeto migrado para o VB.NET  é feito manualmente. Esse processo envolve os seguintes passos:

1.     Copiar, em tempo de projeto, a configuração das propriedades do controle ActiveX.

2.     Excluir o controle ActiveX do formulário.

3.     Colocar no formulário o controle Windows Form equivalente.

4.     Renomear o controle Windows Form para o mesmo nome do controle ActiveX removido.

5.     Configurar as propriedades, em tempo de projeto, copiadas do controle ActiveX.

6.     Corrigir as configurações das propriedades necessárias.

7.     Resolver os erros no código.

8.     Remove a referência da biblioteca do controle ActiveX.

 

Migrando uma aplicação que usa controles ActiveX 

 

Usando o Visual Studio 6.0 irei construir uma aplicação que usa controles ActiveX. Em seguida, usando o Visual Studio .NET 2003 irei migrar a aplicação, mas será preciso fazer alterações manualmente no código para concluir o processo de migração. O layout da aplicação será de acordo com a Figura 2. Os outros componentes utilizados são descritos na Tabela 2. Os códigos das Listagens 7, 8 e 9, referem-se respectivamente, aos eventos Toolbar1_ButtonClick, ProgressBar1_Click e Command1_Click.

 

 

image004.jpg 

Figura 2. Layout da aplicação com controles ActiveX que será convertida para VB.NET.

 

Tabela 2. Controles utilizados na aplicação e os valores das suas principais propriedades.

Controle

Propriedade

Toolbar1

Configure um imagelist para os dois botões. Em seguida, configure a propriedade Image para cada um. Cada botão será ligado a uma imagem do ImageList1

MonthView1

Configuração padrão

ProgressBar1

Min = 1 e Max=200

Command1

Caption = “Executar”

ImageList1

Adicionar duas figures para associar aos botões

 

Listagem 7. Código executado no evento ButtonClick do componente ToolBar1

Private Sub Toolbar1_ButtonClick(ByVal Button As MSComctlLib.Button)

    Select Case Button.Index

        Case 1

           MonthView1.Value = DateAdd("D", -1, MonthView1.Value)

        Case 2

           MonthView1.Value = DateAdd("D", 1, MonthView1.Value)

    End Select

End Sub 

 

 

Listagem 8. Código executado no evento Click do componente ProgressBar1

Private Sub ProgressBar1_Click()

    MsgBox "Você deu um clique sobre o progress bar"

End Sub 

 

Listagem 9. Código executado no evento Click do componente Command1

Private Sub Command1_Click()

    Dim HoraInicio As Single

    For i = ProgressBar1.Min To ProgressBar1.Max

       HoraInicio = Timer

       Do While Timer - HoraInicio < 0.01

       Loop

      

       ProgressBar1.Value = i

       ProgressBar1.Refresh

    Next

End Sub

 

OBS: Caso não consiga visualizar os controles na ToolBar do seu Visual Studio 6.0, selecione o menu Project | Componentes. Em seguida, selecione os itens: Microsoft Windows Common Controls 6.0 (SP6), Microsoft Windows Common Controls-2 6.0 (SP4) e Microsoft Windows Common Controls-2 6.0 (SP5).

 

Depois de construída a aplicação, abra o projeto no Visual Studio .NET 2003 para iniciar o processo de migração pelo Upgrade Wizard. Em seguida, analise o relatório de migração _UpdateReport.htm. Fique atento para os alertas gerados na migração.

O Upgrade Wizard irá converter alguns controles diretamente (MonthView, CommandButton). Você perceberá que alguns controles não foram convertidos. O Upgrade Wizard criará um wrapper (classes VB .NET que sabem fazer a comunicação com o controle ActiveX. Ou seja, são responsáveis pela interoperabilidade) que ficará localizado no caminho do arquivo executável. O resultado deve ser semelhante ao mostrado na Figura 3 onde podemos ver as referências que foram adicionadas ao projeto.

 

image005.gif 

Figura 3. Referências que foram adicionadas ao projeto VB.NET durante a migração automática.

       O relatório de migração indica que não houve erros e só indica um alerta que é referente à declaração da variável i que não foi informado o tipo explicitamente. Analisando o código gerado podemos perceber que o Upgrade Wizard manteve todo o código escrito na aplicação VB 6.0. Também fica claro que, a assinatura de alguns métodos e o código para manter a  compatibilidade foram adicionados.

Antes de qualquer coisa, vamos tentar executar a aplicação. Para isso, selecione o item de menu Debug | Start. Ou, então, pressione a tecla F5 ou clique sobre o botão Start. A primeira coisa que irá aparecer será uma mensagem de erro: Type 'AxMSComctlLib.AxProgressBar' is not defined. Esse erro indica que o namespace AxMSComctlLib não está definido.         Localize o erro dentro do seu código e troque a palavra AxMSComctlLib por Axmscomctl. Agora execute a aplicação novamente pressionando F5. Perceba que a aplicação executou sem problemas (Veja Figura 4).

 

image007.jpg

Figura 4. Aplicação em execução após migração automática. 

 Fique atento quando a aplicação começar a executar e verás que existe uma demora para montar a interface. Isso porque está havendo uma interoperabilidade entre o .NET e os controles ActiveX do VB 6.0. Essa interoperabilidade degrada sua aplicação, então é importante converter, sempre que possível, toda sua aplicação para controles intrínsecos  .NET.

Dando um clique sobre cada controle no formulário, a exceção do CommandButton, pode-se verificar que cada controle ainda é um ActiveX (Veja Figura 5 após clique com botão direito sobre o controle MonthView1).

 

 

image009.jpg

Figura 5. Clique com botão direito sobre o controle MonthView1. Podemos invocar um editor para alterar as propriedades do ActiveX.

 

Substituindo controles ActiveX por controles .NET   

Para que seja possível tirarmos proveito das vantagens oferecidas pelo VB.NET é preciso trocar os controles ActiveX por controles VB.NET. Sendo assim, vamos remover a barra de ferramentas (ToolBar1), o MonthView1, o ProgressBar1 e o ImageList1.

·         Substituição da barra de ferramentas Toolbar1:

o        Selecione o formulário na janela do Solution Explorer e clique duas vezes para exibir o formulário em modo de exibição de design.

o        Remova a barra de ferramentas ToolBar1. Em seguida, adicione um controle Toolbar à aplicação e coloque-o na parte superior do formulário, onde estava a barra de ferramentas antiga. Na janela Properties, selecione a propriedade Buttons e clique no botão à direita.

o        Precisamos dar o mesmo comportamento da barra de ferramentas que foi excluída. Clique em Add para adicionar um botão à barra e modificar as propriedades: Name=bVoltar, TooltipText=Voltar, Text=””, Tag=1 e Sytle=PushButton.

o        Repita a etapa anterior para inserir o botão avançar:

Name=bAvancar,   TooltipText=”Avançar”, Text=””, Tag=2 e Sytle=PushButton

·         Substituição do ImageList1:

o        Remova o controle ImageList1. Adicione um controle ImageList. O controle deverá aparecer como um provedor adicional na parte inferior da IDE no Visual Studio .NET (veja Figura 6). Na janela Properties, selecione a propriedade Images e clique no botão à direita. E adicione duas imagens ao seu gosto.

o        Configure a propriedade ImageList do controle Toolbar1 para ImageList1. Em seguida, selecione a propriedade Buttons do controle Toolbar1 e configure a propriedade ImageIndex para cada botão. Pressione F5 para executar a aplicação.

 

image011.jpg

Figura 6. Controle ImageList é adicionado como um provider. Não é um controle visual.

·         Recriando os eventos:

o        As assinaturas dos eventos são diferentes para controles ActiveX e controles intrínsecos. É necessário recriar o evento que é executado quando o usuário dá um clique sobre a barra de ferramentas.

o        Comente o evento associado ao controle Toolbar antigo.

o        Para adicionar o evento ao novo Toolbar, selecione o controle Toolbar1 na guia da esquerda da janela de código do ambiente de desenvolvimento e, na guia da direita, o evento ButtonClick (Veja Figura 7).

 

 

image013.jpg

Figura 7. Criando evento Clique do controle Toolbar1.

o        Copie o código que foi comentado do Toolbar antigo para esse novo evento.

o        Substitua a expressão:

§          Select Case eventArgs.button.Index por

Select Case ToolBar1.Buttons.IndexOf(e.Button)+1

o        É necessário adicionar o valor +1, pois o Visual Basic 6.0 e o Visual Basic .NET definem as coleções de controles de formas diversas:  nas coleções .NET, o primeiro elemento possui o valor de “0” e não de “1” como antes.

·         Substituindo o controle MonthView1:

o        Remova o controle MonthView. Adicione um controle MonthCalendar.

o        Pressione F5 para executar a aplicação. Vão surgir erros de compilação indicando que o componente MonthView1 não está definido.

o        Altere o código do evento ButtonClick do controle ToolBar1 de acordo com a Listagem 10.

 

Listagem 10. Código alterado do evento ButtonClick do controle ToolBar1 após troca do controle MonthView pelo MonthCalendar do VB.NET.

Private Sub ToolBar1_ButtonClick( _

  ByVal sender As Object, ByVal e As System.Windows.Forms.ToolBarButtonClickEventArgs) _

  Handles ToolBar1.ButtonClick

        Select Case ToolBar1.Buttons.IndexOf(e.Button) + 1

            Case 1

                MonthCalendar1.SetDate(DateAdd(Microsoft.VisualBasic.DateInterval.Day, -1, MonthCalendar1.SelectionStart()))

            Case 2

                MonthCalendar1.SetDate(DateAdd(Microsoft.VisualBasic.DateInterval.Day, 1, MonthCalendar1.SelectionStart))

        End Select

End Sub

·         Substituindo o controle ProgressBar1:

o        Remova o controle ProgressBar1. Adicione um controle ProgressBar.

o        Configure as propriedades Minimum e Maximum para, respectivamente, 1 e 200.

o        Altere o código do controle Command1 para o código Listagem 11.

o        Recrie o evento Click do controle ProgressBar1.

 

Listagem 11. Código alterado do evento Click do controle Command1 após troca do controle ProgressBar1 por um controle do VB.NET.

Private Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click

        Dim i As Integer

                        Dim HoraInicio As Single

        For i = ProgressBar1.Minimum To ProgressBar1.Maximum

            HoraInicio = VB.Timer()

            Do While VB.Timer() - HoraInicio < 0.01

            Loop

 

               ProgressBar1.Value = i

   Next

End Sub

 

Execute o programa no Visual Basic .NET e compare sua funcionalidade com a do programa em Visual Basic 6.0. Para finalizar, remova as referências às seguintes bibliotecas do projeto: AxComCtl3, ComCtl3, MSComctlLib e AxMsComCtlLib.

Conclusões

Nesta segunda parte falei sobre os pontos que impedem o Upgrade Wizard fazer a conversão automática de aplicações que fazem ligação de dados usando DAO ou RDO. Expliquei que a migração é automática quando a aplicação utiliza ADO. Além disso, expliquei porque ainda é possível utilizar ADO em ADO.NET. Adotei como estratégia para as aplicações que usam DAO convertê-las, ainda no VB 6.0, para ADO. Mas, como eu já informei, é melhor que você utilize os componentes do ADO.NET para tirar proveito dos novos componentes e do modelo desconectado oferecido pelo framework. Além disso, comentei sobre os problemas que você poderá encontrar quando for migrar alguma aplicação que usa controles ActiveX. Adotei como estratégia a migração da aplicação para VB.NET e, em seguida, substituição dos controles ActiveX por semelhantes no VB.NET. Vimos também que, mesmo não substituindo os controles, ainda é possível utilizá-los como ActiveX. O upgrade Wizard gera todo código necessário para fazer a comunicação com esse componente COM - Wrapper.

Na terceira e última parte irei abordar algumas dicas de performance e mostrarei os passos necessários para construir uma aplicação web com as mesmas funcionalidades de uma aplicação windows forms.