Search code examples
vb.netlinqoffice-interopms-project

MissingMemberException when trying to use LINQ on subproject Tasks


I am working on a Microsoft Project add-in in VB.NET. Each Project is of type Project, and has its own list of Tasks that are of type Tasks and they contain lots of tasks of type Task. Microsoft Project has an option to add other Project files inside of it as Subprojects. These subprojects are of type Subproject, but they have a property SourceProject which is of type Project. Meaning, you should be able to access each subprojects Tasks as if it were a regular Project type through Project.Subprojects(0).SourceProject.Tasks.

I tried using LINQ to filter out some tasks on a Project. I found this answer very helpful, and I managed to do it successfully without any errors. In the below code ThisProject is of type Project:

Dim tasksWithResources = ThisProject.Tasks.Cast(Of MSProject.Task).Where(Function(x) x.ResourceNames <> "")

However, when I try doing the exact same thing when iterating through subprojects, I get a MemberMissingException:

For Each subproject In ThisProject.Subprojects
    Dim subprojectTasksWithResources = subproject.SourceProject.Tasks.Cast(Of MSProject.Task).Where(Function(x) x.ResourceNames <> "")
Next

I tried accessing the subprojects tasks by simply assigning them to a variable thinking that there were no Tasks in that subproject. But it was successful. So even if I write it like this (which I know is the same thing as the code block above), I get the MemberMissingException on the row where I use Cast:

For Each subproject In ThisProject.Subprojects
    Dim tsks = subproject.SourceProject.Tasks
    Dim subprojectTasksWithResources = tsks.Cast(Of MSProject.Task).Where(Function(x) x.ResourceNames <> "")
Next

This is the error message I'm getting: Public member 'Cast' on type 'Tasks' not found.

Edit: I understand that an easy workaround is not using LINQ, but rather iterating through the object with a For Each, but I'm curious why LINQ is not working.


Solution

  • The issue might be that the subproject's tasks are not yet loaded.

    Try forcing the project to load by accessing a task. For example:

    For Each s As MSProject.Subproject In ThisProject.Subprojects
        Dim tempTsk As MSProject.Task = s.Tasks(1)
        Dim subprojectTasksWithResources = s.SourceProject.Tasks.Cast(Of MSProject.Task).Where(Function(x) x.ResourceNames <> "")
    Next
    

    I have used the following code in my add-ins to force the subprojects to load. It works well, but I think the above code might be all you need.

    Friend Sub ShowAllTasks()
        ' expands all tasks to make sure all collapsed subprojects are loaded
        With ProjApp
            .SummaryTasksShow(True)
            .FilterApply("All Tasks")
            .SelectAll()
            .OutlineShowAllTasks()
            .SelectBeginning()
        End With
    End Sub
    

    Note: this presumes the current view is a task view.

    P.S. Use a different variable name for your subprojects as subproject is the name of an object.