VB.net: o que aconteceu para controlar matrizes

A omissão de matrizes de controle do VB.NET é um desafio para quem ensina sobre matrizes.

  • Não é mais possível simplesmente copiar um controle, como uma caixa de texto, e colá-lo (uma ou várias vezes) para criar uma matriz de controle.
  • O código do VB.NET para criar uma estrutura semelhante a uma matriz de controle tem sido, em todos os livros sobre o VB.NET que eu comprei e on-line, muito mais longo e muito mais complexo. Falta a simplicidade de codificar uma matriz de controle encontrada no VB6.

Se você referenciar a biblioteca de compatibilidade do VB6, existem objetos que funcionam praticamente como matrizes de controle. Para entender o que quero dizer, basta usar o assistente de atualização do VB.NET com um programa que contém uma matriz de controle. O código é feio novamente, mas funciona. A má notícia é que a Microsoft não garante que os componentes de compatibilidade continuem sendo suportados, e você não deve usá-los.

O código VB.NET para criar e usar "matrizes de controle" é muito mais longo e muito mais complexo.

instagram viewer

Segundo a Microsoft, para fazer algo parecido com o que você pode fazer no VB 6, é necessário criar um "componente simples que duplique a funcionalidade da matriz de controle".

Você precisa de uma nova classe e um formulário de hospedagem para ilustrar isso. A classe realmente cria e destrói novos rótulos. O código completo da classe é o seguinte:

Public Class LabelArray
Herda o sistema. Coleções. CollectionBase
Private ReadOnly HostForm As _
Sistema. Janelas. Formulários. Formato
Função pública AddNewLabel () _
Como sistema. Janelas. Formulários. Rótulo
'Crie uma nova instância da classe Label.
Dim aLabel As New System. Janelas. Formulários. Rótulo
'Adicione o rótulo aos itens da coleção
'lista interna.
Eu. Lista. Adicionar (aLabel)
'Adicione o rótulo à coleção Controls
'do formulário referenciado pelo campo HostForm.
HostForm. Controles. Adicionar (aLabel)
'Defina propriedades iniciais para o objeto Label.
um rótulo. Top = Contagem * 25
um rótulo. Largura = 50
um rótulo. Esquerda = 140
um rótulo. Tag = Eu. Contagem
um rótulo. Texto = "Rótulo" & Eu. Contagem. Para sequenciar
Return aLabel
Função final
Sub-público público (_
Host ByVal como sistema. Janelas. Formulários. Formato)
HostForm = host
Eu. AddNewLabel ()
End Sub
Propriedade pública ReadOnly padrão _
Item (índice ByVal como inteiro) como _
Sistema. Janelas. Formulários. Rótulo
Obter
Retornar CType (lista Me. Item (índice), _
Sistema. Janelas. Formulários. Rótulo)
End Get
Propriedade final
Remover público Sub ()
'Verifique se há um rótulo para remover.
Se eu. Contagem> 0 Então
'Remova o último rótulo adicionado à matriz
'do formulário do host controla a coleção.
'Observe o uso da propriedade padrão em
'acessando a matriz.
HostForm. Controles. Remover (Eu (Cont. Me - 1))
Eu. Lista. RemoveAt (contagem de mim - 1)
Fim se
End Sub
Classe final

Para ilustrar como esse código de classe seria usado, você pode criar um formulário que o chama. Você precisaria usar o código mostrado abaixo no formulário:

Formulário de Classe Pública Herda o sistema. Janelas. Formulários. Formato. # Region "Código gerado pelo Windows Form Designer" 'Além disso, você deve adicionar a instrução:' MyControlArray = New LabelArray (Me) 'após a chamada InitializeComponent () no. 'código de região oculto. 'Declare um novo objeto ButtonArray. Dim MyControlArray As LabelArray. Private Sub btnLabelAdd_Click (_. Remetente ByVal como sistema. Objeto, _. ByVal e As System. EventArgs) _. Manipula btnLabelAdd. Clique. 'Chame o método AddNewLabel. 'de MyControlArray. MyControlArray. AddNewLabel () 'Altere a propriedade BackColor. 'do botão 0. MyControlArray (0) .BackColor = _. Sistema. Desenhando. Cor. Vermelho. End Sub. Sub Privado btnLabelRemove_Click (_. Remetente ByVal como sistema. Objeto, _. ByVal e As System. EventArgs) _. Manipula btnLabelRemove. Clique. 'Chame o método Remove do MyControlArray. MyControlArray. Retirar() End Sub. Classe final

