Clique para classificar e enviar comentários
MSDN
Biblioteca MSDN
Artigos Técnicos
Visual Studio
VisualStudio.NET
 Controle de Estoque no Pocket PC: d...
Controle de Estoque no Pocket PC: do eVB ao VB .NET

por Leandro Machado

Para ler todas as matérias da MSDN Magazine, assine a revista no endereço www.neoficio.com.br/msdn

Criar projetos para dispositivos móveis é desafiador. Por um lado você tem todo o poder de um Pocket PC nas mãos, e por outro os dados que estão no servidor. Então, como se comunicar com o banco de dados no servidor e usar as funcionalidades do Pocket PC para desenvolver um projeto de coletores de dados para controlar o estoque? O objetivo deste artigo é ensinar como fazer isso usando a linguagem VB.NET e o bando de dados SQL Server. Em alguns momentos, farei uma comparação entre o eVB (Embebbed Visual Basic) e o VB.NET (Visual Basic .NET).

Inicialmente, eu precisava escolher uma linguagem de desenvolvimento para a aplicação. A Microsoft oferecia duas opções de linguagens para o desenvolvimento Embedded: o C e o modelo visual , o eVB. A opção pela linguagem baseada em visual foi natural, na medida em que toda a equipe de desenvolvimento já a utilizava para o desenvolvimento de aplicações Desktop e uma vez que o custo de aprendizado poderia ser minimizado com essa escolha.

Primeiramente, desenvolvi uma aplicação Off-line sincronizando os dados pelo ActiveSync. Os motivos: o alto custo em equipamentos para conectar os dispositivos à rede e, principalmente, a complexidade de codificar a aplicação para acessar diretamente o servidor SQL Server.

Com o lançamento do Visual Studio.Net 2003 e com a popularização da tecnologia Wi-Fi, optei novamente por trocar a plataforma de desenvolvimento. Essa decisão foi a mais fácil de minha carreira profissional, haja vista as incomparáveis facilidades proporcionadas pelo Visual Studio.Net.

A seguir, demonstrarei como fiz a primeira migração de um aplicativo desenvolvido em eVB para a plataforma .Net. Essa migração demandou apenas um dia de trabalho. Vale ressaltar que levei esse tempo porque separei algumas horas para ler o Help do programa.

Conferência de Estoque

O aplicativo em questão é simples e fácil de entender. Uma rotina do departamento de Expedição da empresa é a conferência física do estoque. No passado, o relatório de estoque era impresso em intermináveis páginas, as quais eram divididas entre os conferentes, que saíam em campo conferindo o que estava na lista. Quando encontravam algum item com uma quantidade diferente da especificada na lista, anotavam essa diferença na própria lista. O procedimento, além de muito demorado, gerava muitas dúvidas, e nunca se tinha certeza de que tudo havia sido conferido corretamente. O sistema de conferência pelo Pocket proporcionou maior velocidade e confiabilidade ao procedimento de conferência de estoque.

Tornando a aplicação On-Line

A grande mudança proporcionada pela troca da plataforma para o VS.Net consistiu em possibilitar o acesso a dados On-Line pela aplicação. A tecnologia utilizada foi a Web Services. Foi criado e publicado na Intranet da empresa um Web Service, o qual será consumido pela aplicação que roda no Pocket PC através da rede local, usando Wi-Fi.

No Web Service, foi criada uma função que retorna um DataSet que poderá ser usado em diferentes pontos do projeto. Como a aplicação trabalha desconectada, o Web Service é invocado no servidor, conecta a base de dados, monta um DataSet, retorna os dados à aplicação e se desconecta. Veja na Listagem 1 o código do Web Service com a função Pesquisa, o qual recebe como parâmetro uma variável do tipo String com a instrução SQL ou com a Stored Procedure desejada e, em seguida, processa e retorna um DataSet à aplicação.

Listagem 1 Web Service com a função Pesquisa

