Understanding the Project Object Model

Every application that can be automated with Visual Basic has an object model. The object model is a road map to the objects in the application that have been exposed—that can be used in VB automation. By now, you should understand the Project object model fairly well: You have been reading about it and working with it for the last 26 chapters. The structure of the Project object model mirrors the structure of the Project program itself.

You know, for example, that before you can create a task, you need to have a project opened. Likewise, in VB you will need a Project object before you can create a Task object. There’s a term for the relationship between the two: The Project object is the parent object for the Task object.

Project is built on the concept of the Component Object Model (COM). Simply put, COM is the idea that an application has built-in components, with each component responsible for providing a specific functionality. The application is built by linking together the individual components. COM allows existing components to be reused for other applications. New components can be introduced or existing components replaced without requiring an update to the entire application.

COM is not a new idea in software, but what is significant about Microsoft’s implementation of COM, ActiveX, is that it is a widely used standard. Prior to ActiveX, there were a number of company-specific standards for developing COM components. If a product were built on one standard, it could not share components with or utilize components from another standard.

ActiveX is a standard set of technologies that allows applications such as COM components to work together, even if they were created using different programming languages. Object model ActiveX is based on abstracting code into objects that have properties, methods, and events. These objects are exposed so they can be manipulated with Visual Basic code.

Exposed objects can be used in a VBA module attached to a project document, or called from other programs such as Excel, Word, and Visual Basic to automate actions within Project. An application’s ActiveX object model is your reference guide to the objects that you can use in programming code. The ActiveX object model is hierarchical in structure similar to the Windows folder structure. For example, the Project object contains collections of Task objects and Resource objects, because a Project file can contain tasks and resources. The Project object is the parent object of both the Task object and the Resource object. Figure 27.1 details the hierarchy of the Project object model, as shown in the VBA Help system.

click to expand
Figure 27.1: The Project object model

Two objects in the structure (the Application object and the Project object) are publicly creatable; the others are not. A publicly creatable object can be created outside the native application. When Project is automated from another application, such as an Excel VBA Project, new instances of the Application and Project objects can be created using the CreateObject function. You can also create new instances of the Application and Project objects from within Project, using the New keyword in the variable declaration or a Set statement. From Excel or any other VB-aware application, you can create a new Project Application object or Project object, or work with existing items in a project file.

You can’t use the CreateObject function to create a new task, however. Project objects, other than the Application object and Project object (such as Task and Resource objects) have to be created by using methods of a parent object. For example, to create a task, you rely on the parent Project object, and use the Add method of the Tasks collection of the Project object.

Note 

The file that contains VB code modules and UserForms attached to an application file is called a VBA project (not to be confused with Microsoft Project—or a project file).

The Project object model generally has two types of objects: objects that represent items, and objects that represent collections of items.

We’re assuming that you’re fairly familiar with the terminology that Project uses to refer to items and fields. If you think of the way that you normally use the application, the object model should be easy to understand. For example, a project has a number of tasks. There is a tab on a task’s dialog box where a number of resources have been assigned to the task, and a tab that lists the task’s predecessors (tasks that the task depends on). Here’s how these relationships are reflected in the Project object model:

  • A Project object has a Tasks collection filled with Task objects.

  • A Task object has an Assignments collection with Assignment objects.

  • The Task also has a DependencyTasks collection with DependencyTask objects.

As we noted in Chapter 26, the hard part about automating Project or any other application isn’t understanding Visual Basic—it’s understanding the application. In the next section, we’ll examine the objects in the Project object model and their events in detail. As you read through this section, you’ll find that the object model directly reflects the way Project operates.

The Application Object

At the top of the object model is the Application object, which provides access to Project itself. One of the primary roles of the Application object is to provide access to other top-level objects that you will manipulate through code, just as you fire up the Project application to get to a project’s tasks and resources. The Application object is a versatile object and, in theory, any action in Project can be accomplished through the use of methods of the Application object. Using the Application object to manipulate tasks and other items, however, is often the least efficient way to accomplish the job. Furthermore, although you can change the value of any field for an item with the Application object, the Application object provides no methods for examining the current value of a field in an item.

Note 

The Application object has several hundred methods. In fact, it has one method for each command that appears on a menu bar or toolbar. All the commands that appear in a macro created with the Macro Recorder are actually methods of the Application object.

The publicly createable Application object also has public events, which can be automated from applications other than Project. Table 27.1 lists the public events of the Application object.

