有一个类似的问题here,遗憾的是这对我没有帮助。当我拨打UserControl.Parent
时,可以返回Form
或其他UserControl
。如果表格被退回,我有我想要的。但是如果返回UserControl
,我就无法迭代链,因为UserControl
是基类名,而且我无法访问控件之外的基类名称。的实施。
从技术上讲,我可以通过在应用程序中的每个UserControl
上公开Parent属性来解决这个问题,但我真的想避免这样做(我们有数千个)。
我的最终目标是获取对托管控件的父窗体的引用,以便控件可以订阅Form_Unload
事件。在这里,控件将删除并清理托管的.NET互操作控件,该控件阻止VB6 UserControl
引发其UserControl_Terminated
事件,从而泄漏GDI对象和内存。
到目前为止,我已尝试在GetParent()
和GetWindow()
事件中调用USER32.dll中的GetAncestor()
,UserControl_Initialize
和UserControl_Resize
函数,然后在Forms
集合中的表单上与hWnds交叉引用,但在UserControl选址在其主机表单上之前,似乎都会引发这两个事件。
答案 0 :(得分:1)
我做了一些摆弄,这应该给你一些东西继续下去。我刚刚创建了两个UserControls,称为Internal和External。内部有一个命令按钮,外部有一个框架。我在框架内放置了一个Internal on External实例。然后我在表单上放置了一个External实例,其名称我刚刚离开Form1。
所以,我在表单的控件中有一个控件。问题是从内部控制的上下文中找到对Form的引用。
首先,我在Form上有一个名为Test的方法,所以:
Public Sub Test
MsgBox "Test Succeeded"
End Sub
现在,在内部控件的命令按钮的Click事件处理程序中:
Private Sub cmdTest_Click()
UserControl.ParentControls(0).Parent.Test
End Sub
运行Form项目并单击命令按钮成功调用Form的Test方法。 (是的哈哈。)
因此,要直接在表单上区分嵌套控件和控件,您可以按照以下方式执行操作:
Private Sub cmdTest_Click()
If TypeOf UserControl.Parent is Form Then
UserControl.Parent.Test
Else
UserControl.ParentControls(0).Parent.Test
End If
End Sub
然后我尝试将外部控件嵌套在另一个控件(External2)中,并在表单上放置一个External2实例。在调试窗口中,我这样做了:
? typename(usercontrol.ParentControls(0))
External
? typename(usercontrol.ParentControls(0).Parent)
External2
就我而言。尝试这样的事情:
? typename(usercontrol.ParentControls(0).Parent.ParentControls(0))
或类似的东西,有一个"对象不支持这个属性或方法"错误。
如果你需要评估嵌套多个深度的控件(你没有确定地说过,但是#34;迭代链#34;暗示你可能),这可能超出了这种技术。你也可以搞乱控件和名称属性,也许可以搞清楚。但看起来ParentControls属性并不会扩展到本身控件的控件的父级,除非您遇到使用不同属性名称公开它们的麻烦。至少你可以用链接在链上再多一个链接。
通常,它看起来不像Parent属性或其衍生物包含对父对象的实际引用,而是它们的属性和方法的某种子集。例如,我可以获取UserControl的hWnd属性,但不能获取UserControl.Parent的hWnd属性。甚至具体通过名称引用父(实际控件实例的名称是External1,所以?External1.hWnd)无法获取hWnd属性,抛出一个" Object Required"错误。这似乎会使API用于解决方案的可能性变得复杂。
无论如何,我留给你玩。如果你比我更进一步,我会很高兴看到你的结果。
答案 1 :(得分:0)
我生锈了,但不是你所追求的Container
财产?
请注意,当与dot net互操作时,该点网具有非常不同的垃圾收集。仅仅因为VB6对象已被释放并不意味着点网对象已经存在。他们仍然可能潜伏在记忆中 - 在极少数情况下 - 仍然可以在计时器上发射事件。
因此,请确保您的dot net控件正在自行清理,并且有一个VB6可以触发的方法,以强制进行此终止。
请参阅:https://msdn.microsoft.com/en-us/library/aa445702(v=vs.60).aspx
答案 2 :(得分:0)
我能够通过使用HWND和win32 API遍历父/子关系来找到父表单。我的代码大致如下:
Private Declare Function GetParent Lib "USER32" (ByVal Hwnd As Long) As Long
Private Declare Function GetClassName Lib "USER32" Alias "GetClassNameA" _
(ByVal Hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Public Function FindParentForm(Hwnd As Long) As Form
Dim ParentHwnd As Long
Dim CandidateForm As Form
Dim strTmp As String * 255
Dim lngLngth As Long
Dim strTitle As String
ParentHwnd = Hwnd
Do While (Not ParentHwnd = 0)
ParentHwnd = GetParent(ParentHwnd)
lngLngth = GetClassName(ParentHwnd, strTmp, 255)
strTitle = Left(strTmp, lngLngth)
'ThunderFormDC is the Debug version of a VB6 form, and ThunderRT6FormDC is the Release/Runtime version of a VB6 form
If strTitle = "ThunderFormDC" Or strTitle = "ThunderRT6FormDC" Then
Exit Do
End If
Loop
For Each CandidateForm In Forms
If CandidateForm.Hwnd = ParentHwnd Then
Set FindParentForm2 = CandidateForm
Exit Function
End If
Next
'Didn't find the parent form somehow
Set FindParentForm2 = Nothing
End Function
正如我在问题中提到的,此解决方案的问题在于,在UserControl_Initialize和UserControl_Resize事件期间,还没有在HWND之间建立父/子关系。如果您尝试遍历父/子关系,您会发现usercontrol的父级是名为" Static"的类。
我能够通过在用户控件的手动Init()
过程中搜索父表单来解决此问题。但是,许多表单不会调用Init()
过程,除非单击它所在的选项卡(试图在VB6中实现某种延迟加载)。我能够解决这个问题,重构控件,以便在调用Init()
过程之前不动态创建/添加.NET互操作控件。到这时,似乎已经建立了父/子关系。
延迟加载问题的另一种解决方案是挂钩WndProc
过程,并侦听WM_CHILDACTIVATED
消息。但是,仅当子控件更改父项时才会发送此消息。它不会传给孙子孙女。但是,应该可以将另一个WndProc
挂钩到新的父控件并监听它自己的WM_CHILDACTIVATED
消息,依此类推,直到子控件成为{{1}的父级。 }。但是,由于ThunderForm
只能在静态模块中实现,因此我并不想跟踪父/子关系。
答案 3 :(得分:0)
我在 ReadProperty 中使用UserControl.Parent解决了我的引用问题。
我试过GetParent()没有成功。还在初始化中尝试了UserControl.Parent。
问题是在Initialize期间对象不存在。它是在链接到表格(父母)之前建立的
在 ReadProperty (或调整大小)中,它已经存在,您可以使用UserControl.Parent。
例如,我使用UserControl.Parent.name在窗口寄存器中保存一些信息。
答案 4 :(得分:0)
这与此主题相关,因此我在此处发布,以便在特殊情况下使用。它不能深入嵌套,但是在我的案例中获取信息是一种快速的方式,而其他人可能会发现它的使用。
我有一个放在用户控件上的Control(cmdPageDown1),它放在一个用户控件(xMCGridNew1)上,放在一个Form(frmMC)上。
正如其他人所指出的那样,我无法使用任何快速的单行代码来获取表单名称,但是使用这些简单的行,我可以获得其他2个嵌套用户控件和较低级别的名称控制。
例如:
'Debug.Print '[Roadblock Here] 'Top Level frm MC (Parent)
Debug.Print Screen.ActiveControl.Name 'SubLevel 1 xMCGridNew1 (Child)
Debug.Print UserControl.Name 'SubLevel 2 xpage (GrandChild)
Debug.Print ActiveControl.Name 'SubLevel 3 cmdPageDown1 (Great Grandchild)
这将在对应于三个嵌套级别的即时窗口中生成。
xMCGridNew1
xPage
cmdPageDown1
正如本主题中另一张海报(Orignal Poster)所述,关于试图使用Container属性:
Container属性有两个问题。首先,UserControl没有> Container属性。您必须从UserControl.Extender>属性中获取它。其次,Container可能是另一个UserControl。由于> UserControl.Extender属性是基类属性,因此在该UserControl的特定实现之外不能访问它。即UserControl1>无法访问UserControl2.UserControl.Extender.Container。因此,> Container属性与Parent属性具有相同的问题 - 我将>需要修改我们的应用程序中的每个用户控件(太多)。 - Taedrin> 1月15日和16日15:08