Z-order 和集合拷贝

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

Z-order 和集合拷贝

原著:ken spencer

翻译:tjq_tang

原文出处:MSDN Magazine Jan 2004(AdvancedBasics)

原代码下载:AdvancedBasics0401.exe

(131KB)

SendToBack 和 BringToFront 方法是改变

Windows® 窗体控件 z-order 的唯一选项吗?

解决这个难题采纳了在微软工作的一个哥们的建议,当然,一旦你知道了如何做,解决方法非常简单。

Windows 窗体控件没有象以前 Visual Basic (ZOrder)那样具备处理 z-order

的属性。碰到类似的处理时,可以在控件集合中找到方法。SetChildIndex 方法允许你设置控件的 z-index 。下面这行代码出自

Figure 1中的单击事件,它改变 Label2 的

z-index 值:

Me.Controls.SetChildIndex(Me.Label2, Label2NewIndex)

为了获取某个控件当前的索引,调用 GetChildIndex方法,如

Figure 1中 ShowIndex 方法所示。

如何用 Windows 窗体控件集的 CopyTo

方法将控件拷贝到一个数组中?

CopyTo 方法将控件集拷贝到一个数组。为了使用它,你务必指定一个数组以及它的起始点。例如,下面的代码从第一个元素开始将控件拷贝到

MyArrayOfControls 数组。

Me.Controls.CopyTo(MyArrayOfControls, 0)

下面我举例来说明一下,首先,我创建叫 frmControlsToArrayMaster 的窗体,它包含一组

Label/textbox 控件和三个按钮。接着我创建第二个窗体, 叫做 frmArrayClient, 它与前面创建的窗体大小相同,但没有控件。

于是,我准备好编写一些代码。

我最初写的代码是cmdCopy_Click事件(参见Figure 2)。该事件定义MyArrayOfControls数组大小为集合中控件的数目。然后,用

CopyTo 从第一个元素位置开始将控件拷贝到这个数组。我将这些代码放在按钮的 click 事件中,以便更加容易观察到它的运行。

接着我创建 cmdNew_Clieck 事件,第一个版本的代码就像这样:

Private Sub cmdNew_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdNew.Click

Dim frm As New frmArrayClient

frm.ShowDialog()

End Sub

然后,我在 frmArrayClient 中添加下面的代码:

Dim ct As Control

If MyArrayOfControls.GetUpperBound(0) 0 Then

Me.Controls.AddRange(MyArrayOfControls)

For Each ct In Me.Controls

If ct.GetType.ToString = "System.Windows.Forms.Button" Then

ct.Visible = False

End If

Next

End If

通过调用 Controls.AddRange 添加来自第一个窗体的控件。因为在这个窗体上我不想要相同命令的按钮,于是将任何按钮的Visible

属性都设置为 False。很 Cool 吧?

效果参见 Figure 3:

Figure 3 Reparented 控件

上面的窗体是 frmControlsToArrayMaster,它是有控件的。但它们在哪里呢? 实际上,frmArrayClient 中的

AddRange 被调用时,这些控件从我的数组中被加载到新的窗体上。

因为一个控件仅能有一个父控件,这些控件被重新指定为新窗体( frmArrayClient

)里的子控件。也就是说这些控件不会再出现在第一个窗体( frmControlsToArrayMaster )上。

Figure 2中的代码cmdNew_Click在进行上面的处理时是有隐痛的。它

会将控件放回到 frmControlsToArrayMaster。你可以自己运行例子程序来证明这一点,将数据放进两个控件,然后单击新按钮。现在将数据添加

到两个以上的控件并且关闭新的窗体。所有输入的数据现在都在在原来窗体上。大多数情况下这样是很酷,但如果你是想拷贝控件到新的窗体上,而不是移动它们,那会

怎么样呢?

我对这个问题不是很在行,就向在 NetEdge Software 工作的朋友 Bill Martschenko

请求帮助,他发给我一些经典的代码以解决控件拷贝(克隆)问题。

它通过 CopyTo 函数将拷贝控件到数组,创建同样属性的控件集合(或者它们的子集),作为原始的控件。接着就可添加新控件而不会影响到原来的控件。

frmNewArrayClient2 采用了 Bill 建议的方法 . Figure 4 显示了新窗体,正如你所见的,原来的窗体上的控件依然如故,但新