Table 27.1: Application Object Events

Event

Condition when Event Occurs

ApplicationBeforeClose

Occurs before Microsoft Project exits

EnterpriseAllowLocalBaseCalendars

Occurs after a new enterprise project is created in Project Professional

EnterpriseFileCheckin

Occurs after a new enterprise project is created in Project Professional

GoalAreaTaskHighlight

Occurs after a new project is created

LoadWebPage

Occurs after the LoadWebBrowserControl method is called

LocalID

Occurs after a new project is created

NewProject

Occurs after a new project is created; cannot be canceled

ProjectAfterSave

Occurs after a new project is created

ProjectAssignmentNew

Occurs when a new assignment is created

ProjectBeforeAssignmentChange

Occurs before the user changes the value of an Assignment field

ProjectBeforeAssignmentChange2

Occurs before the user changes the value of an Assignment field*

ProjectBeforeAssignmentDelete

Occurs before an assignment is deleted or replaced

ProjectBeforeAssignmentDelete2

Occurs before an assignment is deleted or replaced*

ProjectBeforeAssignmentNew

Occurs before one or more assignments are created

ProjectAssignmentNew2

Occurs before one or more assignments are created*

ProjectBeforeClearBaseline

Occurs before the baseline is cleared

ProjectBeforeClose

Occurs before a project is closed

ProjectBeforeClose2

Occurs before a project is closed*

ProjectBeforePrint

Occurs before a project is printed

ProjectBeforePrint2

Occurs before a project is printed*

ProjectBeforeResourceChange

Occurs before the user changes the value of a Resource field

ProjectBeforeResourceChange2

Occurs before the user changes the value of a Resource field*

ProjectBeforeResourceDelete

Occurs before a resource is deleted or replaced

ProjectBeforeResourceDelete2

Occurs before a resource is deleted or replaced*

ProjectBeforeResourceNew

Occurs before one or more resources are created

ProjectBeforeResourceNew2

Occurs before one or more resources are created*

ProjectBeforeSave

Occurs before a project is saved

ProjectBeforeSave2

Occurs before a project is saved*

ProjectBeforeSaveBaseline

Occurs before a baseline is saved

ProjectBeforeTaskChange

Occurs before the user changes the value of a Task field

ProjectBeforeTaskChange2

Occurs before the user changes the value of a Task field*

ProjectBeforeTaskDelete

Occurs before a task is deleted or replaced

ProjectBeforeTaskDelete2

Occurs before a task is deleted or replaced*

ProjectBeforeTaskNew

Occurs before one or more tasks are created

ProjectBeforeTaskNew2

Occurs before one or more tasks are created*

ProjectCalculate

Occurs after a project is calculated; cannot be canceled

ProjectResourceNew

Occurs when a new resource is created

ProjectTaskNew

Occurs when a new task is created

SaveAs

Occurs when saving a file under a different file name

WindowActivate

Occurs when any window within Microsoft Project is activated

WindowBeforeViewChange

Occurs when the top pane view is changed within a window in Microsoft Project

WindowDeactivate

Occurs when any window within Microsoft Project is deactivated

WindowGoalAreaChange

Occurs after the user clicks a different goal area within the Project Guide

WindowSelectionChange

Occurs when the selection handle is changed within a window

WindowSidepaneDisplayChange

Occurs when the user clicks the Show/Hide Project Guide button on the Project Guide toolbar to show or hide the Project Guide

WindowSidepaneTaskChange

Occurs when a user selects different items in the Next Steps and Related Activities menu in the Project Guide

WindowViewChange

Occurs after the top pane view is changed within a project window

WorkpaneDisplayChange

Occurs when the Project Guide is hidden or shown

*All events that end in a “2” are new events that make use of an EventInfo object.

All Application events, with the exception of NewProject and ProjectCalculate, have a Cancel parameter. If you set the Cancel parameter to True, Visual Basic will abort the pending event. This is consistent with the way things work in Project, where you click the Cancel button in a dialog box to cancel whatever it was the dialog box was going to do (the pending event). The events that you can’t cancel with code can’t be canceled from the user interface, either. When you click the New button on the toolbar, you can’t change your mind and then cancel the request.

To use Application events, you need to declare a module-level Application object variable. (Module-level declarations appear before any procedures in a module. See Chapter 26 for information on declaring variables.) You then use the WithEvents keyword to inform VBA that this object has events for which you are going to write event procedures. You cannot use both the WithEvents and New keywords in the same declaration statement, nor can you use WithEvents for a Variant or generic Object variable; the object type must be explicitly declared. Here’s the declaration statement for the Application object:

