How do I handle nested project items in an addin? Nested ProjectItems can occur for several reasons. First in an ASP.NET project, the code file (aspx.vb or aspx.cs) is nested under the Web Form (aspx) file. Secondly, if you place folders in your project to contain your projectitems, such as Forms, Classes, Images, etc., then the ProjectItems are nested and a simple top-level loop through the ProjectItems will not get you to the code files and you will wonder why you can't find code that you know is in your project.
I first discovered this in working with the FileCodeModel of an aspx page and found that I was not scanning any code behind the web forms. Then, I discovered it when scanning a project that had its classes in a Classes Folder and forms in a Forms folder.
To solve the problem, since I am an add-in developer, I wrote a generic Class for scanning ProjectItems that can drill down as far as needed to get to the code windows. I will use a simple illustration of the class that is trying to determine if a certain utility file is already in the project, so I can add it to the project if it is not.
First, I will show you the Class that does the "drilling". The code for the ProjectItemScan Class is shown in Figure 1. I have written it as a class with Shared methods so that I don't have to instantiate it to use it.
Figure 1 - ProjectItemScan Class
| Imports EnvDTE Imports Extensibility Imports System ' This class processes project items and when ' a lowest level project item is found, it does ' a call back to the caller thru invoking a delegate. Public Class ProjectItemScan Private oVS As EnvDTE.DTE Private prj As Project Private projItem As ProjectItem Private projItems As ProjectItems ' the following delegate is what must be changed for the ' project you are working on Public Delegate Sub ProcessPIScanResult(ByVal pi As ProjectItem) Public Shared Sub ScanForProjectItems(ByVal proj As Project, _ ByVal psr As ProcessPIScanResult) Dim projItems As ProjectItems For Each projItem As ProjectItem In proj.ProjectItems projItems = projItem.ProjectItems If Not projItems Is Nothing AndAlso projItems.Count > 0 Then DrillDownInProjectItems(projItems, psr) Else ' call back to the user function delegated to ' handle a single project item psr.Invoke(projItem) End If Next End Sub Private Shared Sub DrillDownInProjectItems(ByVal projectItems As ProjectItems, _ ByVal psr As ProcessPIScanResult) Dim projItems As ProjectItems For Each projItem As ProjectItem In projectItems projItems = projItem.ProjectItems If Not projItems Is Nothing AndAlso projItems.Count > 0 Then ' recurse to get to the bottom of the tree DrillDownInProjectItems(projItems, psr) Else ' call back to the user function delegated to ' handle a single project item psr.Invoke(projItem) End If Next End Sub End Class |
| Dim delg As ProjectItemScan.ProcessPIScanResult = _ AddressOf HandleProjectItems |
| Private Sub HandleProjectItems(ByVal pi As ProjectItem) If langType = 8 Then If pi.Name.ToLower = "tbevents.vb" Then tbeExtant = True End If Else If pi.Name.ToLower = "tbevents.cs" Then tbeExtant = True End If End If End Sub |
| ProjectItemScan.ScanForProjectItems(prj, delg) |