<WebMethod(Description:="Retorno de DataSet")> _
Public Function Pesquisa(ByVal xSql As String) As DataSet
  ‘Coloque a string de conexão com seu banco de dados
  Dim conexao As String =”String de conexão”
  Dim conn As SqlConnection
  Dim da As SqlDataAdapter
  Dim ds As DataSet
  conn = New SqlConnection(conexao)
  Try
    conn.Open()
    da = New SqlDataAdapter(xSql, conn)
    ds = New DataSet
    da.Fill(ds, "Tabela")
    Return ds
  Catch ex As Exception
    Throw ex
  Finally
    conn.Close()
  End Try
End Function

No Web Service, também foi criado uma Sub para operações de Insert, Update e Delete, que recebe como parâmetro uma variável do tipo String com a instrução SQL ou com a Stored Procedure desejada e processa a instrução. Caso ocorra algum erro durante o processamento da instrução, a Sub retornará o erro por meio da linha Throw ex (veja a Listagem 2).

Listagem 2 Sub para operações de Insert, Update e Delete

<WebMethod(Description:="RS sem Retorno")> _
Public Sub FazRSsr(ByVal xSql As String)
  ‘Coloque a string de conexão com seu banco de dados
  Dim conexao As String = “String de Conexão”
  Dim myConnection As New SqlConnection(conexao)
  myConnection.Open()
  Dim sql As String = xSql
  Dim myCommand As New SqlCommand(sql, myConnection)
  Dim myTrans As SqlTransaction
  myTrans = myConnection.BeginTransaction()
  myCommand.Connection = myConnection
  myCommand.Transaction = myTrans
  Try
    myCommand.ExecuteNonQuery()
    myTrans.Commit()
  Catch ex As Exception
    myTrans.Rollback()
    Throw ex
  Finally
    myConnection.Close()
  End Try
End Sub

Com o Web Service criado, o próximo passo é publicar no servidor com o IIS (Internet Information Server) da Intranet, já que o consumo desse Web Service seria feito apenas internamente, pela rede local.

No eVb o acesso a dados era feito por ODBC. Criava-se uma fonte de dados ODBC e usava-se o Microsoft ActiveSync para importar essa fonte de dados para o Pocket PC, gerando assim uma base de dados local no Pocket. A cada conexão do dispositivo à base, o ActiveSync cuidava de replicar os dados do Pocket com a base SQL Server. Essa sincronização eventualmente gerava conflitos, e nossos analistas eram obrigados a resolvê-los manualmente.

Criando uma nova aplicação

Abra o VS.Net 2003, clique em New Project ou pressione CTRL + SHIFT + N. Em Visual Basic Projects, selecione SmartDeviceApplication, escolha o nome do seu projeto e o local onde irá gravá-lo. Pressione OK e, na janela aberta, selecione em “What Platform do you want to target?” a opção “Pocket PC”. Por fim, clique no botão OK.

A Interface

A Toolbox do .Net é muito ampla e a quantidade de objetos e classes disponíveis é infinitamente maior do que no eVB, mas uma de minhas preocupações durante a migração foi manter o mesmo layout da interface, pois os usuários do sistema já estavam habituados com o layout desenvolvido em eVB. Mesmo optando por manter o layout, os ganhos de produtividade no desenvolvimento foram muitos e vocês verão agora o porquê.

Na Toolbox, selecione o objeto InputPanel, que será usado para mostrar um teclado na tela do Pocket PC de modo a permitir que o usuário digite os dados. Use o código da Listagem 3 para habilitar ou desabilitar a visualização do teclado.

Listagem 3 Habilita ou desabilita a visualização do teclado

Private Sub txt_NumeroOrdem_GotFocus( _
  ByVal sender As Object, _
  ByVal e As System.EventArgs) _
  Handles txt_NumeroOrdem.GotFocus
  InputPanel1.Enabled = True
End Sub

Private Sub txt_NumeroOrdem_LostFocus( _
  ByVal sender As Object, _
  ByVal e As System.EventArgs) _
  Handles txt_NumeroOrdem.LostFocus
  InputPanel1.Enabled = False
