Desenvolvendo soluções com o Microsoft InfoPath

Por Patrick Halstead

Este artigo é um extrato do artigo Desenvolvendo soluções com o Microsoft InfoPath (este artigo contém links para páginas em inglês), da Microsoft Press (ISBN 0-7356-2116-0, copyright Microsoft Press 2004. Todos os direitos reservados). Uma parte do Capítulo 5: Design avançado de formulários, está adaptada aqui e descreve como trabalhar com anexação de arquivos e controles de imagem.

Patrick Halstead fundou a Autonomy Systems LLC e liderou o desenvolvimento de soluções para a primeira versão do InfoPath. Patrick é um MVP 2004 da Microsoft em Microsoft Office System-InfoPath. Vani Mandava-Teredesai é engenheira de projeto da Lead Software para testes da equipe de produto do InfoPath e trabalhou no InfoPath desde o início. Matthew Blain é diretor da Software Development for Serriform, LLC, e trabalhou na Microsoft como desenvolvedor do Internet Explorer, e na equipe que desenvolveu o InfoPath posteriormente.

Nenhuma parte deste capítulo pode ser reproduzida, armazenada em um sistema de recuperação nem transmitida de nenhuma forma ou por nenhum meio - eletrônico, mecânico, por fotocópia, gravação nem de outra forma - sem a permissão prévia por escrito do editor, a não ser no caso de citações breves incluídas em artigos críticos ou revisões.

Capítulo 5: Design avançado de formulários

Nesta página
Anexação de arquivos e controles de imagemAnexação de arquivos e controles de imagem
Opções de controle de imagemOpções de controle de imagem
Opções de anexação de arquivosOpções de anexação de arquivos
Controlando a anexação de arquivos com códigoControlando a anexação de arquivos com código

Anexação de arquivos e controles de imagem

Já vimos os controles que ligam a entrada do usuário diretamente aos dados XML por trás do formulário, como os controles Text Box, Rich Text Boxe Date Picker. Todos esses controles ligam ao texto em nós do XML; porém, dados binários são texto. É aí que os controles File Attachment e Picture entram em cena. Esses controles funcionam com dados binários e armazenam os dados no XL por meio da codificação na base 64. Quando esses controles são usados no designer e quando se preenche um formulário, a codificação é transparente e funciona exatamente como você esperaria. Para processar os dados salvos em outro aplicativo, como um serviço da Web, é preciso decodificar as informações.

Vamos demonstrar esses recursos criando um formulário para controlar a observação de animais.

Criando um novo modelo de formulário que inclua uma imagem

1.

Inicie o InfoPath.

2.

Na caixa de diálogo Fill Out A Form, clique em Design A Form.

3.

No painel de tarefas Design A Form, clique em New Blank Form.

4.

Digite Animal Sightings na parte superior do formulário; pressione Enter.

5.

No menu Insert, escolha More Controls para exibir a lista de controles disponíveis.

6.

Na seção File And Picture do painel de tarefas Controls, clique em Picture.

7.

Na caixa de diálogo Insert Picture Control, selecione Included In The Form para certificar-se de que a imagem será salva quando o formulário for salvo; em seguida, clique em OK para inserir o controle Picture na exibição.

8.

Clique com o botão direito do mouse no controle Picture recém-inserido e escolha Picture Properties.

9.

Na caixa de diálogo Picture Properties (mostrada na Figura 1), altere o Nome de campo, de field1 para AnimalPicture. Observe duas outras opções que não alteraremos neste exemplo: especificando uma imagem padrão e permitindo ao usuário alterar a imagem exibida.


Figura 1. Caixa de diálogo Picture Properties

10.

Clique em OK para fechar a caixa de diálogo.

11.

Clique abaixo do controle Picture, pressione Enter para inserir uma nova linha e, em seguida, digite Animal Name.

12.

Insira um controle Text Box.

13.

Clique com o botão direito do mouse na caixa de texto recém-inserida e escolha Text Box Properties.

14.

