PDA

View Full Version : Create new task when task is completed



Stephanie
05-17-2006, 01:48 PM
Good afternoon. I apologize in advance for any crazy questions I may ask in this forum. I am a newbie when it comes to VBA in Outlook, though fairly competent in VBA in Excel.

I have a simple task, I hope. I would like to create a new task when the original task is completed. I have absolutely no idea how to tackle this. Any direction is much appreciated.

Thanks.
Stephanie

Killian
05-17-2006, 05:36 PM
Hi Stephanie and welcome to VBAX :hi:

It's not such a crazy question and (relatively) simple...
It can be done by defining a class that has an object variable of type TaskItem "withevents".

Now you can now use the PropertyChange event of the class to kick off creating the new item.
You'll also need a routine to set up a collection to hold all the instances of the event-enabled items for the session. These instances will be derived for each of the tasks in the task folder.
This routine should be called from the "Application_Startup" event (in the ThisOutlookSession module) and after creating the new item.

It all looks like this...

Class module:Private WithEvents m_Task As TaskItem

Public Sub Init(t As TaskItem)
'!requires a task item passed as an argument!
Set m_Task = t
End Sub

Private Sub m_Task_PropertyChange(ByVal Name As String)
Dim oNewTask As TaskItem
If Name = "Complete" Then 'this is in fact the "Status" dropdown
' the ITEM's Complete property won't be true until the item is saved
m_Task.Save
If m_Task.Complete Then
Set oNewTask = CreateItem(olTaskItem)
With oNewTask
.Subject = "The subject"
'set other task properties here
.Save
're-initialize the collection
Init_Event_Handler
End With
End If
End If
End Sub

Private Sub Class_Terminate()
Set m_Task = Nothing
End SubStandard module:' I called my class "cTaskEvents"
Dim myClass As cTaskEvents
Dim colTasks As New Collection

Sub Init_Event_Handler()
' call this from Application_Startup

Dim ns As NameSpace
Dim oFolder As MAPIFolder
Dim t As TaskItem
Dim i As Long

Set ns = Application.GetNamespace("MAPI")
Set oFolder = ns.GetDefaultFolder(olFolderTasks)
'clear the collection
Do
i = colTasks.Count
If colTasks.Count > 0 Then colTasks.Remove colTasks.Count
Loop Until colTasks.Count = 0

For Each t In oFolder.Items
Set myClass = New cTaskEvents 'new class instance
myClass.Init t 'pass the item to the class' Init routine
colTasks.Add myClass 'add instance to collection
Next t

End Sub

Stephanie
05-18-2006, 10:03 AM
I'm getting a "User defined type not defined" error at "Dim myClass As cTaskEvents". What exactly does this mean and how do I fix it?

Killian
05-18-2006, 11:45 AM
It means there's no definition of "cTaskEvents", which is what you need to set as the Name property of the class you created - I'm guessing its still called Class1?

Stephanie
05-19-2006, 09:16 AM
I'm guessing its still called Class1?

Ahh. I see.

Ok. I'm trying to step through this to figure out what it is doing. When I complete one task it creates three new ones.

I'm sorry, but I really don't know what all the code means. I think I need a little more help.

Killian
05-24-2006, 05:37 AM
Hi Stephanie,

Sorry I didn't get back to you sooner... how are you getting on with this?

I can't see why it's creating three new ones, it tested well with me (OL2003)... :think:

Let me know if you still need a fuller explanation of the code...

Stephanie
05-24-2006, 11:50 AM
After spending a little more time going through the code I feel like I know what should be happening, so that's a step in the right direction. Still, though, three new tasks are created when one is completed and I don't know why.

I am using OL2002 if that makes a difference.

Also...

If Name = "Complete" Then 'this is in fact the "Status" dropdown

... this is the status dropdown menu within the task? When I step through this code Name does not equal all the status options. Ex- "waiting on someone else" is an option in the dropdown, but I never see Name equal that when the code is run.

