So, I created my event handler just as I have described in previous entries. Create an event on the child, bubbles up to the parent. Create a common key between the two. Add an ItemUpdated event handler so then if the child event is updated the parent is updated too. Same with ItemDeleted. Everything hunky dory -
OK, wait, back up the truck. What about recurring events? How do they work?
Leaving them out was not an option. The department had quite a few weekly meeting events. So I hit Mr Google and got a handy link from MSDN here which suggested the following code.
SPListItem recEvent = listItems.Add(); string recData = "<recurrence><rule>" + "<firstDayOfWeek>su</firstDayOfWeek>" + "<repeat><daily dayFrequency='1' /></repeat>" + "<repeatInstances>5</repeatInstances></rule></recurrence>"; recEvent["Title"] = evtTitle; recEvent["RecurrenceData"] = recData; recEvent["EventType"] = 1; recEvent["EventDate"] = new DateTime(2011,8,15,8,0,0); recEvent["EndDate"] = new DateTime(2011,9,25,9,0,0); recEvent["UID"] = System.Guid.NewGuid(); recEvent["TimeZone"] = 13; recEvent["Recurrence"] = -1;
item["RecurrenceData"] = properties.ListItem["RecurrenceData"];
and for the same reason I don't need to code the UID. So I save it and all is well. Then I a dd the recurring event. Let's say I set the start time at 1pm, the end time at 2pm, set it to occur weekly on a Tuesday for two weeks, and save it. Then I go to my parent calendar. In spite of the MSDN advice, still no sign of the recurring event being copied over.
So, I turn on the error handler and get back this error: Value does not fall within accepted range. This error means that the field RecurrenceData does not exist on the list. But how can it not exist? The Recurrence field exists for every event, surely?
Ah - but they are only visible on the form if you click the little Recurring Event checkbox! So if they are not visible on the form, some little quirk means that they are not visible in the code. This is probably because one recurring event contains many child events. So after much searching around I found this link which explained that I had to set the ShowInEdit property of the field concerned to true:
item.Fields["Recurrence"].ShowInEditForm = true;
The only thing that did not work for me in that link was the use of the GetInternalFieldName method. I replaced that with the GetField method, used those lines of code before updating each recurrence data field - you need to do it for all of them and don't forget to call this.DisableEventFiring() after each update! - and then built it once more. Hey presto, it created an event - of sorts.
The problem I have now is that the event that gets created on the parent calendar is a long, unspecified blob that covers all the days of the recurrence time. In order to have it work properly, I had to go into the event from the UI and click "Edit Item". The recurrence info is all there, present and correct. Click Ok, click past the warning message, and it's fine. All I need to do is mimic that update in code. All ideas and suggestions welcome!
ETA. See the following solution kindly provided by Noelle Marchbanks
Add to your copy code:
recEvent["EventType"] = properties.ListItem["EventType"];
recEvent["UID"] = System.Guid.NewGuid();
Even though you are copying an event, these fields are necessary to make it realize that a Recurrence is appropriate. It is IMPERATIVE that you set the EventType to the same as the copied list item, and not hard-code it as 1 as it will break non-recurring events and create orphaned exceptions to the rule.
If, for some reason, you do get orphaned recurring event children (e.g. ID = 1.1.x instead of ID = 1), open up powershell, get the item as an object, set its EventType to 1, then delete it from the list.
Hope this helps.