Is it possible to call "level all" through vba in ms-project? - vba

I am using Microsoft Project 2010 professional and i want to know if it is possible to :
The Question
Use visual basic to call the "Level All" function under the resource tab.
Why would i want that?
I want to do this because we are using various "cadence" in our project. So the same array of tasks might be done in 4 days, or 10 days. Now when there is such a change in "cadence" we will have to increase/decrease the number of employees working on the day/night shifts and reassign tasks to wether day or night shift. This task has to be done manually. And I obviously want to automate it.
So i want to address overallocated tasks and "past deadline" errors. Hence the need to get the indicators columns value.
Project settings
I am using 2 calendars:
"DayShift" everyday from 6:30 AM to 2:30 PM
"AfterDayBeforeNight" everyday from 2:30 PM to 10:30 PM
Assigned to two resource:
The code:
Dim t As Task
For Each t In Application.ActiveProject.Tasks
Dim success As Boolean
Dim r As Resource
success = Application.SelectRow(t.ID, False)
If success Then
Dim posAJ As Integer
Dim posAS As Integer
posAJ = InStr(t.ResourceNames, "A-J")
posAS = InStr(t.ResourceNames, "A-S")
If posAJ <> 0 Then
Font32Ex CellColor:=62207
End If
If posAS <> 0 Then
Font32Ex CellColor:=32207
End If
Dim warn As String
warn = t.Warning
End If
Next
Thank you for your time.

For Q2: You can call from VBA
LevelNow All:=True
See https://msdn.microsoft.com/en-us/library/office/aa195121(v=office.11).aspx

Related

How to add a set number of date to a date in MS Project VBA without counting non-working time

I am trying to set the deadline for a task by taking the amount of slack from the finish date. Thus, I need to be add or take days from the finish and not count any non-working time.
I have made DateAdd work however this includes non-working time, so for instance if I am setting the deadline for 7 days before the finish (11/10/22) I would expect the deadline to be 30/09, giving a slack of -7
However using t.finish = dateadd("d",slack,t.finish) gives 04/10 with a finish of 11/10
I have tried Application.ProjDateAdd(t.Finish, slack, "standard") however VBA doesn't like this.
Any ideas? I know that I am doing something stupid or missing something obvious as MSP is excellent at avoiding non-working time normally so this must be user error :)
Edited to correct 1/10 to 30/09
To:
add or take days from the finish and not count any non-working
time
use the Project Application methods DateAdd and DateSubtract:
Sub SetDeadline()
Dim cal As Calendar
Set cal = ActiveProject.Calendar
Dim t As Task
For Each t In ActiveProject.Tasks
If t.TotalSlack > 0 Then
t.Deadline = Application.DateAdd(t.Finish, t.TotalSlack, cal)
Else
t.Deadline = Application.DateSubtract(t.Finish, -t.TotalSlack + 480, cal)
t.Deadline = Application.DateAdd(t.Deadline, 480, cal)
End If
Next t
End Sub
Also, take a look at Late Finish which is the latest date that a task can finish without delaying the finish of the project.

MS Project VBA Copy Finsh Date to Finsh 1

Im new to VBA, and looking for a simple code to copy say, my current finish and start dates to finish1 and start1
So I can track a shift trend
Here is a simple procedure that loops through the tasks in the active schedule and copies the start/finish dates into start1/finish1.
Sub CopyDates()
Dim t As Task
For Each t In ActiveProject.Tasks
t.Start1 = t.Start
t.Finish1 = t.Finish
Next t
End Sub
In addition to the method Rachel provided, you can use the BaselineSave method of the MS Project Application object. Even though it's called BaselineSave, the method has optional arguments that will allow you to copy current dates into any of the start/finish fields without setting the actual baseline of the tasks. I prefer this method since it can accomplished in a single line.
Sub CopyDates()
Application.BaselineSave All:=True, Copy:=pjCopyCurrent, Into:=pjIntoStart_Finish1
End Sub

How to write my own filter for predecessors in VBA for MS Project?

