Thursday, February 19, 2009

Building asp.net(c#) database driven event calendar




Please visit my new Web Site WWW.Codedisplay.com



Tracking events based on date is one of the most common requirements in our daily lives. Event calendar is one of the most popular solution where user can easily track his/her or agents or subordinates daily most important activies. Most of the free components probably can't implement your demand. In asp.net you can use calendar control to fullfill custom demands. But i am trying to develop a calendar without using calendar control. To do this i choose DataList because here i can define column no & repeat direction which make me interested. I want to produce my output like below:

At first add a datalist control in your page. Use a HeaderTemplate column to generate custom header where you will place year combo control & month navigation link. Add ItemTemplate to create day wise block within the calendar. The code looks like:

<asp:DataList ID="dlCalendar" runat="server" RepeatColumns="7" Width="600px" BorderStyle="None" RepeatDirection="Horizontal" OnItemDataBound="dlCalendar_ItemDataBound">

<HeaderTemplate>
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="background-color:#00BFFF;height:20px"><tr><td width="33%"><asp:DropDownList runat="server" ID="cboPrev" AutoPostBack="true" Width="70px" OnSelectedIndexChanged="RfreshData"></asp:DropDownList>
<asp:Label runat="server" ID="lblLeft" ></asp:Label>
</td><td width="33%" align="Center"><asp:Label runat="server" ID="lblMiddle" >
</asp:Label></td><td width="33%" align="right">
<asp:Label runat="server" ID="lblRight" ></asp:Label>
<asp:DropDownList runat="server" ID="cboNext" Width="70px" OnSelectedIndexChanged="RfreshData"></asp:DropDownList></td></tr>
</table>
</HeaderTemplate>

<ItemTemplate><table border="0" style="background-color:Silver" width="130px" style="height:100px" cellpadding="0" cellspacing="0" ><tr><td align="left" valign="top"">
<asp:Label ID="Label1" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Data") %>' Width="100%"></asp:Label>
</td></tr></table>
</ItemTemplate>

</asp:DataList>

For simplicity here i use datatable. But you can easily replace the datatable by populating data from database. So at first i need to populate event data then combind this data with date block of the calendar. To do that i write the below code:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DateTime dDate;
if (Request["SpecificMonth"] != null)
dDate = Convert.ToDateTime(Request["SpecificMonth"]);
else
dDate = DateTime.Now;

// Here you need to made the datastructure in such a way that you can bind the data in your datalist easily.
// So give concentration on database query to produce data like below:
// You can display each event, description if you can make the data row appropriately.

DataTable dtEvents = new DataTable("DailyEvents");
dtEvents.Columns.Add(new DataColumn("EventDate", System.Type.GetType("System.DateTime")));
dtEvents.Columns.Add(new DataColumn("EventType"));
dtEvents.Columns.Add(new DataColumn("EventDescription"));
dtEvents.Columns.Add(new DataColumn("Done"));
dtEvents.Columns.Add(new DataColumn("Note"));

dtEvents.Rows.Add(DateTime.Now,"Meeting", "BSSOM", "Attended?", "Agenda: 1)Indexing problem in ABC server. 2) Fix time to go Live. 3) Who will be responsible to maintain it?");

dtEvents.Rows.Add(DateTime.Now.AddDays(5),"Travel", "Coxsbazar", "Visited?", "Agenda: 1) Go to barmiz market 2) Buy few cloths for my wife 3) Eat rupchanda fish");

dtEvents.Rows.Add(DateTime.Now,"Assignment", "Audit", "R&D Done?", "");
dtEvents.Rows.Add(DateTime.Now, "Rport", "Fin. report", "Ready?", "");
dtEvents.Rows.Add(DateTime.Now.AddDays(5), "Birthday", "Shumon", "Send gift?", "");

DataTable datatable = new DataTable();
datatable.Columns.Add("Day"); //day contains day of the month
datatable.Columns.Add("Data"); //run time produce html & just place on it.
DataRow oRow;

for (int i = 1; i <= DateTime.DaysInMonth(dDate.Year, dDate.Month); i++)
{

DateTime dCalendarDay = new DateTime(dDate.Year, dDate.Month, i);
oRow = datatable.NewRow(); // here i am preparing data for a specific day.
// bworkingday method return: does the day is off or not.
// You can apply you business logic in this function to reurn data.
// by getEvents method i collect this day events from my all data.
// you can add control & event handler in runtime for more interactive calendar.

if (!bWorkingDay(dCalendarDay))
oRow["Data"] = i.ToString() + " " + dCalendarDay.ToString("ddd") + " " + getEvents(dCalendarDay, dtEvents);
else
oRow["Data"] = i.ToString() + " " + dCalendarDay.ToString("ddd") + " " + getEvents(dCalendarDay, dtEvents);
datatable.Rows.Add(oRow);

}

dlCalendar.DataSource = datatable;
dlCalendar.DataBind();

// here just i am making current date block.
if (dDate.Year == DateTime.Now.Year && dDate.Month == DateTime.Now.Month)
{
foreach (DataListItem oItem in dlCalendar.Items)
{
if (oItem.ItemIndex == DateTime.Now.Day - 1)
{
oItem.BorderStyle = BorderStyle.Solid;
oItem.BorderColor = System.Drawing.Color.DeepSkyBlue; oItem.BorderWidth = 2;
}// if closed
}// for closed
}// if closed

}// !IsPostBack
}// Page_Load