Primeiro, isso nem faz o trabalho no Design Time, como costumávamos fazer no VB 6! E segundo, eles não estão em uma matriz, estão em uma coleção VB.NET - uma coisa muito diferente de uma matriz.

O motivo pelo qual o VB.NET não suporta a "matriz de controle" do VB 6 é que não existe uma "matriz" de "controle" (observe a alteração de aspas). O VB 6 cria uma coleção nos bastidores e faz com que ela apareça como uma matriz para o desenvolvedor. Mas não é uma matriz e você tem pouco controle sobre ela além das funções fornecidas pelo IDE.

O VB.NET, por outro lado, chama o que é: uma coleção de objetos. E eles entregam as chaves do reino ao desenvolvedor, criando a coisa toda em campo aberto.

Como exemplo do tipo de vantagens que isso oferece ao desenvolvedor, no VB 6 os controles tinham que ser do mesmo tipo e tinham que ter o mesmo nome. Como esses são apenas objetos no VB.NET, você pode torná-los diferentes tipos, dar nomes diferentes e ainda gerenciá-los na mesma coleção de objetos.

Neste exemplo, o mesmo evento Click lida com dois botões e uma caixa de seleção e exibe qual deles foi clicado. Faça isso em uma linha de código com o VB 6!

Private Sub MixedControls_Click (_
Remetente ByVal como sistema. Objeto, _
ByVal e As System. EventArgs) _
Botão de alças1.
Botão2.Clique, _
CheckBox1.Click
'A declaração abaixo deve ser uma declaração longa!
'É em quatro linhas aqui para mantê-lo estreito
'o suficiente para caber em uma página da web
Label2.Text =
Microsoft Visual básico. Certo (remetente. GetType. Para sequenciar,
Len (remetente. GetType. Para sequenciar) -
(InStr (remetente. GetType. ToString, "Formulários") + 5))
End Sub

O cálculo de substring é meio complexo, mas não é exatamente o que estamos falando aqui. Você pode fazer qualquer coisa no evento Click. Você pode, por exemplo, usar o Type do controle em uma instrução If para fazer coisas diferentes para controles diferentes.

Grupo de estudos de computação de Frank Feedback sobre matrizes

O Grupo de Estudos de Frank forneceu um exemplo com um formulário com 4 rótulos e 2 botões. O botão 1 limpa os rótulos e o botão 2 os preenche. É uma boa idéia ler a pergunta original de Frank novamente e observar que o exemplo que ele usou foi um loop usado para limpar a propriedade Caption de uma matriz de componentes Label. Aqui está o equivalente VB.NET desse código VB 6. Esse código faz o que Frank originalmente pediu!

Formulário de Classe Pública Herda o sistema. Janelas. Formulários. Formato. # Region "Código gerado pelo Windows Form Designer" Dim LabelArray (4) Como rótulo. 'declara uma matriz de rótulos. Sub-Formulário Privado1_Load (_. Remetente ByVal como sistema. Objeto, _. ByVal e As System. EventArgs) _. Lida com o MyBase. Carga. SetControlArray () End Sub. Sub SetControlArray () LabelArray (1) = Label1. LabelArray (2) = Label2. LabelArray (3) = Label3. LabelArray (4) = Label4. End Sub. Sub-botão privado1_Click (_. Remetente ByVal como sistema. Objeto, _. ByVal e As System. EventArgs) _. Botão de alças1. 'Botão 1 Limpar matriz. Dim a As Inteiro. Para a = 1 a 4. LabelArray (a) .Text = "" Próximo. End Sub. Botão secundário privado2_Click (_. Remetente ByVal como sistema. Objeto, _. ByVal e As System. EventArgs) _. Alças Button2.Click. 'Botão 2 Preencher matriz. Dim a As Inteiro. Para a = 1 a 4. LabelArray (a) .Text = _. "Matriz de controle" e CStr (a) Próximo. End Sub. Classe final

Se você experimentar esse código, descobrirá que, além de definir propriedades dos rótulos, também pode chamar métodos. Então, por que eu (e a Microsoft) nos esforçamos ao máximo para criar o código "Feio" na Parte I do artigo?