Na caixa de diálogo Text Box Properties, altere Field Name, de field2 para AnimalName, e, em seguida, clique em OK para fechar a caixa de diálogo.

15.

Salve o modelo de formulário como Animal Sightings.xsn.

Opções de controle de imagem

O controle Picture pode operar em um dos dois modos totalmente diferentes: Incluído no formulário e Como um link. O primeiro modo salva os dados da imagem no formulário, e o segundo exibe uma imagem vinculada ao formulário, mas não salva com ele. Vimos o primeiro modo no exemplo anterior; continuaremos com as opções de controle neste modo antes de discutir o controle no modo de link.

Vimos também a caixa de diálogo Picture Properties. Não alteramos nenhuma das propriedades específicas de imagens: a imagem padrão e a habilidade do usuário em alterar a imagem.

A imagem padrão funciona da mesma forma que um valor padrão em relação a caixas de texto e outros controles: ela é armazenada com o modelo no arquivo template.xml usado quando novos formulários são criados e também no arquivo sampledata.xml utilizado pelo designer. Quando um usuário preenche um novo formulário, a imagem padrão é copiada para os dados do formulário e é exibida sempre que o nó dos dados for exibido. Se o valor padrão do modelo for alterado posteriormente, a imagem padrão será alterada em novos formulários criados após a alteração, ao passo que os formulários criados anteriormente à alteração ainda terão a imagem antiga.

A segunda opção é uma caixa de seleção rotulada como "Permitir que o usuário navegue, exclua e substitua imagens". Essa caixa de seleção se aplica à exibição, não aos dados. Em outras palavras, se a mesma imagem for exibida duas vezes no seu modelo, é possível ter um lugar onde os usuários possam alterar a imagem e outro lugar onde não possam alterar. Também é possível desabilitar o controle por meio de formatação condicional, na guia Exibir, da caixa de diálogo de propriedades.

O Picture Control in Link Mode pode incluir a referência para uma imagem em um formulário, selecionando-se As A Link na caixa de diálogo Insert Picture Control. A referência funciona de modo bem semelhante a um controle de hiperlink: a imagem exibida no formulário é carregada a partir do URL especificado no nó de dados ligados.

Agora adicionaremos um controle File Attachment ao formulário, possibilitando a comparação entre os dois controles.

Adicionando o controle de arquivo a um formulário

1.

Continue o design do formulário de Observação de animais.

2.

Clique abaixo da linha Animal Name para colocar o cursor na extremidade do formulário.

3.

Digite Attached Info.

4.

No menu Insert , escolha More Controls.

5.

Na seção File And Picture do painel de tarefas Controls, clique em File Attachment.

6.

Clique com o botão direito do mouse no controle File Attachment recém-inserido e escolha File Attachment Properties.

7.

Na caixa de diálogo File Attachment Properties (mostrada na Figura 2), altere o Nome de campo, de field1 para AnimalAttachment e clique em OK.

8.

Salve e feche o modelo de formulário.


Figura 2. Caixa de diálogo File Attachment Properties

Início da páginaInício da página

Opções de controle de imagem

As propriedades de Anexação de arquivos são semelhantes às propriedades de Imagem. Pode-se especificar um arquivo padrão, que é adicionado aos arquivos template.xml e sampledata.xml. Por padrão, o InfoPath permite qualquer tipo de arquivo, com exceção dos arquivos marcados como não seguros, como o .bat e o .exe. O InfoPath usa um modelo de segurança semelhante ao Microsoft Outlook, descrito no artigo 829982 da Base de Dados de Conhecimento. Para obter mais informações, consulte Anexando arquivos no InfoPath 2003 (em inglês).

Também é possível restringir os tipos de arquivo permitidos para um controle específico em um determinado subconjunto de tipos de arquivos. Para isso, clique com o botão direito do mouse em um controle File Attachment na exibição e escolha File Attachment Properties. Selecione a caixa de seleção Allow The User To Attach Only The Following File Types e digite a lista de extensões permitidas, separadas por ponto-e-vírgula. Observe que esta restrição aplica-se apenas ao controle na exibição: se o controle File Attachment for usado em exibições múltiplas, será preciso definir as propriedades de cada instância do controle.