Dim WithEvents pjApplication As MSProject.Application

After you declare an object variable WithEvents, you need to set it to an object. The Set statement should be placed with the code that handles the initialization of the module. The following code samples show the placement of the Set statement for a ThisProject module and a UserForm module. We will be covering these types of modules a little later in the chapter.

 'Setting the Application object in a ThisProject Module Private Sub Project_Open(ByVal pj As Project)   Set pjApplication = pj.Application End Sub 'Setting the Application Object in a UserForm Module Private Sub UserForm_Initialize()   Set pjApplication = Application End Sub
Tip 

In the last chapter, we discussed types of modules: User Forms, Class Modules, and modules, also known as standard modules. There’s a fourth type of application-created module specifically called the ThisProject module, which is in scope (open) for the duration of a project. You can use WithEvents in User Forms, ThisProject modules, and Class modules, but you can’t use it in standard modules. For more information on module types, refer to Chapter 26.

The Project Object

The Project object represents an opened project document. The Projects collection of the Application object contains all project files that are currently open—the same collection of objects you see if you open Project’s Window menu. To create a new project, you can use the Add method of the Projects collection or the FileNew method of the Application object.

To open an existing project file, you use the FileOpen method of the Application object. The opened project document is automatically appended to the Projects collection, just as it automatically appears in the list of files on the Window menu. The documentation for the FileOpen method may seem a little overwhelming. The FileOpen method has a number of optional parameters to tell Project how to open a file if it is not a project document. The Activate method of the Project object is used to set the project as the active project.

The Project object is the other object in Project’s object model that has public events. (Table 27.2 lists the public events of the Project object.) You’ll write event procedures for the Project object’s events in the ThisProject module. When you use the ThisProject module, you do not need to declare and set an object variable as you do for the Application object. The ThisProject module is already pointed at the current project.

Table 27.2: Project Object Events

Event

Condition when Event Occurs

Activate

When the project is switched to the active project in the application

BeforeClose

Before the project is closed

BeforePrint

Before the project is printed

BeforeSave

Before the project is saved

Calculate

After the project has been calculated

Change

When any information in the project is changed, but not if the user simply switches views or filters

Deactivate

When the project is switched from the active project in the application; that is, another project is activated

Open

When a project is opened

Using the Task Object

The Task object represents a task within a project, as shown in Figure 27.2. This object allows the fields of a task to be examined or changed programmatically. Task objects are not top-level objects, and must be created or accessed by using the Tasks collection of a top-level object. The Tasks collection contains the tasks associated with the collection’s parent object. This is usually a Project object, a Selection object, or a Cell object. To add a new Task to the Parent object, you use the Add method of the Task collection.

Dim objProject As MSProject.Project Dim objTask As MSProject.Task Set objProject = Application.ActiveProject Set objTask = objProject.Tasks.Add()


Figure 27.2: The Task Branch of the Project object model

Using the Resource Object

Resources are handled similarly to tasks within the object model, as shown in Figure 27.3. The Resource object represents a resource within a project.


Figure 27.3: The Resource Branch of the object model

Similar to Task objects, a Resource object must be accessed through the Resources collection:

Dim objResource As MSProject.Resource Dim objProject As MSProject.Project Set objProject = Application.ActiveProject Set objTask = objProject.Resources.Add()

Using the Assignment Object

The Assignment object represents the link between a Task and a Resource: the assignment of the resource to the task. Assignments are created using the Add method of the Assignments collection. The Add method of the Assignments collection has three optional named parameters: TaskID, ResourceID, and Units, which are identical to the TaskID, ResourceID, and Units fields in the Assignments dialog box.

'Adding an Assignment from a Task ActiveProject.Tasks(1).Assignments.Add ResourceID:=1, Units:=100

or

ActiveProject.Tasks(1).Assignments.Add ,1, 100 'Adding an Assignment from a Resource ActiveProject.Resources(2).Assignments.Add ResourceID:=2, Units:=100

or

ActiveProject.Resources(2).Assignments.Add, 2 , 100

Using the Cell and Selection Objects

The Cell object and Selection object represent selected items within the Project application. Neither of these objects belongs to a collection, nor can new instances of the objects be created. To access these objects, properties of the Application object must be used. The ActiveCell property of the Application returns a Cell object, and the ActiveSelection property returns a Selection object.

