如何在子项目中选择任务的行(在主项目内)

时间:2017-06-20 14:32:42

标签: vba ms-project microsoft-project-vba

我有一个Master-Project,在里面我有几个子项目。

我想根据字段Text5的值格式化行的颜色。

当前问题:如何使用VBA代码引用第二个子项目中的行。 当我运行代码并修改任务ID 5中的Text5值(在子项目2中)时,它会修改任务ID 5的颜色,但是修改子项目1的颜色。

如何使用SelectRow并将参考添加到所需的子项目?

我的代码 (相关部分)

Sub FormatChangedTasks()

Dim SubPrj      As Subproject
Dim Tsk         As Task
Dim i           As Long

For Each SubPrj In ActiveProject.Subprojects
    ' compare the name of Sub-Project with the one saved in the "Stack" srray
    If SubPrj.SourceProject.Name = ModifiedPrjName Then
        For Each Tsk In SubPrj.SourceProject.Tasks
            If Not Tsk Is Nothing Then
                i = Tsk.ID

                ' check if Tsk.Text5 value has changed from value in "StatusStackArr" array
                If StatusStackArr(i - 1).StatusOldVal <> Tsk.Text5 Then
                    ' **** at the line below it selects the Row from the top
                    ' (not the desired Sub-Project) ******
                    SelectRow Row:=i, RowRelative:=False

                    ' --format entire row --
                    Select Case Tsk.Text5 ' Get the Field's used field, not name
                        Case "R", "Y", "G"
                            FontEx CellColor:=7, Color:=0
                            FontEx Italic:=False '  Font regular

                        Case "Complete"
                            FontEx Italic:=True '  Font Italic
                            FontEx CellColor:=15, Color:=14 ' Background Silver ; font Gray

                    End Select

               ' rest of code (un-relevant)

2 个答案:

答案 0 :(得分:1)

挑战 - 格式化主项目中的行

要格式化表格中的文字,请使用FontEx方法。此方法格式化活动(选定)单元格。要选择要格式化的行,请使用SelectRow方法。要使用此方法,您需要知道:

  1. 相对于有效选择的位置,或
  2. 其在可见任务中的绝对位置,或
  3. 根据唯一标识符
  4. 查找任务

    对于过滤器或折叠摘要隐藏的选项1和2任务,都必须相应地调整SelectRow方法的行参数。很难知道哪些任务可能被隐藏。使用此方法的最佳方法是首先确保所有任务都可见(请参阅代码)。

    此外,在使用子项目时,计算绝对行位置是一项挑战,因为首先需要将日程表中的子项目的任务计数加到主项目本身的任何本机任务中(尽管这是非典型的) )。

    所有这些都导致使用Find方法选项3作为在主项目中选择任务的最佳方式。要准确选择正确的任务,必须将Find方法与唯一字段一起使用。唯一ID字段是唯一保证唯一的字段。

    主项目中的唯一ID

    将任务添加到项目时,将分配增量唯一ID,从1开始。当项目在主项目中合并时,通过添加种子值来更改唯一ID,以便主服务器中不存在重复项项目

    种子价值基于内部子项目&#34;索引&#34;。第一个子项目的任务的种子值为4194304,第二个子项目的任务的种子值为8388608(4194304 * 2),依此类推。

    如果从主程序中删除子项目,它的索引&#34;没有重复使用。同样,如果子项目在主服务器中重新排列,则&#34;索引&#34;价值观不会改变。因此,您不能使用子项目对象的Index属性来获取内部&#34;索引&#34;用于创建种子的值,因为该属性仅指示子项目的顺序。 (注意,有一种方法可以获得这个内部值,但这超出了这个问题的范围。仅供参考,它还需要选择所有任务。)

    解决方案

    要在用户界面中选择任务,您需要知道主计划中的唯一ID。如果您通过SourceProject.Tasks方法访问任务,您将访问其本机子项目中的任务,并且唯一ID将不包含种子值。例如,唯一ID将是2,它在主项目中不是唯一的,因此不足以使用Find方法选择任务。

    由于您已经遍历了计划中的所有任务,因此确定主唯一ID的最简单方法是在主项目中本地循环执行任务。为此,选择所有任务并循环选择。

    Sub FormatChangedTasks()
    
    ' show all tasks
    FilterClear
    SelectAll
    SummaryTasksShow (0)
    OutlineShowAllTasks
    
    Dim AllTasks As Tasks
    Set AllTasks = ActiveSelection.Tasks
    
    Dim Tsk As Task
    
    For Each Tsk In AllTasks
        If Not Tsk Is Nothing Then
            ' compare the name of Sub-Project with the one saved in the "Stack" srray
            If Tsk.Project = ModifiedPrjName Then
    
                ' check if Tsk.Text5 value has changed from prior value
                ' NOTE: use a dictionary here instead of an array
                If StatusStackArr(i - 1).StatusOldVal <> Tsk.Text5 Then
    
                    Find "Unique ID", "equals", Tsk.UniqueID
                    SelectRow
    
                    ' --format entire row --
                    Select Case Tsk.Text5 ' Get the Field's used field, not name
                        Case "R", "Y", "G"
                            FontEx CellColor:=7, Color:=0
                            FontEx Italic:=False '  Font regular
    
                        Case "Complete"
                            FontEx Italic:=True '  Font Italic
                            FontEx CellColor:=15, Color:=14 ' Background Silver ; font Gray
    
                    End Select
    
                ' rest of code (un-relevant)
            End If
        End If
    Next Tsk
    End Sub
    

    注意:

    • 选择所有任务是必需的,除非您可以保证计划已经完全展开,并且您使用选项1或2.选择所有任务将花费一些时间使用10-15个子项目,但其余代码将以接近相同的速度跑。
    • 如果任务已分组或未按任务ID排序,则所有投注均以选项1或2关闭。
    • 将先前的值存储在由任务ID索引的数组中将无法与主项目一起使用。而是将先前的值存储在集合或字典中,并将主唯一ID作为键。 See this SO post about using dictionaries in VBA.

答案 1 :(得分:0)

插入子项目任务的(显示的)任务唯一ID来自以下公式:

(4194304 * ([PROJECT_UID]+1)) + [TASK_UID]

其中[PROJECT_UID]是插入项目的唯一ID(不是索引)。 (插入的子项目的项目摘要被视为主项目中的任务,并且会收到其自己的唯一ID。)

选择一个任务后,您可以从类似以下内容中获得插入子项目的唯一ID:

ActiveProject.Subprojects(ActiveSelection.Tasks(1).Project).InsertedProjectSummary.UniqueID

或者如果您已经拥有TASK_UID(一个长值),则可以使用:

ActiveProject.Subprojects(ActiveProject.Tasks.UnqiueID([TASK_UID]).Project).InsertedProjectSummary.UniqueID

最后,如果您本身具有Task对象:

ActiveProject.Subprojects(Task.Project).InsertedProjectSummary.UniqueID

您可以在此处使用Find "Unique ID","equals",[TASK_UID]选择要格式化的任务。

HT到Rachel,获取“种子”提示和值4194304。


编辑:有时Task.Project属性返回子项目名称(例如[MyProject]),有时返回完整路径(例如c:\users\[userName]\[MyProject].mpp),以便仅获取项目名称使用类似的东西:

If Instr(Task.Project,".mpp") > 0 Then
   strProject = Replace(Dir(Task.Project),".mpp","")
Else
   strProject = Task.Project
End If