Adding RadScheduleView To A LightSwitch Solution

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 13

Adding RadScheduleView to a LightSwitch Solution

When working with Visual Studio LightSwitch you may encounter a scenario in which you need to add rich and dynamic scheduling capabilities for your end users with a graphical overlay similar to what they would expect from applications like Outlook. This is definitely a case when 3rd party controls can help you to quickly and easily add this functionality to your application all while working with the infrastructure provided by LightSwitch. In this Telerik Hands on Lab, we will be adding RadScheduleView to our LightSwitch application and hooking up the necessary data to enable a rich scheduling experience. Lets dive into Visual Studio LightSwitch and begin!

Step 1 Setting Up Our Visual Studio LightSwitch Solution


1. If you do not already have them installed, grab a trial copy of the Telerik RadControls for Silverlight from http://www.Telerik.com so that you will have the proper assemblies available for this lab. 2. Start a new LightSwitch C# project named RadScheduleViewLightSwitch:

3. You will now see the Start with data screen. For our example, we are going to click on the Create new table option here to add a new table to our project that we can work with using RadChart:

4. Add the following fields to your new table and name it ScheduleViewAppt (* = Required): a. Id Integer * b. Subject String * c. StartDate Date Time * d. EndDate Date Time * e. ApptGuid String *

f. g. h. i. j. k. l. m.

Category String Importance String IsAllDay Boolean Location String RecurrenceRule String TimeMarker String URL String Description String

5. Next up we want to add a Screen based on this type of data. Right click on Screens in Solution Explorer and select Add Screen:

6. Select Editable Grid Screen and leave the default name in place. Now select ScheduleViewAppts from the Screen Data dropdown, at which point your screen should look like the following (and you can click OK):

7. At this point our LightSwitch solution is ready for us to create a new custom control, so we can save everything and prepare for the next section.

Step 2 Adding a RadScheduleView Control to our Solution


1. In Solution Explorer, switch from Logical View to File View:

2. Click on Show All Files to ensure the ClientGenerated project is visible. 3. Add the following Telerik assemblies to both Client and ClientGenerated: a. Telerik.Windows.Controls b. Telerik.Windows.Controls.Input c. Telerik.Windows.Controls.Navigation d. Telerik.Windows.Controls.ScheduleView 4. Add a new Silverlight UserControl to the Client project named RadScheduleViewControl.xaml. 5. Note: If the error The given key was not present in the dictionary pops up, simply click the Reload the designer link in the design window and it will be resolved. 6. Add the Telerik namespace to the control:
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"

7. Add a RadScheduleView instance to the Xaml window and you will instantly see a preview of the control letting you know that you will need an AppointmentsSource:
<telerik:RadScheduleView x:Name="xScheduleView"> </telerik:RadScheduleView>

8. Before we go any further we need to add some views to RadScheduleView. If we proceed to add data and events to work with RadScheduleView and dont add views, appointments will

never show up in the control. Add the following between the RadScheduleView tags to enable Day, Week, and Month views:
<telerik:RadScheduleView.ViewDefinitions> <telerik:DayViewDefinition /> <telerik:WeekViewDefinition /> <telerik:MonthViewDefinition /> </telerik:RadScheduleView.ViewDefinitions>

9. We will also utilize three events to handle changing LightSwitch database appointments into appointments that RadScheduleView can work with. Create the following three events in Xaml to automatically generate the needed event code in the code-behind file:
AppointmentCreated="xScheduleView_AppointmentCreated" AppointmentDeleted="xScheduleView_AppointmentDeleted" AppointmentEdited="xScheduleView_AppointmentEdited"

10. Note There are also corresponding *ing events that allow us to intercept the activity before it has been completed. If you are performing some form of validation logic on the client this is where you would want to hook into. 11. Flip into the code behind. After the class declaration we will need three List<> instances to hold our appointments, categories, and time markers. These are necessary to avoid threading issues that can be associated with this type of approach of working with the LightSwitch data model and custom controls. Here are the three lists to add:
public List<Appointment> _CoreAppointments; public List<ICategory> categories; public List<ITimeMarker> timemarkers;

12. We will also need two using statements to make the above work:
using Telerik.Windows.Controls.ScheduleView; using Telerik.Windows.Controls;

13. Next we want to hook to the xScheduleView Loaded event to initialize our lists. Set the event as follows:
public RadScheduleViewControl() { InitializeComponent(); xScheduleView.Loaded += new RoutedEventHandler(xScheduleView_Loaded); } void xScheduleView_Loaded(object sender, RoutedEventArgs e) { }