In the above code block i use few fuctions like:
public string getEvents(DateTime dDate, DataTable dTable)
{
string str = "";
foreach (DataRow oItem in dTable.Rows)
{
if (Convert.ToDateTime(oItem["EventDate"].ToString()).ToString("dd MMM, yyyy") == dDate.ToString("dd MMM, yyyy"))
{
str = str + " " + oItem["EventType"] + ":" + oItem["EventDescription"] + " ";
}
}
return str;
}

public bool bWorkingDay(DateTime bDate)
{
// here i am assuming the sunday as holiday but you can make it more efficiently
// by using a databse if you want to generate country based calendar.
// In different country they have different holidays schedule.
if (bDate.ToString("ddd") == "Sun")
return true;
return false;
}

Now add the dlCalendar_ItemDataBound handler to populate header row of the datalist. Method code looks like:
protected void dlCalendar_ItemDataBound(object sender, DataListItemEventArgs e)
{
// Just populationg my header section
DateTime dDate;
if (Request["SpecificMonth"] != null)
dDate = Convert.ToDateTime(Request["SpecificMonth"]);
else
dDate = DateTime.Now;
if (e.Item.ItemType == ListItemType.Header)
{
DropDownList oPrev = (DropDownList)e.Item.FindControl("cboPrev");
DropDownList oNext = (DropDownList)e.Item.FindControl("cboNext");
DataTable dtYear = new DataTable();
dtYear.Columns.Add("year4");
dtYear.Columns.Add("sValue");
//here i am assuming that when user click on 2009 he wants to see january 2009 calendar.
//it will be more interective if you generate the current month(shown in the page) calendar.
dtYear.Rows.Add("2009", "01 Jan, 2009");
dtYear.Rows.Add("2010", "01 Jan, 2010");
oPrev.DataTextField = "year4";
oPrev.DataValueField = "sValue";
oPrev.DataSource = dtYear;
oPrev.DataBind();
oNext.DataTextField = "year4";
oNext.DataValueField = "sValue";
oNext.DataSource = dtYear;
oNext.DataBind();

((Label)e.Item.FindControl("lblLeft")).Text = " <a style="'color:White'" href="eventcalendar.aspx?SpecificMonth="">" + dDate.AddMonths(-1).ToString("MMMM yyyy") + "</a>";

((Label)e.Item.FindControl("lblMiddle")).Text = dDate.ToString("MMMM yyyy");

((Label)e.Item.FindControl("lblRight")).Text = "<a style="color:White" href="eventcalendar.aspx?SpecificMonth="">" + dDate.AddMonths(+1).ToString("MMMM yyyy") + "</a> ";
}
}

Now almost completed our calendar except corner year combo. To raise the selectedeventchange event must set AutoPostBack property to true. When user select a year then we just redirect him by a querystring & then we generate the calendar based on user selection by reading the query string. Code like:
protected void RfreshData(object sender, System.EventArgs e)
{
//redirect by date thats why page can render the calendar according to user selection
Response.Redirect("eventcalendar.aspx?SpecificMonth=" + ((DropDownList)sender).SelectedValue);
}

Conclusion:
This approach requires more coding. You can reduce effort by using builtin calendar control. So lets try.

6 comments:

Lao Calendar said...

Hi there,
This is very interesting article and thank you for sharing with us. I have a question for you, I would like to have buttons for navigat next and previous months. When the next or previous month clicked I also wanted to display all the evetns occurred within earch selected month.

Please reply with coding sample.

Thank in advance

Dekmekong.

Saion Roy said...

Hi Dekmekong,
Thanks.

If you enlarge the calender image you will found that already i have discussed such option. Here i have used linkbutton instead of button control. So if you read the whole article, hope you can implement your requirement. Let me know if you can't understand.

Vipul said...

hey Shawpnendu..
a very nice article, and thanks for sharing it with all of us.
I was just wondering if we can integrate it with AJAX so that on changing the month the whole page will not be refreshed but only the calendar.

If it is possible, can u please throw some light on it.

Thanks.

Saion Roy said...

Hi Vipul,
Yap its possible. Wrap up the DataList control within UpdatePanel. But keep in mind that you have to change other UpdatePanel UpdateMode property from Always to Conditional.

Now, the Datalist container UpdatePanel will refresh itsself only if an event occurs in one of the controls in that UpdatePanel.

pitso said...

how do we use build in calendar?

Anonymous said...

Thanks for the code - Its great, and not overly complicated like some other calendar examples.

Want to say something?
I WOULD BE DELIGHTED TO HEAR FROM YOU

Want To Search More?
Google Search on Internet
Subscribe RSS Subscribe RSS
Article Categories
  • Asp.net
  • Gridview
  • Javascript
  • AJAX
  • Sql server
  • XML
  • CSS
  • Free Web Site Templates
  • Free Desktop Wallpapers
  • TopOfBlogs
     
    Free ASP.NET articles,C#.NET,VB.NET tutorials and Examples,Ajax,SQL Server,Javascript,Jquery,XML,GridView Articles and code examples -- by Shawpnendu Bikash