This tutorial shows how to use the Month AJAX component from DayPilot Pro package in a simple ASP.NET MVC project.
This tutorial uses a simple SQL Server database, located in App_Data directory (daypilot.mdf).
The database contains a single table with the following structure:
CREATE TABLE [dbo].[event]( [id] [int] IDENTITY(1,1) NOT NULL, [name] [varchar](50), [eventstart] [datetime] NOT NULL, [eventend] [datetime] NOT NULL, CONSTRAINT [PK_event] PRIMARY KEY )
It's necessary to include the following scripts in the web page (the scripts can be found in Scripts/DayPilot directory):
All the scripts are included in the site template (Views/Shared/Site.master).
The DayPilot.Web.Mvc.dll must be placed in the Bin directory of the web applicaton.
The main view (Views/Home/Index.aspx) uses an HTML Helper to generate the client-side code for DayPilot Month:
C#
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> <%@ Import Namespace="DayPilot.Web.Mvc.Enums" %> <%@ Import Namespace="DayPilot.Web.Mvc.Events.Month" %> <asp:Content ID="aboutTitle" ContentPlaceHolderID="TitleContent" runat="server"> Month </asp:Content> <asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server"> <p> <%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig { BackendUrl = ResolveUrl("~/Month/Backend") })%> </p> </asp:Content>
VB.NET
<%@ Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> <%@ Import Namespace="DayPilot.Web.Mvc.Enums" %> <%@ Import Namespace="DayPilot.Web.Mvc.Events.Month" %> <asp:Content ID="aboutTitle" ContentPlaceHolderID="TitleContent" runat="server"> Month </asp:Content> <asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server"> <p> <%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig With { .BackendUrl = ResolveUrl("~/Month/Backend") })%> </p> </asp:Content>
The only required property is BackendUrl which points to a controller that will handle all AJAX requests. Here it points to /Month/Backend. We will create the controller in the next step
The backend controller (MonthController) is located in App_Code/Controllers directory. It defines the Backend action:
C#
[HandleError] public class MonthController : Controller { public ActionResult Backend() { return new Dpm().CallBack(this); } }
VB.NET
<HandleError()>
Public Class MonthController
Inherits Controller
Public Function Backend() As ActionResult
Return New Dpm().CallBack(Me)
End Function
End Class
This Backend action simply passes the control to a newly created class (Dpm) which inherits DayPilotMonth class from DayPilot.Web.Mvc namespace.
The first thing we want to do is to load the events from our database. We will handle an Init event (which is fired after the client-side initialization) by overriding OnInit() method:
C#
public class Dpm : DayPilotMonth
{
protected override void OnInit(InitArgs initArgs)
{
// this select is a really bad example, no where clause
Events = new EventManager(Controller).FilteredData(VisibleStart, VisibleEnd).AsEnumerable();
DataStartField = "eventstart";
DataEndField = "eventend";
DataTextField = "name";
DataIdField = "id";
Update();
}
}
VB.NET
Public Class Dpm Inherits DayPilotMonth Protected Overrides Sub OnInit(ByVal e As DayPilot.Web.Mvc.Events.Month.InitArgs) Dim em = New EventManager(Controller) Events = em.FilteredData(VisibleStart, VisibleEnd).AsEnumerable DataStartField = "eventstart" DataEndField = "eventend" DataTextField = "name" DataIdField = "id" Update() End Sub End Class
Our OnInit method does the following:
1. It loads our data to Events property.
EventManager is a simple class that handles data access (it can be found in App_Code/Data directory).
C#
new EventManager(Controller).FilteredData(VisibleStart, VisibleEnd)
VB.NET
Dim em = New EventManager(Controller) em.FilteredData(VisibleStart, VisibleEnd)
FilteredData() method returns a DataTable. We convert it to Enumerable using AsEnumerable() method and assign the result to Events property (which accepts classes that implement IEnumerable interface):
C#
Events = new EventManager(Controller).FilteredData(VisibleStart, VisibleEnd).AsEnumerable();
VB.NET
Dim em = New EventManager(Controller) Events = em.FilteredData(VisibleStart, VisibleEnd).AsEnumerable
2. It maps the data source columns. DayPilotMonth will use this mapping to load the key event properties from the data source.
DataStartField = "eventstart"; DataEndField = "eventend"; DataTextField = "name"; DataIdField = "id";
3. And finally, it requests an update of the event set on the client side:
Update();
In order to enable event moving using drag & drop AJAX operation, we need to do the following:
1. Enable event moving on the client side by setting EventMoveHandling = EvenMoveHandlingType.CallBack:
C#
<%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig { BackendUrl = ResolveUrl("~/Month/Backend"), EventMoveHandling = EventMoveHandlingType.CallBack, })%>
VB.NET
<%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig With { .BackendUrl = ResolveUrl("~/Month/Backend"), .EventMoveHandling = EventMoveHandlingType.CallBack })%>
2. Handle the EventMove request in the Dpm class:
C#
protected override void OnEventMove(EventMoveArgs e)
{
new EventManager(Controller).EventMove(e.Id, e.NewStart, e.NewEnd);
Events = new EventManager(Controller).FilteredData(VisibleStart, VisibleEnd).AsEnumerable();
DataStartField = "eventstart";
DataEndField = "eventend";
DataTextField = "name";
DataIdField = "id";
Update();
}
VB.NET
Protected Overrides Sub OnEventMove(ByVal e As DayPilot.Web.Mvc.Events.Month.EventMoveArgs) Dim em = New EventManager(Controller) em.EventMove(e.Id, e.NewStart, e.NewEnd) Events = em.FilteredData(VisibleStart, VisibleEnd).AsEnumerable DataStartField = "eventstart" DataEndField = "eventend" DataTextField = "name" DataIdField = "id" Update() End Sub
3. For convenience, we move the Events update to a OnFinish() method, which is called at the end of AJAX request.
Our new OnEventMove method will be very short:
C#
protected override void OnEventMove(EventMoveArgs e) { new EventManager(Controller).EventMove(e.Id, e.NewStart, e.NewEnd); Update(); // this sets CallBackUpdate = CallBackUpdateType.EventsOnly }
VB.NET
Protected Overrides Sub OnEventMove(ByVal e As DayPilot.Web.Mvc.Events.Month.EventMoveArgs) Dim em = New EventManager(Controller) em.EventMove(e.Id, e.NewStart, e.NewEnd) Update() End Sub
OnInit() will be even shorter because we don't do any updates, just send a fresh data set:
C#
protected override void OnInit(InitArgs initArgs) { Update(); }
VB.NET
Protected Overrides Sub OnInit(ByVal e As DayPilot.Web.Mvc.Events.Month.InitArgs) Update() End Sub
In OnFinish(), we check if the update was requested by the event handler and load the events:
C#
protected override void OnFinish() { // only load the data if an update was requested by an Update() call if (UpdateType == CallBackUpdateType.None) { return; } Events = new EventManager(Controller).FilteredData(VisibleStart, VisibleEnd).AsEnumerable(); DataStartField = "eventstart"; DataEndField = "eventend"; DataTextField = "name"; DataIdField = "id"; }
VB.NET
Protected Overrides Sub OnFinish() If UpdateType = CallBackUpdateType.None Then Return End If Dim em = New EventManager(Controller) Events = em.FilteredData(VisibleStart, VisibleEnd).AsEnumerable DataStartField = "eventstart" DataEndField = "eventend" DataTextField = "name" DataIdField = "id" End Sub
Adding AJAX event resizing is easy now:
1. Enable event resizing on the client side by setting EventResizeHandling = EvenResizeHandlingType.CallBack:
C#
<%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig { BackendUrl = ResolveUrl("~/Month/Backend"), EventMoveHandling = EventMoveHandlingType.CallBack, EventResizeHandling = EventResizeHandlingType.CallBack })%>
VB.NET
<%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig With { .BackendUrl = ResolveUrl("~/Month/Backend"), .EventMoveHandling = EventMoveHandlingType.CallBack, .EventResizeHandling = EventResizeHandlingType.CallBack })%>
2. Add a new event handler to Dpm class:
C#
protected override void OnEventResize(EventResizeArgs e) { new EventManager(Controller).EventMove(e.Id, e.NewStart, e.NewEnd); Update(); }
VB.NET
Protected Overrides Sub OnEventResize(ByVal e As DayPilot.Web.Mvc.Events.Month.EventResizeArgs) Dim em = New EventManager(Controller) em.EventMove(e.Id, e.NewStart, e.NewEnd) Update() End Sub
The support for creating a new event using AJAX (selecting a time range) can be added using OnTimeRangeSelected handler. The process is similar:
1. Enable time range selecting on the client side by setting TimeRangeSelectedHandling = TimeRangeSelectedHandlingType.CallBack:
C#
<%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig { BackendUrl = ResolveUrl("~/Month/Backend"), EventMoveHandling = EventMoveHandlingType.CallBack, EventResizeHandling = EventResizeHandlingType.CallBack, TimeRangeSelectedHandling = TimeRangeSelectedHandlingType.CallBack })%>
VB.NET
<%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig With { .BackendUrl = ResolveUrl("~/Month/Backend"), .EventMoveHandling = EventMoveHandlingType.CallBack, .EventResizeHandling = EventResizeHandlingType.CallBack, .TimeRangeSelectedHandling = TimeRangeSelectedHandlingType.CallBack })%>
2. Add a handler to Dpm class:
C#
protected override void OnTimeRangeSelected(TimeRangeSelectedArgs e) { new EventManager(Controller).EventCreate(e.Start, e.End, "Default name"); Update(); }
VB.NET
Protected Overrides Sub OnTimeRangeSelected(ByVal e As TimeRangeSelectedArgs) Dim em = New EventManager(Controller) em.EventCreate(e.Start, e.End, "Default name") Update() End Sub
Note: This simple handler doesn't allow the user to specify the event name. This event will be created right away with a default name.
As the next step, we will add a context menu to events. There will be two menu items:
First, we need to define the context menu using Html.DayPilotMenu() in the view (Views/Home/Index.aspx):
C#
<%= Html.DayPilotMenu("menu", new DayPilotMenuConfig { CssClassPrefix = "menu_", Items = new DayPilot.Web.Mvc.MenuItemCollection { new DayPilot.Web.Mvc.MenuItem { Text = "Open", Action = MenuItemAction.JavaScript, JavaScript = "alert(e.value());"}, new DayPilot.Web.Mvc.MenuItem { Text = "Delete", Action = MenuItemAction.CallBack, Command = "Delete"} } }) %>
VB.NET
<%= Html.DayPilotMenu("menu", new DayPilotMenuConfig With { .CssClassPrefix = "menu_", .Items = New DayPilot.Web.Mvc.MenuItemCollection From { new DayPilot.Web.Mvc.MenuItem With { .Text = "Open", .Action = MenuItemAction.JavaScript, .JavaScript = "alert(e.value());" }, new DayPilot.Web.Mvc.MenuItem With { .Text = "Delete", .Action = MenuItemAction.CallBack, .Command = "Delete" } } }) %>
The context menu block has to be placed above the DayPilotMonth block (otherwise the reference to the menu would be broken).
We will update the DayPilotMonth declaration with a link to the menu (ContextMenu = "menu"):
C#
<%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig { BackendUrl = ResolveUrl("~/Month/Backend"), EventMoveHandling = EventMoveHandlingType.CallBack, EventResizeHandling = EventResizeHandlingType.CallBack, TimeRangeSelectedHandling = TimeRangeSelectedHandlingType.CallBack, ContextMenu = "menu" })%>
VB.NET
<%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig With { .BackendUrl = ResolveUrl("~/Month/Backend"), .EventMoveHandling = EventMoveHandlingType.CallBack, .EventResizeHandling = EventResizeHandlingType.CallBack, .TimeRangeSelectedHandling = TimeRangeSelectedHandlingType.CallBack, .ContextMenu = "menu" })%>
Now we need to handle the "Delete" menu command invoked by the second menu item. We will do this by overriding a OnEventMenuClick method:
C#
protected override void OnEventMenuClick(EventMenuClickArgs e) { switch (e.Command) { case "Delete": new EventManager(Controller).EventDelete(e.Id); Update(); break; } }
VB.NET
Protected Overrides Sub OnEventMenuClick(ByVal e As DayPilot.Web.Mvc.Events.Month.EventMenuClickArgs) If e.Command = "Delete" Then Dim em = New EventManager(Controller) em.EventDelete(e.Id) Update() End If End Sub
All the basic AJAX operations are enabled now. It didn't take more than about 100 lines of code (excluding the data handling EventManager class).
Full source of Views/Home/Index.aspx:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> <%@ Import Namespace="DayPilot.Web.Mvc.Enums" %> <%@ Import Namespace="DayPilot.Web.Mvc.Events.Month" %> <asp:Content ID="aboutTitle" ContentPlaceHolderID="TitleContent" runat="server"> Month </asp:Content> <asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server"> <p> <%= Html.DayPilotMenu("menu", new DayPilotMenuConfig { CssClassPrefix = "menu_", Items = new DayPilot.Web.Mvc.MenuItemCollection { new DayPilot.Web.Mvc.MenuItem { Text = "Open", Action = MenuItemAction.JavaScript, JavaScript = "alert(e.value());"}, new DayPilot.Web.Mvc.MenuItem { Text = "Delete", Action = MenuItemAction.CallBack, Command = "Delete"} } }) %> <%= Html.DayPilotMonth("dpm", new DayPilotMonthConfig { BackendUrl = ResolveUrl("~/Month/Backend"), EventMoveHandling = EventMoveHandlingType.CallBack, EventResizeHandling = EventResizeHandlingType.CallBack, TimeRangeSelectedHandling = TimeRangeSelectedHandlingType.CallBack, ContextMenu = "menu" })%> </p> </asp:Content>
App_Code/Controllers/MonthController.cs:
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Web; using System.Web.Mvc; using DayPilot.Web.Mvc; using DayPilot.Web.Mvc.Enums; using DayPilot.Web.Mvc.Events; using DayPilot.Web.Mvc.Events.Month; namespace MvcApplication1.Controllers { [HandleError] public class MonthController : Controller { public ActionResult Backend() { return new Dpm().CallBack(this); } public class Dpm : DayPilotMonth { protected override void OnTimeRangeSelected(TimeRangeSelectedArgs e) { new EventManager(Controller).EventCreate(e.Start, e.End, "Default name"); Update(); } protected override void OnEventMove(EventMoveArgs e) { new EventManager(Controller).EventMove(e.Id, e.NewStart, e.NewEnd); Update(); } protected override void OnEventMenuClick(EventMenuClickArgs e) { switch (e.Command) { case "Delete": new EventManager(Controller).EventDelete(e.Id); Update(); break; } } protected override void OnEventResize(EventResizeArgs e) { new EventManager(Controller).EventMove(e.Id, e.NewStart, e.NewEnd); Update(); } protected override void OnInit(InitArgs initArgs) { Update(); } protected override void OnFinish() { // only load the data if an update was requested by an Update() call if (UpdateType == CallBackUpdateType.None) { return; } Events = new EventManager(Controller).FilteredData(VisibleStart, VisibleEnd).AsEnumerable(); DataStartField = "eventstart"; DataEndField = "eventend"; DataTextField = "name"; DataIdField = "id"; } } } }