End Sub

Em uma aplicação para Pocket PC, não é aconselhável o uso de muitos Forms para racionalizar o uso de memória. Uma boa saída para isso é o uso de TabControls, onde o programador pode inserir um desses objetos na tela, ajustá-lo ao tamanho da tela e usar quantos tabs forem necessários para a aplicação, economizando assim o uso de Forms. Veja na Figura 1 o formulário com os tabs criados.

Figura 1 Telas da aplicação

Cc518025.controleestoque1(pt-br,MSDN.10).gif

De cara notei uma grande mudança em relação ao eVB. Embora o recurso do objeto TabControl existisse no eVB, o gerenciamento da visualização dos Tabs precisava ser feito manualmente. Para cada Tab, era necessário o uso de um frame, o que reduzia ainda o espaço disponível na tela do Pocket. Dentro de cada Frame eram colocados os objetos. Tanto em ambientes de desenvolvimento como em execução, o evento click nas Tabs não executa nada, ou seja, o desenvolvedor é quem deve disparar uma rotina do tipo Frame1.Viseble=true e Frame2.Viseble=False.

No .Net esse gerenciamento é feito pelo próprio controle, e toda a codificação necessária no eVB torna-se desnecessária. Com o objeto inserido e dimensionado na tela, na barra Properties, clique na propriedade TabPages para exibir a janela de configuração TabPage Collection Editor, onde iremos criar e configurar cada Tab da página. No exemplo, utilizei Quatro Tabs (veja a Figura 1).

Na Tabpage1, serão exibidas informações das conferências geradas na Aplicação Desktop, que trabalha em conjunto com a aplicação do Pocket PC. Foram usados um DataGrid e um Label. Na Tabpage2, serão exibidos os dados da pesquisa de cada item de estoque a ser pesquisado e conferido. Foram usados nove TextBox, um Label para cada TextBox, quatro Buttons e um VScrollBar. Na Tabpage3, serão exibidos em um Grid os itens já conferidos. Foram usados dois Buttons, um DataGrid e um Label. Na Tabpage4, serão exibidos os itens conferidos, porém com dados físicos diferentes dos dados que constam na base SQL Server, denominados “Dúvidas”. Foram usados dois Buttons, um DataGrid e um Label.

Códigos