Preenchendo um formulário que inclua uma imagem e um anexo de arquivo

Escolha Fill Out A Form no menu File.

1.

Na caixa de diálogo Fill Out A Form, clique em Open.

2.

Localize e selecione o modelo Animal Sightings.xsn criado anteriormente e, em seguida, clique em Open.

3.

Clique no controle Picture na exibição rotulada como Click Here To Insert A Picture.

4.

Na caixa de diálogo Insert Picture, selecione uma imagem no disco rígido e clique em Insert.

5.

Clique no controle File Attachment rotulado como Click Here To Attach A File.

6.

Selecione o mesmo arquivo usado no controle Picture, e, em seguida, clique em Insert.

7.

Digite o nome do animal. O formulário completo é mostrado na Figura 3.

8.

Salve o formulário como My Animal.xml.

9.

Feche o InfoPath.

10.

Abra o arquivo My Animal.xml em um editor de textos. Você verá que a imagem foi salva no arquivo XML por meio da codificação na base 64. Ela terá a seguinte aparência:

<my:AnimalPicture>/9j/4AAQSkZJRgABAQEAYABgAAD . . . </my:AnimalPicture> 
<my:AnimalName>Kitten</my:AnimalName> 
<my:AnimalAttachment>x0lGQRQAAAABAAAAAAAAAN5I . . . </my:AnimalAttachment>


Figura 3. Formulário com os controles Picture e File Attachment preenchidos

Observe que my:AnimalName está em texto simples, mas my:AnimalPicture e my:AnimalAttachment não estão. Os dois últimos são a imagem codificada. Observe também que o texto em my:AnimalPicture é diferente do texto em my:AnimalAttachment, muito embora sejam o mesmo arquivo. Isso acontece porque o anexo contém mais informações armazenadas do que os bytes binários do arquivo anexo: ele contém também o nome de arquivo e algumas informações internas (descritas na Tabela 1, adiante neste capítulo). O usuário do formulário pode anexar facilmente um arquivo ou uma imagem ao formulário, mas o desenvolvedor que precisa decodificar os dados fora do InfoPath deve entender o formato (como discutido posteriormente no capítulo).

Início da páginaInício da página

Opções de anexação de arquivos

Pode-se controlar as ações do controle de anexação de arquivos em código através do método ExecuteAction, e, de modo semelhante, pode-se adicionar e remover, por programação, seções repetidas (como descrito no Capítulo 3). As ações que têm suporte são xFileAttachment::attach, xFileAttachment::saveAs e xFileAttachment::remove. Essas ações abrem a caixa de diálogo File Attachment, a caixa de diálogo Save As e removem o anexo relacionado, respectivamente. Para usar esses métodos, o nó correto precisa ser selecionado na exibição e o valor xmlToEdit correspondente precisa ser usado. Use um método como SelectNodes para selecionar o nó na exibição. Examine o atributo name do nó xsf:xmlToEdit em manifest.xsf para obter o valor xmlToEdit.

A função code-behind do Visual Basic a seguir adiciona um novo item a uma tabela ou seção repetida e, em seguida, abre a caixa de diálogo File Attachment para um anexo nessa seção. Se o usuário cancela a caixa de diálogo File Attachment, o código remove a linha inserida.

