Hi,
I have the scheduler largely working as it should - inserting and updating are working fine as is deleting stand-alone appointments and recurring series. The problem is when I try to delete an Exception - I get the error: "Cannot locate the parent of appointment with ID = 'x'. Ensure that the parent appointment with ID = 'x' exists and is loaded." I've performed a watch on the Scheduler control at the moment this error is being caught and can see the parent appointment with the right ID exists (It's a string datatype though - could this be the problem?).
So far as I can tell I'm doing everything by the book - saving on AppointmentInsert and AppointmentUpdate, deleting on AppointmentDelete. The error is being thrown after Page_Load (where I bind the scheduler control if it's not postback) but before it reaches the AppointmentDelete event handler. The code is attached.
I know that you can't see how the deletes, updates and inserts are actually being implemented because I haven't included the lower layers dealing with the business logic and data access but they are all working as they're supposed to.
Any help will be greatly appreciated. Thanks.
I have the scheduler largely working as it should - inserting and updating are working fine as is deleting stand-alone appointments and recurring series. The problem is when I try to delete an Exception - I get the error: "Cannot locate the parent of appointment with ID = 'x'. Ensure that the parent appointment with ID = 'x' exists and is loaded." I've performed a watch on the Scheduler control at the moment this error is being caught and can see the parent appointment with the right ID exists (It's a string datatype though - could this be the problem?).
So far as I can tell I'm doing everything by the book - saving on AppointmentInsert and AppointmentUpdate, deleting on AppointmentDelete. The error is being thrown after Page_Load (where I bind the scheduler control if it's not postback) but before it reaches the AppointmentDelete event handler. The code is attached.
| <asp:ScriptManager ID="scmEvents" runat="server" OnAsyncPostBackError="scmEvents_AsyncPostBackError" /> | |
| <telerik:RadAjaxManager ID="ramEvents" runat="server"> | |
| <AjaxSettings> | |
| <telerik:AjaxSetting AjaxControlID="rscEvents"> | |
| <UpdatedControls> | |
| <telerik:AjaxUpdatedControl ControlID="rscEvents" LoadingPanelID="ralEvents" /> | |
| </UpdatedControls> | |
| </telerik:AjaxSetting> | |
| </AjaxSettings> | |
| </telerik:RadAjaxManager> | |
| <telerik:RadAjaxLoadingPanel ID="ralEvents" runat="server" Transparency="10" BackColor="#E0E0E0" InitialDelayTime="500"> | |
| <asp:Image ID="imgLoading" runat="server" style="margin-top: 200px;" ImageUrl="" BorderWidth="0px" AlternateText="Loading..." /> | |
| </telerik:RadAjaxLoadingPanel> | |
| <telerik:RadScheduler ID="rscEvents" runat="server" Width="750px" Height="561px" style="margin: 0 auto;" Skin="Office2007" SelectedView="MonthView" ShowViewTabs="False" | |
| OnAppointmentInsert="rscEvents_AppointmentInsert" OnAppointmentUpdate="rscEvents_AppointmentUpdate" OnAppointmentDelete="rscEvents_AppointmentDelete" OnAppointmentDataBound="rscEvents_AppointmentDataBound" | |
| DataKeyField="EventId" DataSubjectField="EventName" DataStartField="StartDate" DataEndField="EndDate" DataRecurrenceField="RecurrenceRule" | |
| DataRecurrenceParentKeyField="RecurrenceParentId" StartInsertingInAdvancedForm="True" StartEditingInAdvancedForm="True" DisplayRecurrenceActionDialogOnMove="True" EnableResourceEditing="False"> | |
| <TimelineView UserSelectable="False" /> | |
| </telerik:RadScheduler> |
| /// <summary> | |
| /// I'm using a form of the MVP pattern which is why all of the event handlers look the way they do. | |
| /// </summary> | |
| public partial class Events : BasePage, IEventsView | |
| { | |
| #region Fields | |
| private EventsPresenter presenter; | |
| private int eventId = -1; | |
| private string eventName = String.Empty; | |
| private string eventDescription = String.Empty; | |
| private DateTime startDate = DateTime.MinValue; | |
| private DateTime endDate = DateTime.MinValue; | |
| private string recurrenceRule = String.Empty; | |
| private string recurrenceParentId = String.Empty; | |
| #endregion | |
| #region Constructor | |
| /// <summary> | |
| /// Initializes a new instance of the <see cref="Events"/> class. | |
| /// </summary> | |
| public Events() | |
| { | |
| presenter = new EventsPresenter( this, new EventsDataService(), DefaultInjection.GetDefault() ); | |
| presenter.Init(); | |
| } | |
| #endregion | |
| #region Events | |
| /// <summary> | |
| /// Occurs when the form is loaded | |
| /// </summary> | |
| public event EventHandler FormLoad; | |
| /// <summary> | |
| /// Occurs when an appointment is inserted. | |
| /// </summary> | |
| public event EventHandler AppointmentInsert; | |
| /// <summary> | |
| /// Occurs when an appointment is updated. | |
| /// </summary> | |
| public event EventHandler AppointmentUpdate; | |
| /// <summary> | |
| /// Occurs when an appointment is deleted. | |
| /// </summary> | |
| public event EventHandler AppointmentDelete; | |
| #endregion | |
| #region Event Handlers | |
| protected void Page_Load( object sender, EventArgs e ) | |
| { | |
| if ( !IsPostBack ) | |
| { | |
| if ( FormLoad != null ) | |
| { | |
| FormLoad( sender, e ); | |
| } | |
| } | |
| } | |
| protected void rscEvents_AppointmentInsert( object sender, SchedulerCancelEventArgs e ) | |
| { | |
| SetAppointmentDetails( e.Appointment ); | |
| if ( AppointmentInsert != null ) | |
| { | |
| AppointmentInsert( sender, e ); | |
| } | |
| } | |
| protected void rscEvents_AppointmentUpdate( object sender, AppointmentUpdateEventArgs e ) | |
| { | |
| SetAppointmentDetails( e.ModifiedAppointment ); | |
| if ( AppointmentUpdate != null ) | |
| { | |
| AppointmentUpdate( sender, e ); | |
| } | |
| } | |
| /// <summary> | |
| /// The startDate is used to calculate the beginning date of the schedule | |
| /// </summary> | |
| protected void rscEvents_AppointmentDelete( object sender, SchedulerCancelEventArgs e ) | |
| { | |
| eventId = Int32.Parse( e.Appointment.ID.ToString() ); | |
| startDate = e.Appointment.Start; | |
| if ( AppointmentDelete != null ) | |
| { | |
| AppointmentDelete( sender, e ); | |
| } | |
| } | |
| protected void rscEvents_AppointmentDataBound( object sender, SchedulerEventArgs e ) | |
| { | |
| e.Appointment.ToolTip = e.Appointment.Subject; | |
| } | |
| /// <summary> | |
| /// Captures assynchronous exceptions and handles them in the same way as normal exceptions. | |
| /// </summary> | |
| protected void scmEvents_AsyncPostBackError( object sender, AsyncPostBackErrorEventArgs e ) | |
| { | |
| throw e.Exception; | |
| } | |
| #endregion | |
| #region Properties | |
| /// <summary> | |
| /// This property is set by the Presenter when binding the scheduler control. | |
| /// </summary> | |
| public List<EventDTO> CurrentEvents | |
| { | |
| set | |
| { | |
| List<AppointmentDTO> appointments = new List<AppointmentDTO>(); | |
| foreach ( EventDTO evnt in value ) | |
| { | |
| appointments.Add( new AppointmentDTO( evnt ) ); | |
| } | |
| rscEvents.DataSource = appointments; | |
| rscEvents.DataBind(); | |
| } | |
| } | |
| public int EventId | |
| { | |
| get { return eventId; } | |
| } | |
| public string EventName | |
| { | |
| get { return eventName; } | |
| } | |
| public string EventDescription | |
| { | |
| get { return eventDescription; } | |
| } | |
| public DateTime StartDate | |
| { | |
| get { return startDate; } | |
| } | |
| public DateTime EndDate | |
| { | |
| get { return endDate; } | |
| } | |
| public string RecurrenceRule | |
| { | |
| get { return recurrenceRule; } | |
| } | |
| public string ReccurenceParentId | |
| { | |
| get { return recurrenceParentId; } | |
| } | |
| #endregion | |
| /// <summary> | |
| /// The fields being set in this method are used by the Presenter when saving appointments to the database. | |
| /// </summary> | |
| private void SetAppointmentDetails( Appointment appointment ) | |
| { | |
| eventId = appointment.ID != null ? Int32.Parse( appointment.ID.ToString() ) : -1; | |
| eventName = appointment.Subject; | |
| startDate = appointment.Start; | |
| endDate = appointment.End; | |
| recurrenceRule = appointment.RecurrenceRule; | |
| if ( appointment.RecurrenceParentID != null && !String.IsNullOrEmpty( appointment.RecurrenceParentID.ToString() ) ) | |
| { | |
| recurrenceParentId = appointment.RecurrenceParentID.ToString(); | |
| } | |
| } | |
| #region Classes | |
| /// <summary> | |
| /// Extends the base EventDTO to accomodate functionality in the Telerik Scheduler control by incorporating the RecurrenceState property and | |
| /// making RecurrenceRule and RecurrenceParentId nullable. | |
| /// </summary> | |
| private class AppointmentDTO : EventDTO | |
| { | |
| #region Fields | |
| private RecurrenceState recurrenceState; | |
| #endregion | |
| #region Constructors | |
| private AppointmentDTO() | |
| { | |
| eventId = -1; | |
| } | |
| public AppointmentDTO( int eventId, string eventName, string eventDescription, DateTime startDate, DateTime endDate, string recurrenceRule, string recurrenceParentId ) : this() | |
| { | |
| this.eventId = eventId; | |
| this.eventName = eventName; | |
| this.eventDescription = eventDescription; | |
| this.startDate = startDate; | |
| this.endDate = endDate; | |
| this.recurrenceRule = String.IsNullOrEmpty( recurrenceRule ) ? null : recurrenceRule; | |
| this.recurrenceParentId = String.IsNullOrEmpty( recurrenceParentId ) ? null : recurrenceParentId; | |
| if ( recurrenceParentId != null ) | |
| { | |
| recurrenceState = RecurrenceState.Exception; | |
| } | |
| else if ( !String.IsNullOrEmpty( recurrenceRule ) ) | |
| { | |
| recurrenceState = RecurrenceState.Occurence; | |
| } | |
| } | |
| public AppointmentDTO( EventDTO evnt ) : this( evnt.EventId, evnt.EventName, evnt.EventDescription, evnt.StartDate, evnt.EndDate, evnt.RecurrenceRule, evnt.RecurrenceParentId ) { } | |
| #endregion | |
| #region Properties | |
| /// <summary> | |
| /// This is being setup as per the Binding Generic List demo but it never gets consumed - something I'm missing here??? | |
| /// </summary> | |
| public RecurrenceState RecurrenceState | |
| { | |
| get { return recurrenceState; } | |
| set { recurrenceState = value; } | |
| } | |
| #endregion | |
| } | |
| #endregion | |
| } |
I know that you can't see how the deletes, updates and inserts are actually being implemented because I haven't included the lower layers dealing with the business logic and data access but they are all working as they're supposed to.
Any help will be greatly appreciated. Thanks.