Antes de tudo precisamos fazer referência ao WebService que iremos consumir. Abra a janela do Solution Explorer, clique com o botão direito no nome do projeto e selecione Add Web Reference. Digite a URL completa do local (http://servidor/projeto/pagina.asmx) onde está publicado seu Web Service e use o botão GO para confirmar a existência deste. Em seguida, é só clicar em Add Reference.

Pressione F7 para abrir a janela de código e defina as seguintes variáveis globais:

Option Explicit
'código da conferência selecionada
Dim cellValue As Integer
'Código do Num de ordem conferida selecionado
Dim cellConf As Integer = 0 

O Tabpage1 é o padrão e é nele que o usuário deve selecionar a conferência de estoque com a qual pretende trabalhar. Essas conferências são geradas na aplicação Desktop pelos responsáveis por cada estoque da empresa. Como a empresa possui diversos estoques diferentes, o DataGrid colocado nesse Tabpage serve para listar os códigos de todas as conferências geradas no sistema Desktop. No evento Load do Form, digite o código da Listagem 4.

Listagem 4 Código do Load do formulário

Private Sub Conferencia_Frm_Load(ByVal sender As Object, ByVal e As System.EventArgs) 
Handles MyBase.Load
  Cursor.Current = Cursors.WaitCursor
  CarregaGridConferencias()
  Cursor.Current = Cursors.Default
End Sub

Private Sub CarregaGridConferencias()
  'Configura o estilo de formatação do grid
  'A propriedade MappingName = "Tabela" é devido ao
  'retorno .Tables("Tabela") do WebService
  Dim style As New DataGridTableStyle
  style.MappingName = "Tabela"

  'Para cada coluna do grid, que deseja formatar
  'deve-se criar um DataGridTextBoxColumn
  Dim tcol As New DataGridTextBoxColumn
  With tcol
    .HeaderText = "Conferência"
    .MappingName = "ConfCodigo"
    .Width = 100
  End With
  Dim tcol2 As New DataGridTextBoxColumn
  With tcol2
    .HeaderText = "Data"
    .MappingName = "ConfData"
    .Width = 100
  End With

  'Adicione os DataGridTextBoxColumn ao
  'DataGridTableStyle
  style.GridColumnStyles.Add(tcol)
  style.GridColumnStyles.Add(tcol2)

  'Adicione os DataGridTableStyle ao DataGrid
  dtg_Conferencia.TableStyles.Add(style)

  'Instancia o WebService e carrega o grid
  Try
    Dim WS As New WebReference.Service1
    dtg_Conferencia.DataSource = WS.Pesquisa("sp_PDA_Conferencia").Tables("Tabela").DefaultView
  Catch ex As Exception
    Msgbox("Erro : " & ex.Message, MsgBoxStyle.Critical, "ERRO!")
  End Try
End Sub

Note que na rotina CarregaGridConferencias() a maior parte da codificação trata apenas da formatação do DataGrid, tanto das linhas quanto das colunas. Usei a classe DataGridTableStyle porque ela facilita a formatação e exibição dos dados no Grid.

Os dados do banco de dados SQL Server são carregados no DataGrid através do consumo do Web Service criado no início do artigo. No consumo do Web Service, usei a estrutura Try/Catch para tratar o erro e, se não fosse esse tratamento, a codificação estaria resumida a duas linhas.

Dim WS As New WebReference.Service1
dtg_Conferencia.DataSource = WS.Pesquisa("sp_PDA_Conferencia").Tables("Tabela").DefaultView

O parâmetro do Web Service é o nome de Stored Procedure (veja a Listagem 5), mas seria possível passar qualquer código SQL.

Listagem 5 Stored Procedure

CREATE Procedure sp_PDA_Conferencia
as
Select ConfCodigo, ConfData
From ConfereEstoque
GO

No eVb não existe o DataGrid, mas sim algo parecido com o MSFlexGrid. Esse recurso era outro grande gerador de código, pois a formatação e a população do Grid eram feitas manualmente, linha por linha, coluna por coluna, célula por célula. Tudo manualmente. É necessário dizer que esse método manual de popular o Grid torna o carregamento dos dados extremamente lento, devido ao fato de o código processar individualmente todas as linhas do Recordset gerado para a tarefa.

Como os dados estão exibidos no GRID, o usuário precisa selecionar a conferência desejada usando a caneta no Grid que contém a conferência em que irá trabalhar (veja a Listagem 6).

Listagem 6 Seleciona um item no DataGrid

Private Sub dtg_Conferencia_Click( _
    ByVal sender As System.Object, _
    ByVal e As System.EventArgs) _
    Handles dtg_Conferencia.Click
  Cursor.Current = Cursors.WaitCursor
  Try
    LimpaCampos(TabPage2.Controls)
    ' Valor que guarda a Linha selecionada
    Dim vIntRow As Integer
    vIntRow = dtg_Conferencia.CurrentRowIndex
    'Seta a seleção para a Coluna 0, que é a coluna
    'do código. A linha da seleção é mantida na
    'variável vIntRow
    dtg_Conferencia.CurrentCell = _
        New DataGridCell(vIntRow, 0)

    Dim selectedCell As DataGridCell 
    selectedCell = dtg_Conferencia.CurrentCell
    Dim selectedItem As Object
    selectedItem = _
      dtg_Conferencia.Item(selectedCell.RowNumber, _
      selectedCell.ColumnNumber)
    cellValue = CInt(selectedItem)
    'Preenche o Label com o Código da Conferencia
    'selecionado no grid
    lbl_Codigo.Text = "Código Selecionado:" & _
        cellValue.ToString
    Me.Text = "Conferência:" & cellValue.ToString
  Catch ex As Exception
    Msgbox("Erro : " & ex.Message, MsgBoxStyle.Critical, "ERRO!")
  Finally
    Cursor.Current = Cursors.Default
  End Try
End Sub

Selecionado o Código da Conferência, nossa Tab de trabalho passa a ser a Tabpage2. Nessa Tab, o usuário digita o número de ordem que identifica o item a ser conferido. Quando ele selecionar o Botão “Pesquisa”, será feito um novo consumo ao Web Service para carregar as características do item na tela Pocket PC (veja a Listagem 7).

Listagem 7 Código do botão Pesquisa

Private Sub btn_Pesquisa_Click( _
  ByVal sender As System.Object, _
  ByVal e As System.EventArgs) _
  Handles btn_Pesquisa.Click
  Cursor.Current = Cursors.WaitCursor
  If cellValue = 0 Then
     Msgbox("Você não selecionou nenhum Código de Conferência!", 
     MsgBoxStyle.Information, "Atenção!")
     Cursor.Current = Cursors.Default
     Exit Sub
  ElseIf IsNumeric(txt_NumeroOrdem.Text.Trim) = False Then
     Msgbox("Você não digitou números válidos!", MsgBoxStyle.Information, "Atenção!")
     Cursor.Current = Cursors.Default
     Exit Sub
  Else
     MoveCampos()
     Cursor.Current = Cursors.Default
  End If
End Sub
    
Sub MoveCampos()
  Try
    Dim WS As New WebReference.Service1
    Dim dts As New DataSet
    dts = WS.Pesquisa("sp_PDA_PesquisaSubOrdem " & cellValue & "," & CInt(txt_NumeroOrdem.Text))
    If dts.Tables("Tabela").Rows.Count = 0 Then
       Dim vStrMsg As String = _
       Msgbox("Produto não encontrado!Deseja Marcar como Dúvida?", MsgBoxStyle.YesNo, "Atenção!")
       If vStrMsg = MsgBoxResult.No Then
          Exit Sub
       Else
          HabilitaText(TabPage2.Controls)
          txt_Ordem.Text = txt_NumeroOrdem.Text.Trim
          txt_Status.Enabled = False
          btn_Confirma.Enabled = False
          btn_SalvaDuvida.Text = "Salvar Dúvida!"
       End If
    Else
       LimpaCampos(TabPage2.Controls)
       txt_NumeroOrdem.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "SubOrdem"))
       txt_Descricao.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "SubDescricao"))
       txt_Diametro.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "SubDiametro"))
       txt_Formato.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "SubFormato"))
       txt_Gm2.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "SubGramatura"))
       txt_Largura.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "SubLargura"))
       txt_Ordem.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "SubOrdem"))
       txt_Quantidade.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "SubQuantidade"))
       txt_Status.DataBindings.Add(New Binding("Text", dts.Tables("Tabela"), "ConfSimNaoDuvida"))
       If txt_Status.Text = "C" Then
          txt_Status.Text = "CONFERIDO"
       ElseIf txt_Status.Text = "D" Then
          txt_Status.Text = "DÚVIDA"
       ElseIf txt_Status.Text = "N" Then
          txt_Status.Text = "NÃO CONFERIDO"
       End If
    End If
  Catch ex As Exception
    Msgbox("Erro : " & ex.Message, MsgBoxStyle.Critical, "ERRO!")
  Finally
    Cursor.Current = Cursors.Default
  End Try
