如何遍历项目中所有控件(含未加载的WinForm、UserControl控件)
实现步骤
你已经完成了命名空间下类型的获取,接下来按以下逻辑处理即可:
- 从获取到的类型中筛选出所有继承自
Form、UserControl的控件容器类型 - 对每个容器类型进行安全实例化,不需要调用Show方法,就能获取到设计阶段定义的所有控件(不会触发界面渲染和Load事件)
- 递归遍历容器内的所有层级的子控件,同时收集需要的属性信息
- 遍历完成后释放实例化的容器对象,避免内存泄漏
完整代码实现
' 你原有的获取命名空间下所有类型的方法 Private Function GetTypesInNamespace(ByVal assembly As Assembly, ByVal [nameSpace] As String) As Type() Return assembly.GetTypes().Where(Function(t) String.Equals(t.[Namespace], [nameSpace], StringComparison.Ordinal)).ToArray() End Function ' 定义存储控件信息的结构 Public Structure ControlInfo Public ControlName As String Public TagValue As Object Public ParentName As String Public ContainerName As String ' 所属的窗体/用户控件名称 End Structure ' 递归遍历控件的方法 Private Sub TraverseControls(ByVal parentControl As Control, ByVal containerName As String, ByRef resultList As List(Of ControlInfo)) For Each ctl As Control In parentControl.Controls ' 收集当前控件信息 Dim info As New ControlInfo() info.ControlName = ctl.Name info.TagValue = ctl.Tag info.ParentName = parentControl.Name info.ContainerName = containerName resultList.Add(info) ' 如果当前控件是容器或用户控件,递归遍历子控件 If ctl.HasChildren OrElse TypeOf ctl Is UserControl Then TraverseControls(ctl, containerName, resultList) End If Next End Sub ' 主调用方法,获取所有控件信息 Public Function GetAllProjectControls() As List(Of ControlInfo) Dim result As New List(Of ControlInfo)() ' 获取当前程序集,如果你要遍历其他程序集自行修改 Dim currentAssembly As Assembly = Assembly.GetExecutingAssembly() ' 替换为你自己的项目命名空间 Dim allTypes As Type() = GetTypesInNamespace(currentAssembly, "你的项目命名空间") ' 筛选所有窗体和用户控件类型 Dim containerTypes = allTypes.Where(Function(t) GetType(Form).IsAssignableFrom(t) OrElse GetType(UserControl).IsAssignableFrom(t)).ToList() For Each type In containerTypes ' 跳过抽象类、设计器生成的基类 If type.IsAbstract Then Continue For Try ' 实例化容器,不需要Show Dim instance = Activator.CreateInstance(type) Dim container As Control = CType(instance, Control) ' 遍历当前容器的所有控件 TraverseControls(container, type.Name, result) ' 释放资源 container.Dispose() Catch ex As Exception ' 处理部分构造函数有参数无法实例化的情况,可自行添加日志 Continue For End Try Next Return result End Function
注意事项
如果你的控件是在窗体/用户控件的
Load、Shown事件中动态生成的,直接实例化不会触发这些事件,无法获取到动态控件。如果需要覆盖这部分控件,可在实例化后手动调用OnLoad方法。
如果项目中存在自定义容器控件,可在筛选容器类型的逻辑里补充对应类型的判断规则。
如果部分窗体的构造函数需要传入参数,需要修改Activator.CreateInstance的调用逻辑,传入对应的构造参数避免实例化失败。
内容的提问来源于stack exchange,提问作者Adelina Andreea trandafir
相关产品推荐
相关产品推荐

