The omission of control arrays from VB.NET is a challenge for those teaching about arrays.
VB.NET对控制数组的遗漏对那些关于数组的教导是一个挑战。
- No longer is it possible to simply copy a control, such as a textbox, and then paste it (once or several times) to create a control array. 不再能够简单地复制一个控件(例如文本框),然后将其粘贴(一次或多次)以创建一个控件数组。
- The VB.NET code for creating a structure similar to a control array has been, in all the books on VB.NET that I have bought and online, much longer and much more complex. It lacks the simplicity of coding a control array that is found in VB6. 在我购买并在线购买的所有VB.NET书籍中,用于创建类似于控件数组的结构的VB.NET代码要长得多,也要复杂得多。 它缺乏对在VB6中找到的控制数组进行编码的简单性。
If you reference the VB6 compatibility library, there are objects in there that act pretty much like control arrays. To see what I mean, simply use the VB.NET upgrade wizard with a program that contains a control array. The code is ugly again, but it works. The bad news is that Microsoft will not guarantee that the compatibility components will continue to be supported, and you're not supposed to use them.
如果引用VB6兼容性库,则其中的对象的行为与控件数组非常相似。 若要了解我的意思,只需将VB.NET升级向导与包含控件数组的程序一起使用。 该代码再次很难看,但是可以正常工作。 坏消息是Microsoft不能保证兼容性组件将继续受支持,因此您不应该使用它们。
The VB.NET code to create and use "control arrays" is much longer and much more complex.
用于创建和使用“控件数组”的VB.NET代码要长得多,也要复杂得多。
According to Microsoft, to do something even close to what you can do in VB 6 requires the creation a "simple component that duplicates control array functionality."
根据Microsoft的说法,要想达到与VB 6一样的性能,就需要创建一个“复制控件阵列功能的简单组件”。
You need both a new class and a hosting form to illustrate this. The class actually creates and destroys new labels. The complete class code is as follows:
您需要一个新类和一个托管表单来说明这一点。 该类实际上创建并破坏了新标签。 完整的类代码如下:
Public Class LabelArray Inherits System.Collections.CollectionBase Private ReadOnly HostForm As _ System.Windows.Forms.Form Public Function AddNewLabel() _ As System.Windows.Forms.Label ' Create a new instance of the Label class. Dim aLabel As New System.Windows.Forms.Label ' Add the Label to the collection's ' internal list. Me.List.Add(aLabel) ' Add the Label to the Controls collection ' of the Form referenced by the HostForm field. HostForm.Controls.Add(aLabel) ' Set intial properties for the Label object. aLabel.Top = Count * 25 aLabel.Width = 50 aLabel.Left = 140 aLabel.Tag = Me.Count aLabel.Text = "Label " & Me.Count.ToString Return aLabel End Function Public Sub New( _ ByVal host As System.Windows.Forms.Form) HostForm = host Me.AddNewLabel() End Sub Default Public ReadOnly Property _ Item(ByVal Index As Integer) As _ System.Windows.Forms.Label Get Return CType(Me.List.Item(Index), _ System.Windows.Forms.Label) End Get End Property Public Sub Remove() ' Check to be sure there is a Label to remove. If Me.Count > 0 Then ' Remove the last Label added to the array ' from the host form controls collection. ' Note the use of the default property in ' accessing the array. HostForm.Controls.Remove(Me(Me.Count - 1)) Me.List.RemoveAt(Me.Count - 1) End If End SubEnd Class
公共类LabelArray继承作为System.Windows.Forms.Form的System.Collections.CollectionBase私有ReadHost私有形式。公共函数AddNewLabel()_作为System.Windows.Forms.Label的方法创建Label类的新实例。 将aLabel设置为New System.Windows.Forms.Label'将Label添加到集合的内部列表中。 Me.List.Add(aLabel)'将标签添加到HostForm字段引用的Form的Controls集合中。 HostForm.Controls.Add(aLabel)'设置Label对象的初始属性。 aLabel.Top =计数* 25 aLabel.Width = 50 aLabel.Left = 140 aLabel.Tag = Me.Count aLabel.Text =“ Label”&Me.Count.ToString返回aLabel结束函数Public Sub New(_ ByVal host作为系统.Windows.Forms.Form)HostForm = host Me.AddNewLabel()End Sub Default Public ReadOnly属性_ Item(ByVal Index Integer)As _ System.Windows.Forms.Label Get Return CType(Me.List.Item(Index) ,_ System.Windows.Forms.Label)结束结束结束属性Public Sub Remove()'检查是否有要删除的标签。 如果Me.Count> 0,则从主机窗体控件集合中“删除添加到数组中的最后一个标签”。 '请注意在访问数组时使用默认属性。 HostForm.Controls.Remove(Me(Me.Count-1))Me.List.RemoveAt(Me.Count-1)End如果End SubEnd类结束
To illustrate how this class code would be used, you could create a Form that calls it. You would have to use the code shown below in the form:
为了说明如何使用此类代码,您可以创建一个调用它的窗体。 您将必须使用以下形式的代码:
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
' Also you must add the statement:
' MyControlArray = New LabelArray(Me)
' after the InitializeComponent() call in the
' hidden Region code.
' Declare a new ButtonArray object.
Dim MyControlArray As LabelArray
Private Sub btnLabelAdd_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnLabelAdd.Click
' Call the AddNewLabel method
' of MyControlArray.
MyControlArray.AddNewLabel()
' Change the BackColor property
' of the Button 0.
MyControlArray(0).BackColor = _
System.Drawing.Color.Red
End Sub
Private Sub btnLabelRemove_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnLabelRemove.Click
' Call the Remove method of MyControlArray.
MyControlArray.Remove()
End Sub
End Class
First, this doesn't even do the job at Design Time like we used to do it in VB 6! And second, they aren't in an array, they are in a VB.NET Collection - a much different thing than an array.
首先,这甚至没有像我们在VB 6中所做的那样在设计时完成工作! 其次,它们不在数组中,而是在VB.NET集合中-与数组大不相同。
The reason VB.NET doesn't support the VB 6 "control array" is that there is no such thing as a "control" "array" (note the change of quotation marks). VB 6 creates a collection behind-the-scenes and makes it appear as an array to the developer. But it's not an array and you have little control over it beyond the functions provided through the IDE.
VB.NET不支持VB 6“控件数组”的原因是不存在“控件”“数组”之类的东西(请注意引号的更改)。 VB 6在幕后创建一个集合,并使其作为数组显示给开发人员。 但是它不是一个数组,除了通过IDE提供的功能之外,您几乎无法控制它。
VB.NET, on the other hand, calls it what it is: a collection of objects. And they hand the keys to the kingdom to the developer by creating the whole thing right out in the open.
另一方面,VB.NET称其为:对象集合。 他们通过公开创建整个产品,将王国的钥匙交给开发人员。
As an example of the kind of advantages this gives the developer, in VB 6 the controls had to be of the same type, and they had to have the same name. Since these are just objects in VB.NET, you can make them different types and give them different names and still manage them in the same collection of objects.
作为给开发人员带来的这种好处的一个示例,在VB 6中,控件必须具有相同的类型,并且控件必须具有相同的名称。 由于这些只是VB.NET中的对象,因此您可以将它们设置为不同的类型,并为其指定不同的名称,然后仍然在同一对象集合中对其进行管理。
In this example, the same Click event handles two buttons and a checkbox and displays which one was clicked. Do that in one line of code with VB 6!
在此示例中,相同的Click事件处理两个按钮和一个复选框,并显示单击了哪个按钮。 用VB 6在一行代码中做到这一点!
Private Sub MixedControls_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click, _ Button2.Click, _ CheckBox1.Click ' The statement below has to be one long statement! ' It's on four lines here to keep it narrow ' enough to fit on a web page Label2.Text = Microsoft.VisualBasic.Right(sender.GetType.ToString, Len(sender.GetType.ToString) - (InStr(sender.GetType.ToString, "Forms") + 5))End Sub
Private Sub MixedControls_Click(_ ByVal发送者作为System.Object,_ ByVal e作为System.EventArgs)_处理Button1.Click,_ Button2.Click,_ CheckBox1.Click'下面的语句必须是一个长语句! '在这里保持四行很窄'以适合网页Label2.Text = Microsoft.VisualBasic.Right(sender.GetType.ToString,Len(sender.GetType.ToString)-(InStr(sender.GetType。 ToString,“表单”)+ 5))End Sub
The substring calculation is kind of complex, but it isn't really what we're talking about here. You could do anything in the Click event. You could, for example, use the Type of the control in an If statement to do different things for different controls.
子字符串计算有点复杂,但实际上并不是我们在这里谈论的。 您可以在Click事件中执行任何操作。 例如,您可以在If语句中使用控件的类型对不同的控件执行不同的操作。
弗兰克计算研究小组对阵列的反馈 ( Frank's Computing Studies Group Feedback on Arrays )
Frank's Study Group provided an example with a form that has 4 labels and 2 buttons. Button 1 clears the labels and Button 2 fills them. It's a good idea to read Frank's original question again and notice that the example he used was a loop that is used to clear the Caption property of an array of Label components. Here's the VB.NET equivalent of that VB 6 code. This code does what Frank originally asked for!
弗兰克(Frank)的学习小组提供了一个带有4个标签和2个按钮的表格示例。 按钮1清除标签,按钮2填充标签。 再次阅读Frank的原始问题是一个好主意,请注意,他使用的示例是一个循环,用于清除Label组件数组的Caption属性。 这是该VB 6代码的VB.NET等效项。 该代码完成了Frank最初的要求!
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Dim LabelArray(4) As Label
'declare an array of labels
Private Sub Form1_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load
SetControlArray()
End Sub
Sub SetControlArray()
LabelArray(1) = Label1
LabelArray(2) = Label2
LabelArray(3) = Label3
LabelArray(4) = Label4
End Sub
Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
'Button 1 Clear Array
Dim a As Integer
For a = 1 To 4
LabelArray(a).Text = ""
Next
End Sub
Private Sub Button2_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button2.Click
'Button 2 Fill Array
Dim a As Integer
For a = 1 To 4
LabelArray(a).Text = _
"Control Array " & CStr(a)
Next
End Sub
End Class
If you experiment with this code, you will discover that in addition to setting properties of the Labels, you can also call methods. So why did I (and Microsoft) go to all the trouble to build the "Ugly" code in Part I of the article?
如果您尝试使用此代码,则将发现,除了设置Labels的属性之外,还可以调用方法。 那么,为什么我(和Microsoft)全力以赴在本文的第一部分中构建“丑陋”代码?
I have to disagree that it's really a "Control Array" in the classic VB sense. The VB 6 Control Array is a supported part of the VB 6 syntax, not just a technique. In fact, maybe the way to describe this example is that it is an array of controls, not a Control Array.
我不得不不同意,它实际上是经典VB意义上的“控制阵列”。 VB 6控制数组是VB 6语法受支持的一部分,而不仅仅是一种技术。 实际上,描述此示例的方式可能是它是控件的数组,而不是控件数组。
In Part I, I complained that the Microsoft example ONLY worked at run time and not design time. You can add and delete controls from a form dynamically, but the whole thing has to be implemented in code. You can't drag and drop controls to create them like you can in VB 6. This example works mainly at design time and not at run time. You can't add and delete controls dynamically at run time. In a way, it's the complete opposite of the Part I example.
在第一部分中,我抱怨微软示例仅在运行时有效,而在设计时无效。 您可以动态地从表单添加和删除控件,但是整个过程必须用代码来实现。 您不能像在VB 6中那样拖放控件来创建它们。此示例主要在设计时工作,而不是在运行时工作。 您无法在运行时动态添加和删除控件。 在某种程度上,它与第I部分示例完全相反。
The classic VB 6 control array example is the same one that is implemented in the VB .NET code. Here in VB 6 code (this is taken from Mezick & Hillier, Visual Basic 6 Certification Exam Guide, p 206 - slightly modified, since the example in the book results in controls that can't be seen):
经典的VB 6控件数组示例与VB .NET代码中实现的示例相同。 这里是VB 6代码(摘自Mezick&Hillier,《 Visual Basic 6认证考试指南》 ,第206页-稍作修改,因为书中的示例产生了无法看到的控件):
Dim MyTextBox as VB.TextBox
Static intNumber as Integer
intNumber = intNumber + 1
Set MyTextBox = _
Me.Controls.Add("VB.TextBox", _
"Text" & intNumber)
MyTextBox.Text = MyTextBox.Name
MyTextBox.Visible = True
MyTextBox.Left = _
(intNumber - 1) * 1200
But as Microsoft (and I) agree, VB 6 control arrays aren't possible in VB.NET. So the best you can do is duplicate the functionality. My article duplicated the functionality found in the Mezick & Hillier example. The Study Group code duplicates the functionality of being able to set properties and call methods.
但是,正如Microsoft(和我)所同意的那样,VB.NET中不可能使用VB 6控制阵列。 因此,您能做的最好的就是复制功能。 我的文章重复了Mezick&Hillier示例中发现的功能。 学习组代码复制了能够设置属性和调用方法的功能。
So the bottom line is that it really depends on what you want to do. VB.NET doesn't have the whole thing wrapped up as part of the language -- Yet -- but ultimately it's far more flexible.
因此,最重要的是,它实际上取决于您要执行的操作。 VB.NET并未将全部内容打包为该语言的一部分-但是-但最终它要灵活得多。
约翰·范农(John Fannon)对控制阵列的看法 ( John Fannon's Take on Control Arrays )
John wrote: I needed control arrays because I wanted to put a simple table of numbers on a form at run time. I didn't want the nausea of placing them all individually and I wanted to use VB.NET. Microsoft offers a very detailed solution to a simple problem, but it's a very large sledgehammer to crack a very small nut. After some experimentation, I eventually hit upon a solution. Here's how I did it.
约翰写道:我需要控制数组,因为我想在运行时在表单上放置一个简单的数字表。 我不想把它们全部单独放置的恶心,我想使用VB.NET。 微软为一个简单的问题提供了非常详细的解决方案,但这是一把非常大的锤子,可以用来敲破一个很小的螺母。 经过一些试验,我最终找到了解决方案。 这是我的方法。
The About Visual Basic example above shows how you can create a TextBox on a Form by creating an instance of the object, setting properties, and adding it to the Controls collection that is part of the Form object.
上面的About Visual Basic示例展示了如何通过创建对象的实例,设置属性并将其添加到Form对象的Controls集合中的方式,在Form上创建TextBox。
Dim txtDataShow As New TextBoxtxtDataShow.Height = 19txtDataShow.Width = 80txtDataShow.Location = New Point(X, Y)Me.Controls.Add(txtDataShow)Although the Microsoft solution creates a Class, I reasoned that it would be possible to wrap all this in a subroutine instead. Every time you call this subroutine you create a new instance of the textbox on the form. Here's the complete code:
将txtDataShow变暗为新的TextBoxtxtDataShow.Height = 19txtDataShow.Width = 80txtDataShow.Location =新建Point(X,Y)Me.Controls.Add(txtDataShow)尽管Microsoft解决方案创建了一个Class,但我认为可以包装所有这些而是在子例程中。 每次调用此子例程时,都会在表单上创建文本框的新实例。 这是完整的代码:
Public Class Form1 Inherits System.Windows.Forms.Form
公共类Form1继承System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
#Region“ Windows窗体设计器生成的代码”
Private Sub BtnStart_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnStart.Click
私人Sub BtnStart_Click(_ ByVal发件人为System.Object,_ ByVal e为System.EventArgs)_处理btnStart.Click
Dim I As Integer Dim sData As String For I = 1 To 5 sData = CStr(I) Call AddDataShow(sData, I) Next End Sub Sub AddDataShow( _ ByVal sText As String, _ ByVal I As Integer)
Dim I作为整数Dim sData作为字符串对于I = 1到5 sData = CStr(I)调用AddDataShow(sData,I)下一步Sub Sub Sub AddDataShow(_ ByVal sText作为字符串,_ ByVal I作为整数)
Dim txtDataShow As New TextBox Dim UserLft, UserTop As Integer Dim X, Y As Integer UserLft = 20 UserTop = 20 txtDataShow.Height = 19 txtDataShow.Width = 25 txtDataShow.TextAlign = _ HorizontalAlignment.Center txtDataShow.BorderStyle = _ BorderStyle.FixedSingle txtDataShow.Text = sText X = UserLft Y = UserTop + (I - 1) * txtDataShow.Height txtDataShow.Location = New Point(X, Y) Me.Controls.Add(txtDataShow) End SubEnd ClassVery good point, John. This is certainly a lot more simple than the Microsoft code ... so I wonder why they insisted on doing it that way?
Dim txtDataShow作为新文本框Dim UserLft,UserTop作为整数Dim X,Y作为Integer UserLft = 20 UserTop = 20 txtDataShow.Height = 19 txtDataShow.Width = 25 txtDataShow.TextAlign = _ HorizontalAlignment.Center txtDataShow.BorderStyle = _ BorderStyle.FixedSingle txtDataShow .Text = sText X = UserLft Y = UserTop +(I-1)* txtDataShow.Height txtDataShow.Location = New Point(X,Y)Me.Controls.Add(txtDataShow)End SubEnd Class非常好,约翰。 这肯定比Microsoft代码简单得多...所以我想知道为什么他们坚持要这样做吗?
To begin our investigation, let's try changing one of the property assignments in the code. Let's change
要开始研究,让我们尝试更改代码中的属性分配之一。 让我们改变
txtDataShow.Height = 19to
txtDataShow.Height = 19to
txtDataShow.Height = 100just to make sure that there is a noticeable difference.
txtDataShow.Height = 100只是为了确保有明显的区别。
When we run the code again, we get ... Whaaaat??? ... the same thing. No change at all. In fact, you can display the value with a statement like MsgBox (txtDataShow.Height) and you still get 20 as the value of the property no matter what you assign to it. Why does that happen?
当我们再次运行代码时,我们得到... Whaaaat ??? ... 同一件事情。 完全没有变化。 实际上,您可以使用MsgBox(txtDataShow.Height)之类的语句来显示该值,并且无论您为其分配什么属性,仍然会获得20作为该属性的值。 为什么会这样呢?
The answer is that we're not deriving our own Class to create the objects, we're just adding things to another Class so we have to follow the rules of the other class. And those rules state that you can't change the Height property. (Wellllll ... you can. If you change the Multiline property to True, then you can change the Height.)
答案是我们不是派生自己的Class来创建对象,而是将事物添加到另一个Class中,因此我们必须遵循另一个Class的规则。 这些规则指出您不能更改Height属性。 (Wellllll ...可以。如果将Multiline属性更改为True,则可以更改高度。)
Why VB.NET goes ahead and executes the code without even a whimper that there might be something wrong when, in fact, it totally disregards your statement is a whole 'nother gripe. I might suggest at least a warning in the compile, however. (Hint! Hint! Hint! Is Microsoft listening?)
为什么VB.NET继续进行代码并执行代码,却丝毫没有抱怨可能会出问题的事实,实际上,它完全无视您的陈述是另一回事。 但是,我可能至少建议您在编译时给出警告。 (提示!提示!提示!微软在听吗?)
The example from Part I inherits from another Class, and this makes the properties available to the code in the inheriting Class. Changing the Height property to 100 in this example gives us the expected results. (Again ... one disclaimer: When a new instance of a large Label component is created, it covers up the old one. To actually see the new Label components, you have to add the method call aLabel.BringToFront().)
第一部分的示例继承自另一个类,这使属性可用于继承的类中的代码。 在此示例中,将Height属性更改为100,可以得到预期的结果。 (再次……一个免责声明:创建大型Label组件的新实例时,它会覆盖旧的实例。要实际查看新的Label组件,必须添加方法aLabel.BringToFront()。)
This simple example shows that, although we CAN simply add objects to another Class (and sometimes this is the right thing to do), programming control over the objects requires that we derive them in a Class and the most organized way (dare I say, "the .NET way" ??) is to create properties and methods in the new derived Class to change things. John remained unconvinced at first. He said that his new approach suits his purpose even though there are limitations from not being "COO" (Correctly Object Oriented). More recently, however, John wrote,
这个简单的例子表明,尽管我们可以简单地将对象添加到另一个Class中(有时这是正确的做法),但是对对象进行编程控制需要我们以Class和最有组织的方式派生它们(我敢说, “ .NET方式”(??)是在新的派生类中创建属性和方法来更改事物。 约翰起初不相信。 他说,即使不是“ COO”(正确的面向对象)存在局限性,他的新方法也适合他的目的。 不过,约翰最近写道:
" ... after writing a set of 5 textboxes at runtime, I wanted to update the data in a subsequent part of the program - but nothing changed - the original data was still there.
“ ...在运行时编写了5个文本框后,我想在程序的后续部分中更新数据-但未做任何更改-原始数据仍然存在。
I found that I could get round the problem by writing code to take off the old boxes and putting them back again with new data. A better way to do it would be to use Me.Refresh. But this problem has drawn my attention for the need to supply a method to subtract the textboxes as well as add them."
我发现我可以通过编写代码来删除旧盒子并用新数据再次放回原处来解决这个问题。 更好的方法是使用Me.Refresh。 但是这个问题引起了我的注意,因为需要提供一种减去文本框并添加文本框的方法。”
John's code used a global variable to keep track of how many controls had been added to the form so a method ...
John的代码使用一个全局变量来跟踪已向表单添加了多少控件,因此是一种方法。
Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load CntlCnt0 = Me.Controls.CountEnd Sub
私有子Form1_Load(_ ByVal发送者作为System.Object,_ ByVal e作为System.EventArgs)_处理MyBase.Load CntlCnt0 = Me.Controls.CountEnd Sub
Then the "last" control could be removed ...
然后可以删除“最后一个”控件...
N = Me.Controls.Count - 1Me.Controls.RemoveAt(N)John noted that, "maybe this is a bit clumsy."
N = Me.Controls.Count-1Me.Controls.RemoveAt(N)John指出:“也许这有点笨拙。”
It's the way Microsoft keeps track of objects in COM AND in their "ugly" example code above.
这就是Microsoft在上面的“丑陋”示例代码中跟踪COM AND中对象的方式。
I've now returned to the problem of dynamically creating controls on a form at run time and I have been looking again at the 'What Happened to Control Arrays' articles.
现在,我回到了在运行时在窗体上动态创建控件的问题,并且我再次查看了“控件数组发生了什么”文章。
I have created the classes and can now place the controls onto the form in the way I want them to be.
我已经创建了类,现在可以按照我希望的方式将控件放置在窗体上。
John demonstrated how to control the placement of controls in a group box using the new classes he has started using. Maybe Microsoft had it right in their "ugly" solution after all!
John演示了如何使用他开始使用的新类来控制控件在组框中的放置。 毕竟,也许微软在其“丑陋”的解决方案中是对的!
翻译自: https://www.thoughtco.com/vbnet-what-happened-to-control-arrays-4079042