End Sub

O mais importante do código da Listagem 7 é novamente o consumo do Web Service. Se o Web Service não retornar nenhum valor no DataSet, sugerimos ao usuário marcar o item como “Dúvida”, caso contrário colocamos os dados de retorno do Web Service que estão no Data Set nos TextBox correspondentes.

Veja na Listagem 8 um exemplo para gravar Item como conferido no banco de dados.

Listagem 8 Gravar dados no banco de dados

Private Sub btn_Confirma_Click( _
   ByVal sender As System.Object, _
   ByVal e As System.EventArgs) _
   Handles btn_Confirma.Click
  'Verifica se há alguma coisa preenchida na tela
  'antes de fazer o update
  Cursor.Current = Cursors.WaitCursor
  If txt_Ordem.Text = "" Then
     Msgbox("Não há nada em Tela para ser Marcado como Conferido!", 
     MsgBoxStyle.Exclamation, "Atenção!")
     Cursor.Current = Cursors.Default
     Exit Sub
  End If
  'Rotina para ver se número não foi conferido
  If txt_Status.Text <> "NÃO CONFERIDO" Then
     Msgbox("Esse número consta como conferido. Você não pode salvar duas vezes!", 
     MsgBoxStyle.Exclamation, "Atenção!")
     Cursor.Current = Cursors.Default
     Exit Sub
  End If
  Dim WS As New WebReference.Service1
  Dim xSql As String = "sp_PDA_UpdateConferido " & cellValue & "," & txt_Ordem.Text
  Try
     WS.FazRSsr(xSql)
     Msgbox("Conferido!", MsgBoxStyle.Information, "OK!")
     LimpaCampos(TabPage2.Controls)
     dtg_Conferidos.DataSource = Nothing
     dtg_Duvida.DataSource = Nothing
  Catch ex As Exception
     Msgbox("Erro Confirmar: " & ex.Message, MsgBoxStyle.Critical, "ERRO!")
  Finally
     Cursor.Current = Cursors.Default
  End Try
