Features
ASP.NET Gantt Control
Customizable scale - we are displaying one cell per day
Customizable time header - we are displaying days grouped by month
Adding a new task using a modal dialog
Editing a task using a modal dialog
PNG Export
PDF Export
Customizable PDF page format (Letter, A4)
Customizable PDF page orientation (portrait, landscape)
License
Licensed for testing and evaluation purposes. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for ASP.NET WebForms.
Gantt ASP.NET Control
We will create the Gantt chart using DayPilot ASP.NET scheduler control. Add the DayPilotScheduler control to the web page.
Switch to the Gantt chart mode using ViewType="Gantt". The Gantt mode will display one task per row. The rows will be generated from the supplied event set automatically.
Set the scale (cell duration) using Scale="Day".
Define the time headers using TimeHeaders. We will display months in the first row and days (as defined using Scale property) in the second header row.
Define the row header columns using HeaderColumns. We will use the columns to display additional data about the Gantt tasks (such as duration).
<DayPilot:DayPilotScheduler
runat="server"
ID="GanttControl"
ViewType="Gantt"
Scale="Day"
>
<TimeHeaders>
<DayPilot:TimeHeader GroupBy="Month" Format="MMMM yyyy" />
<DayPilot:TimeHeader GroupBy="Cell" />
</TimeHeaders>
<HeaderColumns>
<DayPilot:RowHeaderColumn Title="Task" Width="120" />
<DayPilot:RowHeaderColumn Title="Duration" Width="90" />
</HeaderColumns>
</DayPilot:DayPilotScheduler>
Loading the Gantt Tasks
Load the event/task data to the Gantt control. You can load events from any data sources like List, DataTable, SqlDataSource, etc.. We will use a simple DataTable returned by GetData() method.
C#
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
SetDataSourceAndBind();
}
}
private void SetDataSourceAndBind()
{
GanttControl.DataSource = GetData(GanttControl.StartDate, GanttControl.EndDate);
GanttControl.DataStartField = "eventstart";
GanttControl.DataEndField = "eventend";
GanttControl.DataIdField = "id";
GanttControl.DataTextField = "name";
GanttControl.DataBind();
}
private DataTable GetData(DateTime start, DateTime end)
{
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM [event] WHERE NOT (([eventend] <= @start) OR ([eventstart] >= @end))", ConfigurationManager.ConnectionStrings["daypilot"].ConnectionString);
da.SelectCommand.Parameters.AddWithValue("start", start);
da.SelectCommand.Parameters.AddWithValue("end", end);
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If Not IsPostBack Then
SetDataSourceAndBind()
End If
End Sub
Private Sub SetDataSourceAndBind()
GanttControl.DataSource = GetData(GanttControl.StartDate, GanttControl.EndDate)
GanttControl.DataStartField = "eventstart"
GanttControl.DataEndField = "eventend"
GanttControl.DataIdField = "id"
GanttControl.DataTextField = "name"
GanttControl.DataBind()
End Sub
Private Function GetData(ByVal start As Date, ByVal [end] As Date) As DataTable
Dim da As New SqlDataAdapter("SELECT * FROM [event] WHERE NOT (([eventend] <= @start) OR ([eventstart] >= @end))", ConfigurationManager.ConnectionStrings("daypilot").ConnectionString)
da.SelectCommand.Parameters.AddWithValue("start", start)
da.SelectCommand.Parameters.AddWithValue("end", [end])
Dim dt As New DataTable()
da.Fill(dt)
Return dt
End Function
SQL Server Database Schema for the Gantt Data
Our sample uses a very simple database structure. All Gantt chart data are stored in a single database table called [event] with four fields:
[id]
[name]
[eventstart]
[eventend]
The SQL schema is as follows:
CREATE TABLE [dbo].[event] (
[id] INT IDENTITY (1, 1) NOT NULL,
[name] VARCHAR (50) NULL,
[eventstart] DATETIME NOT NULL,
[eventend] DATETIME NOT NULL,
CONSTRAINT [PK_event] PRIMARY KEY CLUSTERED ([id] ASC)
);
You can use your existing database schema and map the data set fields using Data*Field properties.
C#
private void SetDataSourceAndBind()
{
GanttControl.DataSource = GetData(GanttControl.StartDate, GanttControl.EndDate);
GanttControl.DataStartField = "eventstart";
GanttControl.DataEndField = "eventend";
GanttControl.DataIdField = "id";
GanttControl.DataTextField = "name";
GanttControl.DataBind();
}
VB
Private Sub SetDataSourceAndBind()
GanttControl.DataSource = GetData(GanttControl.StartDate, GanttControl.EndDate)
GanttControl.DataStartField = "eventstart"
GanttControl.DataEndField = "eventend"
GanttControl.DataIdField = "id"
GanttControl.DataTextField = "name"
GanttControl.DataBind()
End Sub
Visible Date Range
You can define the visible range using StartDate and Days properties.
We are displaying the current month.
C#
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GanttControl.StartDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
GanttControl.Days = DateTime.DaysInMonth(DateTime.Today.Year, DateTime.Today.Month);
SetDataSourceAndBind();
}
}
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If Not IsPostBack Then
GanttControl.StartDate = New Date(Date.Today.Year, Date.Today.Month, 1)
GanttControl.Days = Date.DaysInMonth(Date.Today.Year, Date.Today.Month)
SetDataSourceAndBind()
End If
End Sub
Adding Tasks to the Gantt Chart
We will use a modal dialog to display a new task dialog.
<a href="javascript:add()" id="add">Add Task...</a>
<script type="text/javascript">
function add() {
var start = new DayPilot.Date().getDatePart();
var end = start.addDays(1);
modal().showUrl('New.aspx?start=' + start + '&end=' + end);
}
function modal() {
var m = new DayPilot.Modal();
m.closed = function () {
var data = this.result;
console.log(data);
if (data == "OK") {
GanttControl.commandCallBack("refresh");
}
};
return m;
}
</script>
It is a standalone page (New.aspx). It creates a new record in the database and updates the main page using the client side .closed callback.
C#
protected void ButtonOK_Click(object sender, EventArgs e)
{
DateTime start = Convert.ToDateTime(TextBoxStart.Text);
DateTime end = Convert.ToDateTime(TextBoxEnd.Text);
DbInsertEvent(start, end, TextBoxName.Text);
Modal.Close(this, "OK");
}
private void DbInsertEvent(DateTime start, DateTime end, string name)
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["daypilot"].ConnectionString))
{
con.Open();
SqlCommand cmd = new SqlCommand("INSERT INTO [event] (eventstart, eventend, name) VALUES(@start, @end, @name)", con);
cmd.Parameters.AddWithValue("start", start);
cmd.Parameters.AddWithValue("end", end);
cmd.Parameters.AddWithValue("name", name);
cmd.ExecuteNonQuery();
}
}
VB
Protected Sub ButtonOK_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim start As Date = Convert.ToDateTime(TextBoxStart.Text)
Dim [end] As Date = Convert.ToDateTime(TextBoxEnd.Text)
DbInsertEvent(start, [end], TextBoxName.Text)
Modal.Close(Me, "OK")
End Sub
Private Sub DbInsertEvent(ByVal start As Date, ByVal [end] As Date, ByVal name As String)
Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("daypilot").ConnectionString)
con.Open()
Dim cmd As New SqlCommand("INSERT INTO [event] (eventstart, eventend, name) VALUES(@start, @end, @name)", con)
cmd.Parameters.AddWithValue("start", start)
cmd.Parameters.AddWithValue("end", [end])
cmd.Parameters.AddWithValue("name", name)
cmd.ExecuteNonQuery()
End Using
End Sub
Drag and Drop Task Moving
You can enable drag and drop task moving using EventMoveHandling property.
ASPX
<DayPilot:DayPilotScheduler
runat="server"
ID="GanttControl"
ViewType="Gantt"
...
EventMoveHandling="Notify"
OnEventMove="GanttControl_EventMove"
...
/>
The Gantt control will fire GanttControl_EventMove event handler when the moving is finished.
C#
protected void GanttControl_EventMove(object sender, EventMoveEventArgs e)
{
DbUpdateEvent(e.Value, e.NewStart, e.NewEnd, e.Text);
}
private void DbUpdateEvent(string id, DateTime start, DateTime end, string name)
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["daypilot"].ConnectionString))
{
con.Open();
SqlCommand cmd = new SqlCommand("UPDATE [event] SET eventstart = @start, eventend = @end, name = @name WHERE id = @id", con);
cmd.Parameters.AddWithValue("id", id);
cmd.Parameters.AddWithValue("start", start);
cmd.Parameters.AddWithValue("end", end);
cmd.Parameters.AddWithValue("name", name);
cmd.ExecuteNonQuery();
}
}
VB
Protected Sub GanttControl_EventMove(ByVal sender As Object, ByVal e As EventMoveEventArgs)
DbUpdateEvent(e.Value, e.NewStart, e.NewEnd, e.Text)
End Sub
Private Sub DbUpdateEvent(ByVal id As String, ByVal start As Date, ByVal [end] As Date, ByVal name As String)
Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("daypilot").ConnectionString)
con.Open()
Dim cmd As New SqlCommand("UPDATE [event] SET eventstart = @start, eventend = @end, name = @name WHERE id = @id", con)
cmd.Parameters.AddWithValue("id", id)
cmd.Parameters.AddWithValue("start", start)
cmd.Parameters.AddWithValue("end", [end])
cmd.Parameters.AddWithValue("name", name)
cmd.ExecuteNonQuery()
End Using
End Sub
See also event moving [doc.daypilot.org].
We will also limit the drag and drop moving to the horizontal direction using BeforeEventRender:
C#
protected void GanttControl_BeforeEventRender(object sender, BeforeEventRenderEventArgs e)
{
e.EventMoveVerticalEnabled = false;
}
VB
Protected Sub GanttControl_BeforeEventRender(ByVal sender As Object, ByVal e As BeforeEventRenderEventArgs)
e.EventMoveVerticalEnabled = False
End Sub
Drag and Drop Task Resizing
You can enable drag and drop task resizing using EventResizeHandling property.
.aspx
<DayPilot:DayPilotScheduler
runat="server"
ID="GanttControl"
ViewType="Gantt"
...
EventResizeHandling="Notify"
OnEventResize="GanttControl_EventResize"
...
/>
The GanttControl_EventResize will update the database and refresh the Gantt chart to display the new duration in the row header.
C#
protected void GanttControl_EventResize(object sender, EventResizeEventArgs e)
{
DbUpdateEvent(e.Value, e.NewStart, e.NewEnd, e.Text);
// force client-side Gantt chart update (possible duration change)
SetDataSourceAndBind();
GanttControl.Update(CallBackUpdateType.Full);
}
VB
Protected Sub GanttControl_EventResize(ByVal sender As Object, ByVal e As EventResizeEventArgs)
DbUpdateEvent(e.Value, e.NewStart, e.NewEnd, e.Text)
' force client-side update (possible duration change)
SetDataSourceAndBind()
GanttControl.Update(CallBackUpdateType.Full)
End Sub
Gantt Row Header Columns
Define the row header columns using HeaderColumns:
<DayPilot:DayPilotScheduler
runat="server"
ID="GanttControl"
ViewType="Gantt"
...
>
<HeaderColumns>
<DayPilot:RowHeaderColumn Title="Task" Width="120" />
<DayPilot:RowHeaderColumn Title="Duration" Width="90" />
</HeaderColumns>
</DayPilot:DayPilotScheduler>
The first column will automatically display the task name as defined in DataTextField property. The content of the additional columns can be defined using BeforeResHeaderRender event handler:
C#
protected void GanttControl_BeforeResHeaderRender(object sender, BeforeResHeaderRenderEventArgs e)
{
DateTime start = (DateTime) e.DataItem["eventstart"];
DateTime end = (DateTime) e.DataItem["eventend"];
TimeSpan duration = end - start;
e.Columns[0].Html = duration.ToString();
}
VB
Protected Sub GanttControl_BeforeResHeaderRender(ByVal sender As Object, ByVal e As BeforeResHeaderRenderEventArgs)
Dim start As Date = CDate(e.DataItem("eventstart"))
Dim [end] As Date = CDate(e.DataItem("eventend"))
Dim duration As TimeSpan = [end].Subtract(start)
e.Columns(0).Html = duration.ToString()
End Sub
Gantt PNG Export
The Gantt control has a built-in support for image export (PNG, JPG and other formats).
The "Export to PNG" button will use the Export() method to return the exported image for download.
C#
private void ExportToPng()
{
SetDataSourceAndBind();
SetExportProperties();
Response.Clear();
Response.ContentType = "image/png";
Response.AddHeader("content-disposition", "attachment;filename=gantt.png");
MemoryStream img = GanttControl.Export(ImageFormat.Png);
img.WriteTo(Response.OutputStream);
Response.End();
}
VB
Private Sub ExportToPng()
SetDataSourceAndBind()
SetExportProperties()
Response.Clear()
Response.ContentType = "image/png"
Response.AddHeader("content-disposition", "attachment;filename=gantt.png")
Dim img As MemoryStream = GanttControl.Export(ImageFormat.Png)
img.WriteTo(Response.OutputStream)
Response.End()
End Sub
Gantt PDF Export
We will use the PNG image export to insert the Gantt into a PDF file.
We will use the open-source PDFSharp library for handling the PDF export.
C#
private void ExportToPdf()
{
// create a new PDF document
PdfDocument doc = new PdfDocument();
doc.Info.Title = "Gantt Chart PDF Export";
doc.Info.Author = "DayPilot";
// add a page
PdfPage page = doc.AddPage();
// set PDF page properties (size and orientation)
page.Size = (PageSize) Enum.Parse(typeof (PageSize), ListPageSize.SelectedValue);
page.Orientation = (PageOrientation)Enum.Parse(typeof(PageOrientation), ListPageOrientation.SelectedValue);
// create graphics object for PDF page modification
XGraphics gfx = XGraphics.FromPdfPage(page);
// write title
XRect titleRect = new XRect(new XPoint(), gfx.PageSize);
titleRect.Inflate(-10, -15);
XFont font = new XFont("Tahoma", 14, XFontStyle.Bold);
gfx.DrawString("DayPilot Gantt PDF Export", font, XBrushes.DarkGray, titleRect, XStringFormats.TopCenter);
// create the Gantt image
SetDataSourceAndBind();
SetExportProperties();
Bitmap bitmap = GanttControl.ExportBitmap();
// add the image to the PDF page
XImage image = XImage.FromGdiPlusImage(bitmap);
XRect imageRect = GetPaddedRectForImage(gfx, image, 10);
double y = 40;
imageRect.Y = y;
gfx.DrawImage(image, imageRect);
// save the PDF file to MemoryStream
MemoryStream mem = new MemoryStream();
doc.Save(mem, false);
// send the output stream to the browser
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=gantt.pdf");
mem.WriteTo(Response.OutputStream);
Response.End();
}
VB
Private Sub ExportToPdf()
' create a new PDF document
Dim doc As New PdfDocument()
doc.Info.Title = "Gantt Chart PDF Export"
doc.Info.Author = "DayPilot"
' add a page
Dim page_Renamed As PdfPage = doc.AddPage()
' set PDF page properties (size and orientation)
page_Renamed.Size = DirectCast(System.Enum.Parse(GetType(PageSize), ListPageSize.SelectedValue), PageSize)
page_Renamed.Orientation = DirectCast(System.Enum.Parse(GetType(PageOrientation), ListPageOrientation.SelectedValue), PageOrientation)
' create graphics object for PDF page modification
Dim gfx As XGraphics = XGraphics.FromPdfPage(page_Renamed)
' write title
Dim titleRect As New XRect(New XPoint(), gfx.PageSize)
titleRect.Inflate(-10, -15)
Dim font As New XFont("Tahoma", 14, XFontStyle.Bold)
gfx.DrawString("DayPilot Gantt PDF Export", font, XBrushes.DarkGray, titleRect, XStringFormats.TopCenter)
' create Gantt image
SetDataSourceAndBind()
SetExportProperties()
Dim bitmap As Bitmap = GanttControl.ExportBitmap()
' add the image to the PDF page
Dim image As XImage = XImage.FromGdiPlusImage(bitmap)
Dim imageRect As XRect = GetPaddedRectForImage(gfx, image, 10)
Dim y As Double = 40
imageRect.Y = y
gfx.DrawImage(image, imageRect)
' save the PDF file to MemoryStream
Dim mem As New MemoryStream()
doc.Save(mem, False)
' send the output stream to the browser
Response.Clear()
Response.ContentType = "application/pdf"
Response.AddHeader("content-disposition", "attachment;filename=gantt.pdf")
mem.WriteTo(Response.OutputStream)
Response.End()
End Sub