AddAttachment(ByVal xmlToEditRepeatingSection, _ 
   ByVal xmlToEditAttachment, ByVal xpathAttachment) 
   Dim nodeInserted As IXMLDOMNode 
   Dim nodeAttach As IXMLDOMNode 
   ' Add a new item to the group 
   thisXDocument.View.ExecuteAction("xCollection::insert", _ 
       xmlToEditRepeatingSection) 
   ' Select the node in the group with the attachment data. 
   ' After insert ExecuteAction, the new node will be selected. 
   ' The attachment data node must be selected for the next ExecuteAction. 
   nodeInserted = thisXDocument.View.GetSelectedNodes().Item(0) 
   nodeAttach = nodeInserted.selectSingleNode(xpathAttachment) 
   thisXDocument.View.SelectNodes(nodeAttach, Type.Missing, Type.Missing) 
   ' Open the Attachment dialog box. 
   thisXDocument.View.ExecuteAction("xFileAttachment::attach", _ 
       xmlToEditAttachment) 
   ' Check to see if an attachment was added.  
   If (nodeAttach.text.Length = 0) Then 
       ' No attachment added, remove the entire inserted row. 
       nodeInserted.parentNode.removeChild(nodeInserted) 
   End If Function

Para chamar a função, insira um botão na exibição e codifique-o para chamar a função. Se o xmlToEdit do grupo repetido for AttachmentGroup_1, o xmlToEdit do anexo será AttachmentData_1, e o nome do nó de anexo será my:AttachmentData, a função será chamada do seguinte modo: AddAttachment("AttachmentGroup_1", " AttachmentData_1", "my:AttachmentData").

Adicionando uma imagem a tinta a um formulário

As imagens a tinta funcionam de modo semelhante aos anexos com imagens. É possível adicionar um controle Ink Picture, com ou sem uma imagem de plano de fundo, a um formulário. Uma imagem de plano de fundo é salva como parte do modelo de formulário, não como parte de cada um dos formulários preenchidos. As anotações preenchidas a tinta são salvas em cada formulário como dados codificados na base 64. Para preencher um controle Ink Picture, é preciso um Tablet PC. (Não é necessário um Tablet PC para projetar um formulário com uma imagem a tinta). O usuário de um Tablet PC pode também inserir uma imagem a tinta em um campo de texto rico que contenha a opção Full Rich Text habilitada.

Usando dados de controles de arquivo e imagem fora do InfoPath

Um controle de arquivo ou imagem usado inteiramente dentro de um formulário do InfoPath funciona de modo transparente para o usuário. Entretanto, se você desejar acessar os dados fora do InfoPath, será preciso decodificá-los. Isso envolve duas etapas: converter os dados do formato codificado na base 64 para um formato binário e determinar o nome e o tipo do arquivo. Nesta seção examinaremos a ferramenta .NET Windows Forms, que pode salvar imagens e arquivos anexados em um arquivo XML gerado pelo InfoPath. As mesmas técnicas podem ser usadas em um serviço da Web ou qualquer outra situação na qual seja necessário decodificar um anexo salvo em um formulário do InfoPath.

Usando o aplicativo de exemplo do gravador de anexos

1.

Localize o diretório InfoPathAttachmentSaver incluído no conteúdo correspondente.

2.

Inicie o InfoPathAttachmentSaver.exe.

3.

Clique em Browse, selecione o arquivo My Animal.xml criado anteriormente; em seguida, clique em Open.

4.

O aplicativo preenche o espaço para nome do nó raiz.

5.

No campo XPath, digite //my:AnimalAttachment.

6.

Clique em Decode Attachment. Você deverá ver o nome e o tamanho do arquivo que foi salvo na tela (como mostrado na Figura 4).


Figura 4. Usando a ferramenta Gravador de anexos para decodificar um anexo

7.

Clique em Save. Salve o arquivo em algum lugar no disco rígido. Compare o arquivo recém-salvo com o arquivo original. Eles devem ser iguais.

8.

Clique em Decode Picture. O aplicativo exibe uma mensagem de erro informando que a imagem é um anexo de arquivo, e não continuará. Se você fosse salvar os dados decodificados, o cabeçalho do anexo de arquivo do InfoPath estaria na frente dele, e o arquivo, portanto, seria ligeiramente maior do que o arquivo original. Os dados binários resultantes não poderiam ser usados por outros aplicativos.

9.

Altere o valor XPath para //my:AnimalPicture.

10.