End Sub

O consumo do Web Service no código da Listagem 8 destina-se a gravar dados no banco de dados. Passei uma Stored Procedure com o código do item conferido para o Web Service, que cuidou de gravar os dados na base SQL Server. Caso o Web Service tenha algum problema para gravar os dados, o tratamento do Catch mostrará um MsgBox com o erro.

Os Tabpages3 e 4 possuem DataGrids para ajudar o usuário a verificar o que foi gravado como conferido e o que foi gravado como dúvida. O código é basicamente consumir o mesmo Web Service para carregar o DataGrid e a formatação usa a mesma Classe de Formatação de Grid utilizada acima.

Quando o item pesquisado não for encontrado na Base de Dados, o usuário deverá digitar os dados do item e gravá-lo na base como “Dúvida”. Para executar esse procedimento, consumi a mesma Sub do Web Service usado para gravar o Item como “Conferido”, passando para isso o nome da Stored Procedure adequada ao Web Service.

Conclusão

Com este projeto, o tempo de execução de conferências de estoque foi reduzido à metade. E, com o complemento do programa na aplicação Desktop, o tempo para solução das dúvidas também foi reduzido à metade, pois com a aplicação migrada e funcionando On-Line os encarregados puderam acompanhar de seus Desktops o andamento da conferência em tempo real.

A partir deste projeto, a equipe ganhou em produtividade e desenvolveu outros aplicativos com sucesso em muito menos tempo do que era feito no eVB. Além disso, não foram mais necessárias correções manuais resultantes de falhas na replicação e sincronização dos dados.

O projeto em .Net economizou muito na codificação, se comparado ao eVB, mas o que mais tornou interessante a migração foi o fato de ela nos permitir utilizar a mesma plataforma de desenvolvimento que a aplicação Desktop. Como as duas aplicações se completam, isso torna o desenvolvimento muito mais produtivo.

Leandro Machado (leandrobcm@kmpapel.com.br) é pós-graduado em Análise de Sistemas e atualmente gerencia o departamento de TI da KM Indústria e Comércio de Papel.

OLHO: Fiz a migração em apenas um dia de trabalho. Vale ressaltar que levei esse tempo porque separei algumas horas para ler o Help do programa.

© 2009 Microsoft Corporation. Todos os direitos reservados. Termos de Uso | Marcas Comerciais | Política de Privacidade
Page view tracker