The Cell object represents the active cell selected in the table view. The FieldID and FieldName properties of the Cell object represent the column in the table. The FieldID property is a long integer, Long, that contains the internal code Project uses for the field. FieldID is useful when you need to use the GetField or SetField methods of a Task object or Resource object. FieldID works fine when passing field identifiers between functions, but FieldID 188743687 is not significant to users. The FieldName property returns the full name of the Field as a string: If the active cell is the Actual Work field in the Task table, the FieldName property does not return "Actual Work"; it returns "Task Actual Work".

start sidebar
Mastering Troubleshooting: Implementing the Cell Object

The Cell object, returned by the ActiveCell property of the Application object, has a few quirks and is not as simple to use as one would think. The Cell object has a Resource property to return a Resource object if the cell refers to a field in a resource, and a Task property to return a Task object if the cell refers to a field in a task. The Cell object does not, however, have a property to inform you which type of object the Cell refers to. When you call the Cell object, you need to know which property to call or an error will occur, so you need a method to determine the type of item to which the active cell refers. There is an unused type in the model PjFieldType that can be either pjTask or pjResource, which we’ll use to get this information. The following function makes use of pjFieldType:

Public Function ActiveCellType() As PjFieldType   Dim pjCell As MSProject.Cell   Dim ReturnValue As PjFieldType   Set pjCell = Application.ActiveCell   If InStr(1, pjCell.FieldName, "Task", vbTextCompare) = 1 Then     ActiveCellType = pjTask Else     ActiveCellType = pjResource   End If End Function

end sidebar

If you want to examine only the text in the active cell, you can simply use the Text property of the Cell object; however, if you want to alter the value in the active cell programmatically, it becomes a little trickier. The Text property of the Cell object is read-only, so you will have to use a property of the appropriate Resource or Task object:

Sub SetActiveCellTo(Value As String)   Dim pjCell As MSProject.Cell   Dim lngFieldId As Long     On Error Resume Next   Set pjCell = Application.ActiveCell   lngFieldId = pjCell.FieldID   If Not (pjCell.Resource Is Nothing) Then     pjCell.Resource.SetField lngFieldId, Value   ElseIf Not (pjCell.Task Is Nothing) Then     pjCell.Task.SetField lngFieldId, Value   Else ' Cell does not belong to an item   End If End Sub

Project has defined constants for all the FieldID numbers. These constants are the full name of the field, prefixed with pj. The FieldID constant for Task Actual Work would be pjTaskActualWork. This also works for custom fields, but you must use Project’s actual name for the field (Task1, Cost7, and so on); therefore, the FieldID constant for the Task1 custom field would be pjTask1.

Warning 

The Cell object always returns a FieldName and FieldID, but the Resource and Task properties are only valid if the active cell is in a row corresponding to an item. If you call the Resource or Task property when it does not apply, a trappable error will occur. Routines that use these methods need to have appropriate error handling.

The Selection object represents a selected range of cells within the table view. The methods of the Selection object are similar to the methods of the Cell object. The Tasks property returns a Tasks collection if the selection is in a tasks table. Likewise, the Resources property returns a Resources collection if the selection is in a resource table. A selection can include multiple columns in the table, so List objects are used to return the field IDs and field names of the selected columns. The FieldIDList property is used to retrieve a List of field IDs for the column. In a similar fashion the FieldNamesList property is used to retrieve a List of field names. The List object has two main properties: the Count, which returns the number of items in the list, and the Item property, which returns the value of the item as a string. The following example would display the names of all selected columns in a message box.

Dim pjSelection As MSProject.Selection Dim pjListNames As MSProject.List Dim strMsgText As String Dim i As Integer Set pjSelection = Application.ActiveSelection Set pjListNames = pjSelection.FieldNameList If pjListNames.Count > 0 Then   For i = 1 To pjListNames.Count     strMsgText = strMsgText & " " & pjListNames(i)   Next i Else   strMsgText = "No Cells Selected" End If MsgBox strMsgText
Warning 

The Item property of a List always returns a string value. If you use a string for the FieldID parameter of the GetField or SetField methods, however, an error will occur. To prevent this error you can use the CLng function to convert the string to a long integer as follows: CLng(ActiveSelection.FieldIDList(i)).



Mastering Microsoft Project 2002
Mastering Microsoft Project 2002
ISBN: 0782141471
EAN: 2147483647
Year: 2006
Pages: 241

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net