14. Well want to accomplish three tasks within the xScheduleView_Loaded event. First we initialize our _CoreAppointments list, then well iterate through both the CategoriesSource and TimeMarkersSource on our xScheduleView to create our list collections. As mentioned previously, this is important to avoid threading issues down the road. When finished, our event should look like the following:
void xScheduleView_Loaded(object sender, RoutedEventArgs e) { _CoreAppointments = new List<Appointment>(); categories = new List<ICategory>(); foreach (ICategory icat in xScheduleView.CategoriesSource) { categories.Add(icat); } timemarkers = new List<ITimeMarker>(); foreach (ITimeMarker marker in xScheduleView.TimeMarkersSource) { timemarkers.Add(marker); } }

15. We are now ready to enable our application to send appointments from LightSwitch to RadScheduleView.

Step 3 Transferring Appointments


1. The most important thing about this section is that we are working to ensure our appointments map between our database and our Appointment class. When working with RadScheduleView, the AppointmentsSource always needs to derive from AppointmentBase, so unless we need a custom appointment type we can safely use the Appointment class for our purposes. 2. Create a public class named GetLSAppointments which takes a List<ScheduleViewAppt> in the constructor:
public void GetLSAppointments(List<ScheduleViewAppt> svAppts) { }

3. In this class we have two purposes convert database appointments into Appointment items and to bind the newly populated _CoreAppointments collection to our xScheduleView.

4. To convert appointments, we will create a quick foreach loop to iterate through the svAppts collection, convert them via a MakeAppointment method, and add them to the foreach (ScheduleViewAppt sva in svAppts) _CoreAppointments list:
{ Appointment appt = MakeAppointment(sva); _CoreAppointments.Add(appt); }

5. MakeAppointment takes in a ScheduleViewAppt (from LightSwitch) and returns a new Appointment. In this method we can easily copy strings and Booleans to the appropriate Appointment parameters, but for Category and TimeMarker well do a quick look through the local collections to find a match. For the Importance, which is an Enum, well do a quick parse to grab the value. Lastly, for the RecurrenceRule, the developers have helped us out with a built-in RecurrencePatternHelper that will both produce RecurrencePatterns for us and turn RecurrencePatterns into new rules. Here is the complete method:
private Appointment MakeAppointment(ScheduleViewAppt sva) { Appointment appt = new Appointment(); appt.Subject = sva.Subject; appt.UniqueId = sva.ApptGuid; appt.Start = sva.StartDate; appt.End = sva.EndDate; appt.Body = sva.Description; appt.IsAllDayEvent = Convert.ToBoolean(sva.IsAllDay); appt.Location = sva.Location; appt.Url = sva.URL; if (sva.Category != null) { appt.Category = categories.Where(x => x.CategoryName == sva.Category).Singl eOrDefault(); } if (sva.Importance != null) { appt.Importance = (Importance)Enum.Parse(typeof(Importance), sva.Importance , true); } if (sva.TimeMarker != null) { appt.TimeMarker = timemarkers.Where(x => x.TimeMarkerName == sva.TimeMarker ).SingleOrDefault(); } if (sva.RecurrenceRule != null) { RecurrencePattern pattern = new RecurrencePattern(); RecurrencePatternHelper.TryParseRecurrencePattern(sva.RecurrenceRule, out p attern); appt.RecurrenceRule = new RecurrenceRule(pattern); } return appt; }

6. The last step is to set our _CoreAppointments collection to the AppointmentsSource of xScheduleView. To work within the threading model we need to do this with the Dispatcher:
Dispatcher.BeginInvoke(() => { xScheduleView.AppointmentsSource = _CoreAppointments; });

7. We can now load appointments into RadScheduleView, but we need to send them to the custom control via LightSwitch. Switch back over to the EditableScheduleViewAppts Screen and be sure to build your project. 8. Switch the Data Grid to a Custom Control:

9. In the Properties window change the name to SVControl and click the Chance link next to the custom control box. We want to select the custom control we just made:

10. Now click the Write Code button in the upper-right:

11. The first thing we need to do is to declare an instance of our control so that we can send appointments to it when they are loaded:
RadScheduleViewControl rsvc;

12. After this we want to utilize the partial method EditableScheduleViewApptsScreen_Created in which well hook up an event to fire off when our ScheduleView wrapper control is available, at which point we set our previously made instance to the available control:
partial void EditableScheduleViewApptsGrid_Created() { var svControl = this.FindControl("SVControl"); svControl.ControlAvailable += new EventHandler<ControlAvailableEventArgs>(s vControl_ControlAvailable); } void svControl_ControlAvailable(object sender, ControlAvailableEventArgs e) { rsvc = e.Control as RadScheduleViewControl; }

13. The last step is to ensure that when our ScheduleViewAppts load we can send them to our control (since weve already hooked up getting them to display). This is accomplished with the ScheduleViewAppts_Loaded event:
partial void ScheduleViewAppts_Loaded(bool succeeded) { if (succeeded) { rsvc.GetLSAppointments(this.ScheduleViewAppts.ToList<ScheduleViewAppt>()); } }