Clique em Decode Attachment. Você deverá obter um erro explicando que esse não é um anexo válido.

11.

Clique em Decode Picture. O nome de arquivo se torna um nome de arquivo desconhecido, e o tamanho é o tamanho da imagem.

12.

Salve o arquivo e feche o InfoPath. Observe que a ferramenta usa sempre a extensão de arquivo .jpg. O tipo real de arquivo pode ser determinado pesquisando-se os dados no arquivo. A ferramenta Gravador de anexos do InfoPath não contém esse recurso, porém, a maioria dos aplicativos de exibição de imagens pesquisa os dados e exibe corretamente a imagem, mesmo que ela não esteja verdadeiramente no formato JPEG.

Início da páginaInício da página

Controlando a anexação de arquivos com código

O gravador de anexos contém três classes: A FormInfoPathAttachmentSaver, que manipula a interface do usuário e também o carregamento e a gravação do XML; a InfoPathImage, que representa os dados de imagens armazenados em dados codificados na base 64 pelo InfoPath; e a InfoPathAttachment, que representa dados de anexo de arquivo armazenados em dados codificados na base 64 pelo InfoPath. As classes InfoPathImage e InfoPathAttachment funcionam da mesma forma: elas têm um método de fábrica que utiliza como entrada a seqüência de caracteres de dados e retorna uma instância da classe. A própria classe expõe duas propriedades - nome de arquivo e dados de arquivo.

É preciso fazer duas coisas ao decodificar uma imagem: ler os dados binários e verificar o tipo de arquivo. Veja a função de decodificação de uma imagem:

Shared Function DecodePicture(ByVal InnerTextAttachment As String) As InfopathPicture 
   Dim objPicture As InfopathPicture = New InfopathPicture 
   objPicture.FileData = Convert.FromBase64String(InnerTextAttachment) 
   ' To ensure that the image type is correct, you should sniff here. 
   ' Look at the first few bytes or so and look for the signature. 
   ' See each image format specification for more info 
   ' All we look for now is the InfoPath attachment signature 
   If objPicture.CheckInfoPathAttachmentSignature Then 
       Throw New Exception("Data represents an attachment, not a picture.") 
   End If 
   ' Since we have not sniffed the actual file type, we will assume jpg. 
   ' There is no stored filename, so use 'UnknownAttachedPicture'. 
   objPicture.FileName = "UnknownAttachedPicture.jpg" 
   Return objPicture Function

Ao decodificar um anexo de arquivo, é preciso decodificar os dados em uma estrutura binária. Essa estrutura é descrita na Tabela 1. A classe System.Runtime.InteropServices.Marshaldo .NET Framework permite converter a totalidade dos dados binários em uma estrutura do Visual Basic .NET de uma só vez.

Tabela 1. Estrutura binária do anexo de arquivo

MembroComprimento

Assinatura

4 bytes

Comprimento do cabeçalho (não inclui Assinatura, Nome de arquivo nem Dados de arquivo).

4 bytes (DWORD)

versão InfoPath

4 bytes (DWORD)

Reservado

4 bytes (DWORD)

Tamanho do arquivo

4 bytes (DWORD)

Comprimento de nome de arquivo (caracteres)

4 bytes (DWORD)

Nome de arquivo (UTF-16 codificado)

Comprimento do nome de arquivo * 2 bytes

Dados de arquivo

Bytes do tamanho de arquivo

Veja a função de decodificação de um anexo de arquivo:

' Visual Basic .NET representation of the InfoPath File Attachment header. 
<StructLayout(LayoutKind.Sequential, Pack:=1)> _ Structure AttachmentStructure 
   Public Signature As Int32 
   Public HeaderSize As Int32 
   Public InfopathVersion As Int32 
   Public Reserved As Int32 
   Public Filesize As Int32 
   Public FilenameCharLen As Int32 Structure 
Shared Function Base64EncodedLength(ByVal cb As Integer) As Integer 
   ' The base64 encoded header will always be 4/3 the size of the  
   ' binary version, rounded up to a multiple of 4. 
   Return Math.Ceiling(cb / 3) * 4 Function 
