Monday, June 20, 2011

RadScheduler Resource Limitation

In this article, I will attempt to describe how to limit the availability of a resource to only be scheduled once per time slot in Telerik’s RadScheduler using very lameman’s terms.  This means that if you have a resource (like a room, car, light bulb… whatever) it will only allow you to schedule the use of the resource once per time slot per day.  However, if you have additional resources, you can schedule one of those additional resources in the same time/date slot.

The Gist:

You have 4 meeting rooms that are available as resources.  North, South, East, and West.  In order to have a meeting you need to schedule a time slot to use the room.  You decide on North.  However, a coworker has already scheduled this room for the time slot and date that you wished to use the room.  In this case, you will receive a notification alerting you to this fact and no data will be saved in the database. 

The Scheduler:

In this scenario, our hypothetical RadScheduler will look like:

<telerik:RadScheduler ID="rsRoomScheduler" runat="server" 
DataEndField="End" DataKeyField="ID" DataRecurrenceField="RecurrenceRule" 
DataRecurrenceParentKeyField="RecurrenceParentID" DataSourceID="sdsAppointment" 
DataStartField="Start" DataSubjectField="Subject" Height="600px" 
Width="640px" StartInsertingInAdvancedForm="True" Skin="Telerik" EnableRecurrenceSupport="true"
DayStartTime="07:00:00" OnAppointmentInsert="rsRoomScheduler_AppointmentInsert"
OnAppointmentUpdate="rsRoomScheduler_AppointmentUpdate" AdvancedForm-MaximumHeight="640px"  
OnAppointmentCancelingEdit="rsRoomScheduler_AppointmentCancelingEdit" OverflowBehavior="Expand" >                
<AdvancedForm Modal="true" MaximumHeight="400px" />
<%# Eval("Subject") %>
<div style="text-align: right;">
<span style="cursor: pointer; cursor: hand;">
<asp:ImageButton runat="server" ID="Button1" ImageUrl="~/images/Outlook.gif" AlternateText="Export to iCalendar"
CommandName="Export" />

<telerik:ResourceType DataSourceID="sdsRooms" KeyField="ID" 
Name="Room" TextField="RoomName" ForeignKeyField="RoomID" />


This sets up our Scheduler.  It gives our Appointment Template and Resource Types.  Use of the Smart Tags is usually the most convenient way to set this up for the novice user.  Whether you are using a SQLDataSource or performing the Data Layer through the backend is irrelevant in this scenario and will not be included as to not confuse the reader.

The Code Behind:

The event trigger from the Scheduler that we will use will be the Appointment Insert trigger.  This event is fired immediately before the write/update to the data layer (or database – whichever is the case).  It is triggered after validation. 

Our code will call a custom Function that will check to ensure that the resource only exists once and Return a Boolean value based on this check (Not initialized, True if it exists, False if it does not exist).
Protected Function ExceedsLimit(ByVal apt As Appointment) As Boolean
'Dim appointmentsCount As Integer = rsRoomScheduler.Appointments.GetAppointmentsInRange(apt.Start, apt.End).Count
For Each existingApt As Appointment In rsRoomScheduler.Appointments.GetAppointmentsInRange(apt.Start, apt.End)
For Each existingRes As Resource In existingApt.Resources
If Not ((apt.Resources.GetResource(existingRes.Type, existingRes.Key)) Is Nothing) Then
Return True
End If
'Return (appointmentsCount > (AppointmentsLimit - 1))
Return False
End Function
Protected Sub rsRoomScheduler_AppointmentInsert(ByVal sender As Object, ByVal e As Telerik.Web.UI.SchedulerCancelEventArgs)
If ExceedsLimit(e.Appointment) Then
Label1.Text = "This room has already been scheduled for this time slot."
e.Cancel = True

'ScriptManager.RegisterClientScriptBlock(Me, GetType(Page), "LabelUpdated", "$telerik.$('.lblError').show().animate({ opacity: 0.9 }, 2000).fadeOut('slow');", True)
End If
End Sub

We start with entry into the Trigger Appointment Insert.  Follow through the IF statement that calls ExceedsLimit with a reference to Telerik.Web.UI.Appointment.  This is our entry point to the ExceedsLimit function.  We will enter the For Each Loop by declaring existingApt As Appointment.  At this point we already have the appointments already scheduled through the DataSet that has been binded to the DataGrid, so we look in there and get all the appointments in the same time/date range.  We enter another For Each Loop to check and see if the resources are the same (by key).  If they are, then processing stops and we return true to the calling Sub Appointment Insert.  This gives us our ability to alert the user and then cancel the request.  If it does not match, we will then check the next appointment (dataRow in the set) until we have exhausted all appointments or make a match.

It’s important to note that you must import Telerik.Web.UI in order to get a handle on the Appointment, like so:
Imports Telerik.Web.UI

Who knew two little functions could be so much fun?

Blogger Labels: RadScheduler,Resource,Telerik,database,Scheduler,server,DataEndField,DataKeyField,DataRecurrenceField,RecurrenceRule,DataRecurrenceParentKeyField,RecurrenceParentID,DataSourceID,DataStartField,Start,DataSubjectField,Width,StartInsertingInAdvancedForm,True,Skin,EnableRecurrenceSupport,DayStartTime,OnAppointmentInsert,OnAppointmentUpdate,AdvancedForm,OnAppointmentCancelingEdit,OverflowBehavior,Expand,Modal,AppointmentTemplate,Eval,text,cursor,pointer,ImageButton,ImageUrl,images,Outlook,AlternateText,Export,CommandName,ResourceTypes,ResourceType,KeyField,Name,TextField,RoomName,ForeignKeyField,RoomID,Appointment,Template,Smart,novice,user,Whether,SQLDataSource,Layer,reader,Code,Behind,event,Insert,validation,custom,Function,Return,Boolean,False,ExceedsLimit,Integer,Appointments,GetAppointmentsInRange,Count,Resources,GetResource,Type,AppointmentsLimit,sender,Object,SchedulerCancelEventArgs,Cancel,ScriptManager,RegisterClientScriptBlock,GetType,Page,font,size,Courier,background,margin,Trigger,statement,reference,Loop,DataSet,DataGrid,rsRoomScheduler,runat,rsRoomScheduler_AppointmentInsert,appointmentsCount,existingApt,existingRes,

No comments:

Post a Comment