Killian
05-25-2006, 01:30 AM
I think I made a poor choice with the PropertyChange event... the problem being that a number of the items properties seems to change if you alter the status and we only really need to check one.
On reflection, a more straight-forward approach would be to use the item Close event and just check the Complete property. I would expect that to improve the situation Option Explicit

Private WithEvents m_Task As TaskItem

Public Sub Init(t As TaskItem)
'!requires a task item passed as an argument!
Set m_Task = t
End Sub

Private Sub m_Task_Close(Cancel As Boolean)
Dim oNewTask As TaskItem

If m_Task.Complete Then
Set oNewTask = CreateItem(olTaskItem)
With oNewTask
.Subject = "The subject"
'set other task properties here
.Save
're-initialize the collection
Init_Event_Handler
End With
End If
End Sub

Private Sub Class_Terminate()
Set m_Task = Nothing
End Sub

Stephanie
05-26-2006, 08:58 AM
The close event works well. The only concern I have is that I will have to manually open the task and complete it, instead of just checking the check-box.

I was thinking, wouldn't the property change event work if the name of the desired task was specified? What is the code to retrieve the task's name?

Killian
05-26-2006, 01:51 PM
I didn't notice that... so yes, we need to revert to the property change event.
I doing this, I found it was triggered another time (it looks like the multiple additions are a side-effect of using the checkbox on the unopened item) so I've added your suggestion of specifying the completed task, although I've used the EntryID property (this is an items' unique ID).

I set up a public variable, "CompletedTaskID". On the first pass, it's set with the EntryID so it can be ignored on the extra events.
I also moved the CreateItem part out of the class for clarity' ### standard module ###
Dim myClass As cTaskEvents
Dim colTasks As New Collection
Public CompletedTaskID As String

Sub Init_Event_Handler()

Dim ns As NameSpace
Dim oFolder As MAPIFolder
Dim t As TaskItem
Dim i As Long

Set ns = Application.GetNamespace("MAPI")
Set oFolder = ns.GetDefaultFolder(olFolderTasks)
'clear the collection
Do
i = colTasks.Count
If colTasks.Count > 0 Then colTasks.Remove colTasks.Count
Loop Until colTasks.Count = 0
CompletedTaskID = ""

For Each t In oFolder.Items
Set myClass = New cTaskEvents 'new class instance
myClass.Init t 'pass the item to the class' Init routine
colTasks.Add myClass 'add instance to collection
Next t

End Sub

Sub CreateNewTask()

Dim oNewTask As TaskItem

Set oNewTask = CreateItem(olTaskItem)
With oNewTask
.Subject = "The subject"
.Save
Set myClass = New cTaskEvents
myClass.Init oNewTask
colTasks.Add myClass
End With

End Sub
' ### standard module - END ###

' ### class module ###
Private WithEvents m_Task As TaskItem

Public Sub Init(t As TaskItem)
'!requires a task item passed as an argument!
Set m_Task = t
End Sub

Private Sub m_Task_PropertyChange(ByVal Name As String)

If Name = "Complete" Then
If m_Task.Complete Then
If CompletedTaskID = "" Then
CreateNewTask
CompletedTaskID = m_Task.EntryID
Else
CompletedTaskID = ""
End If
End If
End If

End Sub

Private Sub Class_Terminate()
Set m_Task = Nothing
End Sub
' ### class module - End ###
There is a slight problem which you might just choose to ignore...
When you delete a Task, its associated class instance remains in the collection. The result being that if you create/delete a large number of tasks during an Outlook session, you'll end up with a lot of redundant items in the collection, using up memory.
I would have been nice to use the Before_Delete event to remove the collection item but this event only fires it the item is open... if you delete from the app toolbar with the tasks in list view (most likely) it doesn't.

I think you should get away with it but it's far from ideal. I've decided to upgrade my original assesment of "(relatively) simple" to "somewhat complicated" :whistle:

Stephanie
05-31-2006, 05:04 AM
Your modifications work well. I really appreciate your help. Thanks.