Shared Function BytesToHeaderStructure( _ 
   ByVal rg As Byte()) As AttachmentStructure 
   Dim cb As Integer 
   cb = Marshal.SizeOf(GetType(AttachmentStructure)) 
   If (rg.Length < cb) Then 
       Return Nothing 
   End If 
   Dim hGlobal As IntPtr 
   hGlobal = Marshal.AllocHGlobal(cb) 
   Marshal.Copy(rg, 0, hGlobal, cb) 
   Dim obj As AttachmentStructure 
   obj = Marshal.PtrToStructure(hGlobal, GetType(AttachmentStructure)) 
   Marshal.FreeHGlobal(hGlobal) 
   Return obj Function 
Shared Function DecodeAttachment( _ 
   ByVal InnerTextAttachment As String) As InfoPathAttachment 
   Dim objAttachment As InfoPathAttachment 
   objAttachment = New InfoPathAttachment 
   ' Decode the header from string to bytes. 
   Dim rgHeader As Byte() 
   Dim cbHeaderEncoded As Integer 
   Dim objHeader As AttachmentStructure 
   cbHeaderEncoded = Base64EncodedLength( _ 
       Marshal.SizeOf(objHeader.GetType)) 
   If (InnerTextAttachment.Length < cbHeaderEncoded) Then 
       Throw New Exception( _ 
           "Encoded string is not long enough to include header.") 
   End If 
   rgHeader = Convert.FromBase64String( _ 
       InnerTextAttachment.Substring(0, cbHeaderEncoded)) 
   ' Decode the header from bytes to structure. 
   objHeader = BytesToStructure(rgHeader, objHeader.GetType) 
   ' Check the signature. 
   ' 1095125447 is CIPA, or {199, 73, 70, 65}. 
   If Not (objHeader.Signature.Equals(1095125447)) Then 
       Throw New Exception( _ 
           "Signature does not match InfoPath attachment signature.") 
   End If 
   ' Check the header size.  
   ' The size of the header does not include the size of the signature. 
   Dim headerSizeRequired As Integer 
   headerSizeRequired = Marshal.SizeOf(objHeader.GetType) - 4 
   If Not (objHeader.HeaderSize.Equals(headerSizeRequired)) Then 
       Throw New Exception("Header size does not match expected size.") 
   End If 
   ' Decode the rest of the bytes. 
   Dim cbBodyEncoded As Integer 
   Dim rgBody As Byte() 
   cbBodyEncoded = Base64EncodedLength( _ 
       objHeader.FilenameCharLen * 2 + objHeader.Filesize) 
   If (InnerTextAttachment.Length < _ 
       (cbHeaderEncoded + cbBodyEncoded)) Then 
       Throw New Exception( _ 
           "Encoded string is not long enough to include body.") 
   End If 
   rgBody = Convert.FromBase64String( _ 
       InnerTextAttachment.Substring(cbHeaderEncoded, cbBodyEncoded)) 
   ' Copy out filename. 
   objAttachment.FileName = System.Text.Encoding.Unicode.GetString( _ 
       rgBody, 0, objHeader.FilenameCharLen * 2) 
   ' Copy out the rest of the file bytes. 
   objAttachment.FileData = Array.CreateInstance( _ 
       GetType(Byte), objHeader.Filesize) 
   rgBody.Copy(rgBody, objHeader.FilenameCharLen * 2, _ 
       objAttachment.FileData, 0, objHeader.Filesize) 
   Return objAttachment Function

Para codificar um anexo de arquivo, reverta o processo. É preciso também certificar-se de que qualquer arquivo XML gerado com um anexo contenha essa instrução de processamento na parte superior do arquivo. Se a instrução de processamento não estiver presente, o recurso de anexação de arquivo será desabilitado para essa instância específica do formulário.

© 2006 Microsoft Corporation. Todos os direitos reservados. Termos de uso.


Início da páginaInício da página