Eu tenho que discordar que é realmente uma "matriz de controle" no sentido clássico de VB. A matriz de controle do VB 6 é uma parte suportada da sintaxe do VB 6, não apenas uma técnica. De fato, talvez a maneira de descrever esse exemplo seja uma matriz de controles, não uma matriz de controle.

Na Parte I, reclamei que o exemplo da Microsoft SOMENTE funcionava em tempo de execução e não no tempo de design. Você pode adicionar e excluir controles de um formulário dinamicamente, mas tudo deve ser implementado no código. Você não pode arrastar e soltar controles para criá-los como no VB 6. Este exemplo funciona principalmente em tempo de design e não em tempo de execução. Você não pode adicionar e excluir controles dinamicamente em tempo de execução. De certa forma, é o oposto completo do exemplo da Parte I.

O exemplo clássico da matriz de controle do VB 6 é o mesmo implementado no código do VB .NET. Aqui no código VB 6 (extraído de Mezick & Hillier, Guia do Exame de Certificação do Visual Basic 6, p 206 - ligeiramente modificado, pois o exemplo no livro resulta em controles que não podem ser vistos):

Dim MyTextBox como VB.TextBox. Static intNumber como Inteiro. intNumber = intNumber + 1. Defina MyTextBox = _. Eu. Controles. Adicione ("VB.TextBox", _. "Texto" e intNumber) MyTextBox. Texto = MyTextBox. Nome. MyTextBox. Visível = Verdadeiro. MyTextBox. Esquerda = _. (intNúmero - 1) * 1200

Mas, como a Microsoft (e eu) concordamos, as matrizes de controle do VB 6 não são possíveis no VB.NET. Portanto, o melhor que você pode fazer é duplicar a funcionalidade. Meu artigo duplicou a funcionalidade encontrada no exemplo Mezick & Hillier. O código do Grupo de Estudos duplica a funcionalidade de poder definir propriedades e chamar métodos.

Portanto, o ponto principal é que realmente depende do que você deseja fazer. O VB.NET não tem tudo isso como parte da linguagem - ainda - mas, no final das contas, é muito mais flexível.

A opinião de John Fannon sobre as matrizes de controle

John escreveu: Eu precisava de matrizes de controle porque queria colocar uma tabela simples de números em um formulário em tempo de execução. Eu não queria a náusea de colocá-los todos individualmente e queria usar o VB.NET. A Microsoft oferece uma solução muito detalhada para um problema simples, mas é uma marreta muito grande quebrar uma noz muito pequena. Depois de algumas experiências, acabei encontrando uma solução. Aqui está como eu fiz isso.

O exemplo Sobre o Visual Basic acima mostra como você pode criar uma caixa de texto em um formulário, criando uma instância do objeto, definindo propriedades e adicionando-o à coleção Controls que faz parte do Form objeto.

Dim txtDataShow como novo TextBox
txtDataShow. Altura = 19
txtDataShow. Largura = 80
txtDataShow. Localização = Novo Ponto (X, Y)
Eu. Controles. Adicionar (txtDataShow)
Embora a solução da Microsoft crie uma classe, concluí que seria possível agrupar tudo isso em uma sub-rotina. Toda vez que você chama essa sub-rotina, você cria uma nova instância da caixa de texto no formulário. Aqui está o código completo:

Public Class Form1
Herda o sistema. Janelas. Formulários. Formato

# Region "Código gerado pelo Windows Form Designer"

Private Sub BtnStart_Click (_
Remetente ByVal como sistema. Objeto, _
ByVal e As System. EventArgs) _
Manipula btnStart. Clique

Dim I Como Inteiro
Dim sData As String
Para I = 1 a 5
sData = CStr (I)
Chamar AddDataShow (sData, I)
Próximo
End Sub
Sub AddDataShow (_
ByVal sText como String, _
ByVal I Como Inteiro)

