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

gantt asp.net control setup

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

gantt asp.net sql schema

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

gantt asp.net visible 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

gantt asp.net control add task

We will use a modal dialog to display a new task dialog.

<a href="javascript:add()" id="add">Add Task...</a>&nbsp;

<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

gantt asp.net control 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

gantt asp.net control 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

gantt asp.net control 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

gantt asp.net control 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

gantt asp.net control pdf

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