14. Now when the control is loaded, we save an instance that can be utilized when the data is loaded. This allows us to send the collection of appointments to our control for display, manipulation, etc.

Step 4 Adding, Editing, and Deleting Appointments


1. Adding appointments is relatively easy and utilizes very similar code to what we saw already in the MakeAppointment method. Before we do that, however, we need to work with the Screen Dispatcher to add a new appointment and copy details over. 2. One thing to consider in this step we are transferring data back and forth, but the end user creating appointments is what will actually populate the data we are using. So we as the

developers have it easy, were essentially ensuring the data model remains valid and otherwise mapping values. 3. Getting an instance of the Screen we are in involves utilizing the DataContext of our current control and grabbing the related Screen as an IScreenObject. Then we can work with the Screen Details Dispatcher to work within the Screen data:
var objDataContext = (IContentItem)this.DataContext; var Screen = (Microsoft.LightSwitch.Client.IScreenObject)objDataContext.Screen; Screen.Details.Dispatcher.BeginInvoke(() => { });

4. Since were working with the LightSwitch model, we need to utilize the AddNew() method on our ScheduleViewAppts collection to generate a new appointment. Then we can grab the newly created appointment from the user event and run an update method to copy values over:
ScheduleViewAppt sva = (Screen as EditableScheduleViewApptsGrid) .ScheduleViewAppts.AddNew(); Appointment appt = e.CreatedAppointment as Appointment; UpdateAppointment(sva, appt);

5. The update method is pretty simple we save all the values to their respective database fields, however for recurrence we utilize the RecurrencePatternHelper again:
private void UpdateAppointment(ScheduleViewAppt sva, Appointment appt) { sva.Subject = appt.Subject; sva.ApptGuid = appt.UniqueId; sva.StartDate = appt.Start; sva.EndDate = appt.End; sva.Description = appt.Body; sva.IsAllDay = appt.IsAllDayEvent; sva.Location = appt.Location; sva.URL = appt.Url; if (appt.Category != null) { sva.Category = appt.Category.CategoryName; } if (appt.Importance != null) { sva.Importance = appt.Importance.ToString(); } if (appt.TimeMarker != null) { sva.TimeMarker = appt.TimeMarker.TimeMarkerName; } if (appt.RecurrenceRule != null) { sva.RecurrenceRule = RecurrencePatternHelper.RecurrencePatternToString( appt.RecurrenceRule.Pattern); } }

6. Deleting is very similar, except now we grab an appointment based on the unique ID, and if it exists we utilize the Delete() method. The nice thing is that if we dont save the screen, this change gets undone:
private void xScheduleView_AppointmentDeleted(object sender, Telerik.Windows.C ontrols.AppointmentDeletedEventArgs e) { var objDataContext = (IContentItem)this.DataContext; var Screen = (Microsoft.LightSwitch.Client.IScreenObject)objDataContext.Sc reen; Screen.Details.Dispatcher.BeginInvoke(() => { Appointment appt = e.Appointment as Appointment; ScheduleViewAppt sva = (Screen as EditableScheduleViewApptsGrid).Sched uleViewAppts.Where(x => x.ApptGuid == appt.UniqueId).SingleOrDefault(); if (sva != null) { sva.Delete(); } }); }

7. Editing is also very similar. We utilize much of the same code, except now we run the same UpdateAppointment that we utilized while adding (since were basically just persisting local changes to the database record):
private void xScheduleView_AppointmentEdited(object sender, Telerik.Windows.C ontrols.AppointmentEditedEventArgs e) { var objDataContext = (IContentItem)this.DataContext; var Screen = (Microsoft.LightSwitch.Client.IScreenObject)objDataContext.S creen; Screen.Details.Dispatcher.BeginInvoke(() => { Appointment appt = e.Appointment as Appointment; ScheduleViewAppt sva = (Screen as EditableScheduleViewApptsGrid).Sche duleViewAppts.Where(x => x.ApptGuid == appt.UniqueId).SingleOrDefault(); if (sva != null) { UpdateAppointment(sva, appt); } }); }

8. And now RadScheduleView is ready to rock!

Last Step Wrapping Up


Now you can run your project! When you navigate to our new screen youll see an instance of RadScheduleView sitting in your LightSwitch application. Double click on a time slot and select some properties for the fields:

Click OK and youll see it on the screen as well as the * on the Screen tab to show there is new data. Click save, then refresh and youll see your appointment is still there!

Cool, right? Other considerations not covered here are custom appointments, recurrence exceptions, and custom views. These can all be accomplished by utilizing this project as a base so go nuts and try to experiment! If you need any help, just check out the RadScheduleView documentation: http://www.telerik.com/help/silverlight/radscheduleview-overview.html Happy coding!

You might also like