窗体上这些控件被复制出来,几个命令按钮除外。

Figure 4 拷贝的控件

这个窗体加载 frmNewArrayClient2 事件:

Dim ctNew As Control

Dim i As Integer

If MyArrayOfControls.GetUpperBound(0) 0 Then

For i = 0 To MyArrayOfControls.GetUpperBound(0)

ctNew = CloneControl(MyArrayOfControls(i))

If ctNew.GetType.ToString "System.Windows.Forms.Button" Then

Me.Controls.Add(ctNew)

End If

Next

End If

上面这段代码循环访问 MyArrayOfControls 中所有控件,然后只要不是按钮,便每次都创建一个新的控件并添加到窗体上。新控件是通过调用 CloneControl

函数创建的。此代码十分简单并实现了控件的拷贝。现在,让我们进一步深入代码看看它是如何工作的 (参见

Figure 5 ) 。首先, CloneControl 函数执行

下面这行代码,创建与当前控件类型相同的新控件:

Dim newControl As Control = CType(NewAs(c), Control)

从CType 调用中可以看出,它有一个 NewAs 方法调用。该函数的这个参数就是你要拷贝的控件。NewAs 的具体细节请参见

Figure 5

如果你检查 NewAs 的定义( Figure 5

里有两个),就会发现它们看起来就像是自己在做递归调用,其实他们仅仅是被重载。这个小诀窍使你将参数作为对象来传递,

使得第一个函数调用干净利落。然后函数便可以对参数使用一些诸如 GetType

之类的操作,这样使开发人员更容易使用这个函数,因为他们不必知道如何调用私有函数的细节。第二个 NewAs 函数调用了程序集类的 CreateInstance,该方法根据控件

的类型创建控件实例。可以用它创建你想要克隆的控件实例。

CloneProperties 函数的第二行拷贝控件的属性并且将属性映射到新控件中,参见如下代码:

CloneProperties(newControl, c, "Visible", "Size", "Font", _

"Text", "Location", "BackColor", "ForeColor", "Enabled", _

"BackgroundImage")

CloneControl以一个If语句块结束,这个语句块允许你对特定的控件类型进行专门的处理。例子程序中有一个If语句块,当控件为按钮或链接标签时拷贝特定的属性。此外,它还二次调用

CloneProperties以获取附加属性。

CloneProperties 函数实现代码也在 Figure 5 中,该函数有一个你想要设置的属性数组参数。然后,它为每一个控件创建一个 PropertyAccessor 类实例。最后,代码循环参数

名数组,将目标控件的属性设为源控件的属性。从而将源控件的属性一个一个拷贝到新控件属性中。

让我们来看一下 PropertyAccessor 类(参见 Figure 6 )。该类的构造函数带了一个参数 ---

源或目的控件的引用,该引用设置到目标变量上。目标变量可继承引用控件的属性。

有意思的是代码定义了子项属性,有缺省值。可以看到子项属性:

Default Public Property Item(ByVal propertyName As String) As Object

Get 方法返回属性值。接着创建 PropertyInfo 类的实例并设置需要的属性 :

Dim prop As PropertyInfo = Me.Target.GetType().GetProperty(propertyName)

一旦获得了属性,就可通过 GetValue 方法获得它的值。 Set 方法也是这样直接使用的。新值被忽略,你需创建 PropertyInfo

类实例:

Dim prop As PropertyInfo = Me.Target.GetType().GetProperty(propertyName)

可调用 SetValue 设置属性值:

prop.SetValue(Me.Target, value, Nothing)

这就是所有的东西了。从一个 Form 拷贝控件到另一个 Form 的代码:

这个月的二个问题初看比较困难。但 Microsoft® .NET Framework

都为它们提供了直接的方式来解决。有时候自己就得坚持不懈以找寻解决问题的方案。

对 Ken 所写有什么问题或者评论,与 basics@microsoft.com 联系。

Ken Spencer 为 32X Tech 工作( http://www.32X.com ),提供培训,软件开发,微软技术质询。

本文出自

MSDN Magazine

January 2004 期刊,可通过当地

报摊获得,或者最好是 订阅

本文由 VCKBASE MTT 翻译

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航