Dim txtDataShow como novo TextBox
Dim UserLft, UserTop As Inteiro
Dim X, Y como número inteiro
UserLft = 20
UserTop = 20
txtDataShow. Altura = 19
txtDataShow. Largura = 25
txtDataShow. TextAlign = _
Alinhamento horizontal. Centro
txtDataShow. BorderStyle = _
Estilo de borda. FixedSingle
txtDataShow. Text = sText
X = UserLft
Y = UserTop + (I - 1) * txtDataShow. Altura
txtDataShow. Localização = Novo Ponto (X, Y)
Eu. Controles. Adicionar (txtDataShow)
End Sub
Classe final
Muito bom argumento, John. Isso certamente é muito mais simples que o código da Microsoft... então eu me pergunto por que eles insistiram em fazer dessa maneira?

Para começar nossa investigação, vamos tentar alterar uma das atribuições de propriedade no código. Vamos mudar

txtDataShow. Altura = 19
para

txtDataShow. Altura = 100
apenas para garantir que haja uma diferença perceptível.

Quando executamos o código novamente, obtemos... O que??? a mesma coisa. Nenhuma mudança. De fato, você pode exibir o valor com uma instrução como MsgBox (txtDataShow. Altura) e você ainda recebe 20 como o valor da propriedade, independentemente do que você atribuir a ela. Por que isso acontece?

A resposta é que não estamos derivando nossa própria classe para criar os objetos, estamos apenas adicionando coisas a outra classe, para que tenhamos que seguir as regras da outra classe. E essas regras afirmam que você não pode alterar a propriedade Height. (Bem... você pode. Se você alterar a propriedade Multiline para True, poderá alterar a Altura.)

Por que o VB.NET segue em frente e executa o código sem nem um gemido de que possa haver algo errado quando, de fato, desconsidera totalmente sua declaração, é uma queixa total. No entanto, posso sugerir pelo menos um aviso na compilação. (Dica! Dica! Dica! A Microsoft está ouvindo?)

O exemplo da Parte I herda de outra Classe, e isso torna as propriedades disponíveis para o código na Classe herdada. Alterar a propriedade Height para 100 neste exemplo fornece os resultados esperados. (Novamente... um aviso: Quando uma nova instância de um componente Label grande é criada, ela cobre a antiga. Para realmente ver os novos componentes Label, você precisa adicionar a chamada de método aLabel. Traga para frente().)

Este exemplo simples mostra que, embora PODEMOS simplesmente adicionar objetos a outra classe (e às vezes isso é a coisa certa a fazer), o controle da programação sobre os objetos requer que os derivemos de uma classe e a maneira mais organizada (ouso dizer, "a maneira .NET"?) é criar propriedades e métodos na nova classe derivada para alterar coisas. John não ficou convencido a princípio. Ele disse que sua nova abordagem se adequa ao seu objetivo, embora haja limitações de não ser "COO" (Orientado a Objetos Corretos). Mais recentemente, porém, John escreveu:

"... depois de escrever um conjunto de 5 caixas de texto em tempo de execução, eu queria atualizar os dados em uma parte subsequente do programa - mas nada mudou - os dados originais ainda estavam lá.

Eu descobri que poderia solucionar o problema escrevendo código para retirar as caixas antigas e colocá-las novamente com novos dados. Uma maneira melhor de fazer isso seria Me usar. Atualizar. Mas esse problema chamou minha atenção para a necessidade de fornecer um método para subtrair as caixas de texto e adicioná-las ".

O código de John usava uma variável global para acompanhar quantos controles foram adicionados ao formulário para um método ...

Subformulário particular1_Load (_
Remetente ByVal como sistema. Objeto, _
ByVal e As System. EventArgs) _
Lida com o MyBase. Carga
CntlCnt0 = Eu. Controles. Contagem
End Sub

Em seguida, o "último" controle pode ser removido ...

N = eu. Controles. Contagem - 1
Eu. Controles. RemoveAt (N)
John observou que "talvez isso seja um pouco desajeitado".

É a maneira como a Microsoft controla os objetos no COM AND no código de exemplo "feio" acima.

Agora voltei ao problema de criar controles dinamicamente em um formulário em tempo de execução e estive analisando novamente os artigos 'O que aconteceu com as matrizes de controle'.

Eu criei as classes e agora posso colocar os controles no formulário da maneira que eu quero que eles sejam.

John demonstrou como controlar o posicionamento dos controles em uma caixa de grupo usando as novas classes que ele começou a usar. Talvez a Microsoft tenha acertado em sua solução "feia", afinal!

instagram story viewer