I am currently setting up a GAANT chart to determine the runtime and dependencies of a huge project.
There are a little over 600 tasks. They are dependent on each other, but unfortunately not in a linear and clustered way.
I can colourise the predecessors and successors of one task. But, because there are other tasks in between, I need to scroll a lot to get to the next connected task.
I want to write a filter in VBA, so that it will show me ONLY the connected Predecessors and Successors of the selected task.
So far I do not even know how to write a simple filter, because the online documentation is very poor, when it comes to filters.
Applying a normal filter does not work, because it will give me only the direct predecessors and successors.
I expect the predecessors of the predecessor, and so on.
I hope someone can help me.
I found a solution with the help of google. It is a bit of a workaround.
My code flags all the predecessors with a simple "Yes" in the Projects Field "Text10" (you can use any other Text field), and then I filter all the tasks with the "Yes".
Dim ProjTasks As Tasks
Dim ProjTasks2 As Task
Dim ProjTasks3 As Tasks
Dim ProjTask As Task
Dim ProjTask2 As Task
Dim ProjTask3 As Task
Dim Deadline As String
Set ProjTasks = ActiveProject.Tasks
Set ProjTasks2 = ActiveProject.Tasks
Set ProjTasks3 = ActiveProject.Tasks
So here comes the main part of my code:
For Each ProjTask In ProjTasks
If ProjTask.Start < (DateValue(Deadline) + TimeValue(Deadline)) Then
For Each ProjTask2 In ProjTasks2
If ProjTask2.Start < (DateValue(Deadline) + TimeValue(Deadline)) Then
If Not (ProjTask2 Is Nothing) Then
If ProjTask2.Text10 = "YES" Then
PredArray() = Split(ProjTask2.Predecessors, ";")
For Each i In PredArray()
For Each ProjTask3 In ProjTasks3
If ProjTask3.Start < (DateValue(Deadline) + TimeValue(Deadline)) Then
If ProjTask3.ID = i Then
ProjTask3.Text10 = "YES"
End If
End If
Next ProjTask3
Next i
End If
End If
End If
Next ProjTask2
End If
Next ProjTask
Because it contains 3 for-loops I tried to minimise the number of tasks, that are looped over.
Because I can see when my target task ends (Deadline), I do not loop over tasks which have a beginning time after the end time of my target task.
Be careful, that code takes some time to run through. After the code ran through, you can go to column "Text10" and filter the "Yes".
Starting with MS Project 2013, there is a feature that highlights Predecessors and Successors of the active task (see end for details).
However, to hide all tasks not linked to a particular task requires code. Fortunately the PredecessorTasks and SuccessorTasks collection objects make easy work of this.
This code finds all tasks linked to the target task (active task in this case) and sets a flag (Text10='Yes') so that non-linked tasks can be filtered out. The code only touches tasks linked to the target task, and only touches them one time each so it runs very quickly.
The code can be easily modified to use a different target task and to add criteria such as to skip over completed tasks.
Sub FlagTasksLinkedtoTargetTask()
Dim tsk As Task
For Each tsk In ActiveProject.Tasks
tsk.Text10 = vbNullString
Next tsk
Dim TargetTask As Task
Set TargetTask = Application.ActiveCell.Task
FlagPredecessors TargetTask
FlagSuccessors TargetTask
End Sub
Sub FlagPredecessors(tsk As Task)
Dim pred As Task
For Each pred In tsk.PredecessorTasks
If pred.Text10 <> "Yes" Then
pred.Text10 = "Yes"
FlagPredecessors pred
End If
Next pred
End Sub
Sub FlagSuccessors(tsk As Task)
Dim succ As Task
For Each succ In tsk.SuccessorTasks
If succ.Text10 <> "Yes" Then
succ.Text10 = "Yes"
FlagSuccessors succ
End If
Next succ
End Sub
FYI: The highlighting feature is found under Task Path on the Format tab (when viewing a Gantt Chart view). You can select to highlight Predecessors, Driving Predecessors (only the ones that currently are affecting the date), Successors, and/or Driven Successors. Here's the documentation.

MS Project VBA Code to Delete Zero Work Effort Tasks Using a Custom Field as Criteria

