Вы находитесь на странице: 1из 8

SHAREPOINT CALENDAR - PREVENT DOUBLE BOOKING

Source code and concept from: http://blog.sharepointsydney.com.au


Source code modified and implemented by: David Poarch

PROBLEM
The default SharePoint calendar does not come with double booking prevention.

DESIGN
Calendar double booking detection and prevention functionality will be implemented by first
adding a column for the event/location—in this case, the Meeting Room. Views for different
meeting rooms will also be created. A new class library will then be incorporated, which will
include custom event handlers for ItemAdding and ItemUpdating events.

PROCEDURE
1. Create a new calendar. (Site Actions  Create)
2. Click Settings  List Settings and create a new column.
3. Name the column “Meeting Room” of type “Choice”.
4. Add some meeting room choices. (e.g. Red Room, White Room, Blue Room)
5. Create a new view. (Settings  Create View)
6. Click “Calendar View”.
7. Name your view as one of the meeting rooms—Red Room, for example.
8. For the filtering criteria, select “Show items only when the following is true:”
9. Show the items when column “Meeting Room” “is equal to” “Red Room”.
10. Repeat these steps until you have created a view for all Meeting Rooms.
11. To get the necessary information in month view, create a new column called “Summary”.
12. The type will be “Calculated”.
13. The formula will be: =[Meeting Room]&” – “&Title
14. Go into the calendar view and select “Summary” as the Month View Title.
15. Set Week View Title and Day View Title as “Title”.
16. Set Week View Sub Heading and Day View Sub Heading as “Meeting Room”.
17. Create an Event Listener by opening Visual Studio and creating a new class library project.
18. Add a reference to Microsoft.Sharepoint.dll (the dll can be found in Program Files\Common
Files\Microsoft Shared\web server extensions\12\ISAPI on the the server running WSS).
19. Add a new code file and name it PreventDoubleBooking.cs.
20. In PreventDoubleBooking.cs, add the code labeled “PreventDoubleBooking.cs” in the
Appendix.
21. The assembly must now be strongly typed. First, open the command prompt.
22. Execute the command: cd C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin
23. Execute the command: sn –k SPCalEvent.snk
24. Copy and save the .snk file to the PreventDoubleBooking project folder.
25. Add the generated key into the PreventDoubleBooking solution.
26. Modify AssemblyKeyFile and AssemblyVersion in Assembly.Info.cs as follows (take into
account your own directory path names and where you placed the .snk file):
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyKeyFile(@"C:\Documents and Settings\your.username\My
Documents\Visual Studio
2008\Projects\booking\booking\Properties\SPCalEvent.snk")]
27. To sign the assembly, right-click the PreventDoubleBooking class assembly (right below the
Solution inside the Solution Explorer panel) and select “Properties”.
28. Click “Signing” from the menu on the left-hand side.
29. Check “Sign the Assembly” and browse to the location of the .snk file just created and
choose it as the strong name key file.
30. Build the project.
31. Navigate to the obj\Debug folder of the PreventDoubleBooking project and copy the
PreventDoubleBooking.dll file.
32. Paste it into C:\ for easy access.
33. Register the assembly into the GAC by first opening the command prompt.
34. Execute the command: cd C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin
35. Execute the command: gacutil.exe /i C:\PreventDoubleBooking.dll
36. Execute the command: iisreset
37. Run the EventHandlerExplorer.exe file, which is in the same folder as this document.
38. Enter the URL of the SharePoint site for the site collection you want to explore.
39. Once connected, expand the site and navigate to the site location containing the List that
holds the calendar data (it will be whatever you named the calendar).
40. Expand the list.
41. Highlight the list (by single-clicking it).
42. Click “Load Assembly” and locate and select PreventDoubleBooking.dll (in C:\)
43. For the Class, select: Webcoda.WSS.Calendar.Events.PreventDoubleBooking
44. Set Sequence to 0
45. Select “ItemAdding” for the Event Type.
46. Click “Add Handler”
47. Select “ItemUpdating” for the Event Type.
48. Click “Add Handler” again.
49. In the command prompt, execute the command: iisreset
50. The procedure is complete. The calendar should now detect and prevent double booking.
Should you need to “Re-Deploy”:
1. Rebuild the project.
2. Navigate to the obj\Debug folder of the PreventDoubleBooking project and copy the most
recent PreventDoubleBooking.dll file (refresh the folder contents).
3. Paste it into C:\ for easy access.
4. Register the assembly into the GAC by first opening the command prompt.
5. Execute the command: cd C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin
6. Execute the command: gacutil.exe /i C:\PreventDoubleBooking.dll
7. Execute the command: iisreset
8. Run the EventHandlerExplorer.exe file, which is in the same folder as this document.
9. Enter the URL of the SharePoint site for the site collection you want to explore.
10. Once connected, expand the site and navigate to the site location containing the List that
holds the calendar data (it will be whatever you named the calendar).
11. Expand the list.
12. Expand “Event Handlers”
13. Click the “ItemAdding” event handler and click “Remove Handler”
14. Repeat for “ItemUpdating”
15. Highlight the list (by single-clicking it).
16. Click “Load Assembly” and locate and select PreventDoubleBooking.dll (in C:\)
17. For the Class, select: Webcoda.WSS.Calendar.Events.PreventDoubleBooking
18. Set Sequence to 0
19. Select “ItemAdding” for the Event Type.
20. Click “Add Handler”
21. Select “ItemUpdating” for the Event Type.
22. Click “Add Handler” again.
23. In the command prompt, execute the command: iisreset
24. Repeat this process each time you rebuild or wish to redeploy.

CONCLUSION
Now the user can designate a meeting room for an event and select which room they would like
to see the availability for by selecting from the view drop down list in the top right of the
calendar page. Also, double booking is detected and prevented should the user attempt to set
multiple events for the same time and meeting place.

APPENDIX
PreventDoubleBooking.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.SharePoint;

namespace Webcoda.WSS.Calendar.Events
{
class PreventDoubleBooking : SPItemEventReceiver
{
/// <summary>
/// This event is triggered when the user adds a new item
/// </summary>
/// <param name="properties"></param>
public override void ItemAdding(SPItemEventProperties properties)
{
//Our query string variable
string strQuery = null;

try
{
//Get the Sharepoint site instance
using (SPWeb oWebsite = new
SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
{

//Get the collection of properties for the Booking item


SPListItemCollection collItems = oWebsite.Lists[properties.ListTitle].Items;

//Get the Calendar List that we will be querying against


SPList calendar = oWebsite.Lists[properties.ListId];

//Get the internal name of the fields we are querying.


//These are required for the CAML query
string start_internal = collItems.List.Fields["Start Time"].InternalName;
string end_internal = collItems.List.Fields["End Time"].InternalName;
string MeetingRoom_Internal = collItems.List.Fields["Meeting
Room"].InternalName;

//Get the query string parameters


string start_str = properties.AfterProperties[start_internal].ToString();
string end_str = properties.AfterProperties[end_internal].ToString();
string MeetingRoom_str =
properties.AfterProperties[MeetingRoom_Internal].ToString();

//Construct a CAML query


SPQuery query = new SPQuery();

//Create the CAML query string that checks to see if the booking we are
attemping
//to add will overlap any existing bookings
strQuery = string.Format(@"

<Where>

<And>
<Or>

<Or>
<And>
<Leq>
<FieldRef Name='EventDate' />
<Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
</Leq>

<Gt>
<FieldRef Name='EndDate' />
<Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
</Gt>
</And>

<And>
<Lt>
<FieldRef Name='EventDate' />
<Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
</Lt>

<Geq>
<FieldRef Name='EndDate' />
<Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
</Geq>
</And>
</Or>

<Or>
<And>
<Leq>
<FieldRef Name='EventDate' />
<Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
</Leq>

<Geq>
<FieldRef Name='EndDate' />
<Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
</Geq>
</And>

<And>
<Geq>
<FieldRef Name='EventDate' />
<Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
</Geq>

<Leq>
<FieldRef Name='EndDate' />
<Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
</Leq>
</And>
</Or>

</Or>

<Eq>
<FieldRef Name='Meeting_x0020_Room' />
<Value Type='Choice'>{2}</Value>
</Eq>

</And>

</Where>
<OrderBy>
<FieldRef Name='EventDate' />
</OrderBy>
", start_str, end_str, MeetingRoom_str);

//Set the query string for the SPQuery object


query.Query = strQuery;

//Execute the query against the Calendar List


SPListItemCollection existing_events = calendar.GetItems(query);

//Check to see if the query returned any overlapping bookings


if (existing_events.Count > 0)
{
//Cancels the ItemAdd action and redirects to error page
properties.Cancel = true;

//Edit the error message that will display on the error page
properties.ErrorMessage += "This booking cannot be made because of one or
more bookings in conflict. <BR><BR>";

properties.ErrorMessage += "Please go back and schedule a new time.";


}

}
}
catch (Exception ex)
{
//Cancels the ItemAdd action and redirects to error page
properties.Cancel = true;

//Edit the error message that will display on the error page
properties.ErrorMessage = "Error looking for booking conflicts: " + ex.Message;
}

/// <summary>
/// This event is triggered when the user edits an calendar item
/// </summary>
/// <param name="properties"></param>
public override void ItemUpdating(SPItemEventProperties properties)
{

string strQuery = null;

try
{

//Get the Sharepoint site instance


using (SPWeb oWebsite = new
SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
{
//Get the collection of properties for the Booking item
SPListItemCollection collItems = oWebsite.Lists[properties.ListTitle].Items;

//Get the Calendar List that we will be querying against


SPList calendar = oWebsite.Lists[properties.ListId];

//Get the internal name of the fields we are querying.


//These are required for the CAML query
string start_internal = collItems.List.Fields["Start Time"].InternalName;
string end_internal = collItems.List.Fields["End Time"].InternalName;
string MeetingRoom_Internal = collItems.List.Fields["Meeting
Room"].InternalName;
//string guid_internal = collItems.List.Fields["GUID"].InternalName;

//Get the query string parameters


string start_str = properties.AfterProperties[start_internal].ToString();
string end_str = properties.AfterProperties[end_internal].ToString();
string MeetingRoom_str =
properties.AfterProperties[MeetingRoom_Internal].ToString();
string guid_str = properties.ListItem.UniqueId.ToString();
//properties.AfterProperties[guid_internal].ToString();

//Construct a CAML query


SPQuery query = new SPQuery();

//Create the CAML query string that checks to see if the booking we are
attemping
//to change will overlap any existing bookings, OTHER THAN ITSELF
strQuery = string.Format(@"

<Where>
<And>

<Or>

<Or>
<And>
<Leq>
<FieldRef Name='EventDate' />
<Value Type='DateTime'
IncludeTimeValue='TRUE'>{0}</Value>
</Leq>

<Gt>
<FieldRef Name='EndDate' />
<Value Type='DateTime'
IncludeTimeValue='TRUE'>{0}</Value>
</Gt>
</And>

<And>
<Lt>
<FieldRef Name='EventDate' />
<Value Type='DateTime'
IncludeTimeValue='TRUE'>{1}</Value>
</Lt>

<Geq>
<FieldRef Name='EndDate' />
<Value Type='DateTime'
IncludeTimeValue='TRUE'>{1}</Value>
</Geq>
</And>
</Or>

<Or>
<And>
<Leq>
<FieldRef Name='EventDate' />
<Value Type='DateTime'
IncludeTimeValue='TRUE'>{0}</Value>
</Leq>

<Geq>
<FieldRef Name='EndDate' />
<Value Type='DateTime'
IncludeTimeValue='TRUE'>{1}</Value>
</Geq>
</And>

<And>
<Geq>
<FieldRef Name='EventDate' />
<Value Type='DateTime'
IncludeTimeValue='TRUE'>{0}</Value>
</Geq>

<Leq>
<FieldRef Name='EndDate' />
<Value Type='DateTime'
IncludeTimeValue='TRUE'>{1}</Value>
</Leq>
</And>
</Or>

</Or>

<Eq>
<FieldRef Name='Meeting_x0020_Room' />
<Value Type='Choice'>{2}</Value>
</Eq>

</And>

</Where>

<OrderBy>
<FieldRef Name='EventDate' />
</OrderBy>
", start_str, end_str, MeetingRoom_str);

//Set the query string for the SPQuery object


query.Query = strQuery;

//Execute the query against the Calendar List


SPListItemCollection existing_events = calendar.GetItems(query);

int count_results = 0;

//Discount the item being updated from the existing_events.Count


if (existing_events.Count > 0)
foreach (SPListItem oListItem in existing_events)
{
if (oListItem.UniqueId.ToString() != guid_str)
count_results++;
}

//Check to see if the query returned any overlapping bookings


if (count_results > 0)
{

//Cancels the ItemAdd action and redirects to error page


properties.Cancel = true;

//Edit the error message that will display on the error page
properties.ErrorMessage += "This booking cannot be made because of one or
more bookings in conflict. <BR><BR>";

properties.ErrorMessage += "Please go back and schedule a new time.";


}

}
}
catch (Exception ex)
{
//Cancels the ItemAdd action and redirects to error page
properties.Cancel = true;

//Edit the error message that will display on the error page
properties.ErrorMessage = "Error looking for booking conflicts: " + ex.Message;
}

}
}

Вам также может понравиться