Telerik blogs

If you've been along for the ride so far with this series, you already know that we've hooked a SQL database up to RIA Services using an ADO.Net Entity Data Model and a DomainDataService data context.  If you've missed it, check out the prior two posts (or search RadScheduler for Silverlight learning series in the Telerik Blogs site).  Now that we're here, we have three more events to handle and we've got a fully-functional RadScheduler for Silverlight hooked up to RIA services.

First up, the two easy events- AppointmentAdded and AppointmentDeleted.

AppointmentAdded Event

This event is pretty straightforward and does not require very much explanation.  When it fires, RadScheduler has already created an appointment internally that comes to us in the argument e.Appointment.  Once we have this, we simply turn the appointment into an SqlAppointment (which our data context understands), generate a recurrence string from the recurrence pattern of the appointment (don't gotta worry about exceptions because a new appointment won't have exceptions), and add it to our data context.  You can do this as follows:

    private void xRadScheduler_AppointmentAdded(object sender, Telerik.Windows.Controls.AppointmentAddedEventArgs e)  
    {  
        Appointment app = e.Appointment as Appointment;  
          
        SqlAppointments sq = new SqlAppointments();  
        sq.Start = app.Start;  
        sq.End = app.End;  
        sq.Subject = app.Subject;  
        sq.Body = app.Body;  
        sq.IsAllDayEvent = app.IsAllDayEvent;  
        sq.Location = app.Location;  
        sq.Url = app.Url;  
        sq.UniqueId = new Guid(app.UniqueId);  
        sq.Type = (int)AppointmentType.Regular;  
 
        if (app.RecurrenceRule != null)  
        {  
            sq.RecurrencePattern = RecurrencePatternHelper.RecurrencePatternToString(app.RecurrenceRule.Pattern);  
        }  
          
        var context = DDS.DomainContext as SchedulerContext;  
        context.SqlAppointments.Add(sq);  
        context.SubmitChanges(delegate { RadWindow.Alert("Added!"); }, null);              
    } 

 

AppointmentDeleted Event

Again, it is pretty wasy to figure out what is happening on this one.  RadScheduler has already deleted the appointment internally, so all we need to do is to let the context know which appointment we are deleting.  Since all recurrence exception info is stored in our appointments we don't need any complex operations, so this next part is pretty self-explanatory:

    private void xRadScheduler_AppointmentDeleted(object sender, Telerik.Windows.Controls.AppointmentDeletedEventArgs e)  
    {  
        // Grab our SchedulerContext and our appointment that was deleted  
        var context = DDS.DomainContext as SchedulerContext;  
        Appointment anApp = e.Appointment as Appointment;  
 
        // We want to remove the appointment from the context based on UniqueID  
        context.SqlAppointments.Remove(context.SqlAppointments.Single(x => x.UniqueId == new Guid(anApp.UniqueId)));  
        context.SubmitChanges(delegate { RadWindow.Alert("Removed!"); }, anApp);  
    }  
 

 

AppointmentEdited Event

Now we get to the fun stuff. :)

When editing an appointment, there is one big question that needs to be asked- does this in any way, shape, or form involve either Recurrence or Recurrence Exceptions?  If the answer is no, then editing an appointment is pretty easy as it looks a lot like creating one.  That would involve grabbing the appointment from the context via the UniqueID of the appointment we edited, making our changes, and doing the all-too-familiar context.SubmitChanges() operation. 

But what if there is an ExceptionOccurrence?  Then we need to check it by one of four states:

  • ExceptionAction.Add - We add an exception to a recurring appointment
  • ExceptionAction.Delete - We remove an exception from a recurring appointment
  • ExceptionAction.Edit - We edit an exception that already exists
  • ExceptionAction.None - We've reset the recurrence rule so exceptions need to go the way of Betamax