I am currently trying to write a VBA code that will look at a project plan and delete all of the tasks that have zero work effort, but are not a milestone, from my plan. We have added a custom field called Key Milestone to capture whether a task is a milestone or not. The reason we are not using the existing Milestone field is that not all of the tasks with zero work effort and zero duration are necessarily milestones.
I was previously unfamiliar with the GetField function in VBA and I have been working through a couple of tries at incorporating this to 'read' the custom field as a part of this code. Here is what I have so far:
Sub DeleteMsProjectTask()
Dim proj As Project
Dim t As Task
Set proj = ActiveProject
For Each t In proj.Tasks
If t.OutlineLevel > 1 And t.Work = 0 Then
If GetField(FieldNametoFieldConstant("Key Milestone") = Yes Then
Else
t.Delete
End If
End If
Next t
End Sub
This is not working as it doesn't read the milestone field correctly. Thanks in advance for the help!
GetField is a method of the Task object, so you need to preface it with your task object variable, e.g. t.GetField. Also, you missed a closing parentheses. And since GetField returns a string, you need to compare to a string--in other words, the word Yes needed to be in quotes. Since the criteria for deletion was actually a "No" value, I simplified your code accordingly.
Sub DeleteMsProjectTask()
Dim proj As Project
Dim t As Task
Set proj = ActiveProject
For Each t In proj.Tasks
If t.OutlineLevel > 1 And t.Work = 0 Then
If t.GetField(FieldNameToFieldConstant("Key Milestone")) = "No" Then
t.Delete
End If
End If
Next t
End Sub

Vb.net How can I sleep between multiple tasks in a sub

Figured my previous attempt in doing this question was too opinion based, so I'll be more specific.
Intro:
I'm trying to best way possible sleep inbetween multiple "tasks" within a private sub, but my attempts so far have failed me.
I have 9 "tasks" being triggered by a timer timermain and a progressbar pbmain that are working together. At pbmain.value 10 task 1 is being triggered, at pbmain.value 20 task 2 is being triggered and this goes all the way up to pbmain.value 100 and at that point it sets value to 1 and then this whole process loops over and over.
The problem is that this way is not very accurate because some of the tasks take more time than the others, so I'd much rather like to somehow sleep/pause/wait a second or so between each task than use progressbar value.
This is what it looks like
Private Sub TimerMain_Tick(sender As Object, e As EventArgs) Handles TimerMain.Tick
pbMain.Increment(1)
'Channel 1
If cbc1.Checked = True Then
If pbMain.Value = 10 Then
Try
Dim fileTotal As Integer
For Each item As String In lbChannel1.Items
fileTotal += My.Computer.FileSystem.GetFiles(item.ToString, FileIO.SearchOption.SearchTopLevelOnly, (tbExt1.Text)).Count
Next
tbCount1.Text = String.Format("{0}", fileTotal.ToString)
Catch ex As Exception
lbErrors.Items.Add(String.Concat(TimeOfDay & " Error 001: ", ex.Message)) 'Error output
End Try
End If
End If
'Channel 2
'... same as above. Then channel 3, 4, 5, 6, 7, 8 and 9...
To clarify what this does and the whole purpose:
I have so called channels in my form. Each channel is a listbox with items that are paths like \server\share\folder. The code above counts files in those folders if checkbox for that specific channel is checked and gives number output to a textbox tbcount1-9. So yes, the application is monitoring files going in and out of specified folders.
My goal:
Do task 1 -> Complete task 1 and wait one second -> Move to task 2 -> repeat this all the way to task 9 and then loop
I've tried:
Perform step. Did not work well because it looped too fast and fast out of control. I removed pbmain.increment and used performstep between each task.
Thread.sleep. This caused the whole application to sleep for given amout of time instead .
Progressbar marquee mode. I tried, but couldn't figure out how to make it work like my goal.
My question:
How can I complete my goal using something else than progressbar value with a timer...?
Update
Alexander's comment answered my question
You can try with Asnyc/Await Asynchronous Programming with Async and Await
Since your task are working with IO - async/await will be best approach.
Starting new thread only for waiting result from IO is waste of resources(threads).
Private Async Function ExecuteAllAsync() As Task
While True
Await ExecuteTasksAsync()
End while
End Function
Private Async Function ExecuteTasksAsync() As Task
Dim task1 As Task = ExecuteTaskNumberOneAsync()
Await Task.Delay(1000)
Dim task2 As Task = ExecuteTaskNumberTwoAsync()
Await Task.Delay(1000)
'... and so on
'Then wait for all results
Await Task.WhenAll({task1, task2, ...})
End Function
Here is only an idea - of course code above can/must be refactored to "usable" way
Are you just looking for a simple 1 second delay? If so.
Dim Current_Time as Date=Now
While DateAdd(DateInterval.Second, 1, Current_Time)>Now
End While
Now returns the current Date and Time
So I guess your flow would be
Task1->
Delay 1 Sec->
Task 2