Looking at the examples from the links I provided in part 1, you can see these can be somewhat of complex operations when you have related tables.  But since I wanted this at some point to be cloud-ready, storing serialized exceptions in a field of our appointment allows us to use RecurrenceExceptionHelper to come to the rescue.  When adding, deleting, or editing an exception, since we are in the Edited event, the new Exceptions list is already updated, so all we need to do is serialize that and set it to the ExceptionAppointments string.  If ExceptionAction.None, we've changed the recurrence rule, which wipes exceptions, so all we need to do is reset that string.  Here is the full Edited event:

    private void xRadScheduler_AppointmentEdited(object sender, Telerik.Windows.Controls.AppointmentEditedEventArgs e)  
    {  
        var context = DDS.DomainContext as SchedulerContext;  
 
        // this is the appointment being edited, whether it is a base appt or a part of a series  
        Appointment editedAppt = e.Appointment as Appointment;  
         
        // If there is no exception going on, we're just updating the appointment that we are working with  
        if (e.ExceptionOccurrence == null)  
        {  
            SqlAppointments sqlApptToEdit = context.SqlAppointments.Single(x => x.UniqueId == new Guid(editedAppt.UniqueId));  
 
            sqlApptToEdit.Start = editedAppt.Start;  
            sqlApptToEdit.End = editedAppt.End;  
            sqlApptToEdit.Subject = editedAppt.Subject;  
            sqlApptToEdit.Body = editedAppt.Body;  
            sqlApptToEdit.Location = editedAppt.Location;  
            sqlApptToEdit.IsAllDayEvent = editedAppt.IsAllDayEvent;  
            sqlApptToEdit.Url = editedAppt.Url;  
 
            if (editedAppt.RecurrenceRule != null)  
            {  
                sqlApptToEdit.RecurrencePattern = RecurrencePatternHelper.RecurrencePatternToString(editedAppt.RecurrenceRule.Pattern);  
            }  
        }  
        else  
        {  
            Appointment masterAppt = e.ExceptionOccurrence.Master as Appointment;  
 
            SqlAppointments sqlApptToEdit = context.SqlAppointments.Single(x => x.UniqueId == new Guid(masterAppt.UniqueId));  
 
            sqlApptToEdit.Start = masterAppt.Start;  
            sqlApptToEdit.End = masterAppt.End;  
            sqlApptToEdit.Subject = masterAppt.Subject;  
            sqlApptToEdit.Body = masterAppt.Body;  
            sqlApptToEdit.Location = masterAppt.Location;  
            sqlApptToEdit.IsAllDayEvent = masterAppt.IsAllDayEvent;  
            sqlApptToEdit.Url = masterAppt.Url;  
 
            if (editedAppt.RecurrenceRule != null)  
            {  
                sqlApptToEdit.RecurrencePattern = RecurrencePatternHelper.RecurrencePatternToString(masterAppt.RecurrenceRule.Pattern);  
            }  
 
            switch (e.ExceptionAction)  
            {  
                case ExceptionAction.Add:  
                case ExceptionAction.Delete:  
                case ExceptionAction.Edit:  
                    {  
                        // Adding, deleting, and editing an exception are the same thing as far as   
                        //  RecurrenceExceptionHelper is concerned, since we are changing the exception set,  
                        //  all we need to do is update the serialized string and we're good to go!  
 
                        sqlApptToEdit.ExceptionAppointments = ExceptionHelper.MakeExceptionsString(masterAppt.RecurrenceRule.Exceptions.ToList<ExceptionOccurrence>());  
 
                        break;  
                    }  
                case ExceptionAction.None:  
                    {  
                        // We're deleting or resetting the recurrence rule, so we need to reset the exceptions  
                        //  *** This mimics the behavior of RadScheduler  
                        sqlApptToEdit.ExceptionAppointments = "";  
                          
                        break;  
                    }  
            }  
        }  
 
        context.SubmitChanges(delegate { RadWindow.Alert("Updated!"); }, null);  
    } 

 

In a future iteration I'm going to refactor out the conversion from Appointment to SqlAppointment, so this will be even shorter in a later installment.

And there you have it!  But since I've teased enough with this, you can download the full project I've been working with from here:

Silverlight RadScheduler RIA App Part 3

In the next installment I'll give a brief overview of this magic RecurrenceExceptionHelper class that makes saving and editing appointments easy as pie.  Beyond that, we're going to explore customizing our appointment editing window, modifying appointment appearance based on different resources in the appointment, and showing you just how to take advantage of the Location, URL, Developer, and ProductLine fields in our database.

'Til next time... happy coding!


About the Author

Evan Hutnick

works as a Developer Evangelist for Telerik specializing in Silverlight and WPF in addition to being a Microsoft MVP for Silverlight. After years as a development enthusiast in .Net technologies, he has been able to excel in XAML development helping to provide samples and expertise in these cutting edge technologies. You can find him on Twitter @EvanHutnick.

Comments

Comments are disabled in preview mode.