Many blog engines provide a calendar view when visiting the blog via the Web. Typically the calendar shows the current month, with days that have one or more entries rendered as hyperlinks. Clicking on the link for a given day displays the posts for that day. Unfortunately .Text doesn't provide such a built-in calendar view, so I decided to create my own. (As to why .Text doesn't include a calendar view, Scott Watermasysk indicated that there were issues with the ASP.NET Calendar control and CSS. Not being a CSS expert, I'm not sure exactly what issues there are, but in my own experiment I'm happy with the rendered display of my calendar, and all stylesheets seem to be playing nicely together...)
In any event, take a minute to check out the Scott on Writing homepage - up in the upper-right hand corner you can see a calendar view. Pretty cool, eh? I'd like to share how I accomplished this.
DISCLAIMER: To add the Calendar control I decided to take a path of least resistance, and actually had the entire thing written in under ten minutes. I used a user control - a compiled control might be a better choice. There may be more efficient techniques to use than I employed. If you have suggestions on improvements, feel free to post them; if you want to use the code, feel free, but realize it was created hastily with a “let's get something working before my fiancee gets home from work”-attitude.
TECHNICAL NOTE: I am using .Text 0.94 - I have no idea if this code will work “as-is“ with different versions. I imagine it would, although if the database schema has changed, that would require a slight update of the SQL query used to get the blog entries for a given month/year....
I started by creating a User Control and adding a Calendar. My aim was to create an event handler for the Calendar's DayRender event, and then see if the particular day being rendered had any posts and, if so, display a hyperlink to the correct /archive/ URL. (To view the posts on MM/DD/YYYY, you can simply visit /archive/MMDDYYYY.aspx - ah, the power of HTTP handlers.)
Of course, I didn't want to have to hit the database once for each day in the month, so I loaded all of the blog entries from the month into a DataTable (ordered by the date of entry, in ascending order). The SQL query to run (which was moved into a stored procedure) was:
SELECT DateAdded FROM blog_Content (nolock)
WHERE PostType=1
AND BlogID = @BlogID
AND DATEPART(yyyy, DateAdded) = @Year
AND DATEPART(m, DateAdded) = @Month
ORDER BY DateAdded
|
Here, @BlogID is the ID of the blog whose dates of posts you want to show (if you are hosting multiple blogs on a single .Text install, each blog has its own BlogID). @Year and @Month are the year and month of blog entries to get. (The PostType=1 gets only blog entries - not comments, tracebacks, etc.)
In my User Control I have a DataTable (named dates) scoped at the class level that is populated with the results of the above SQL query. The code that performs this follows:
private void LoadMonthData() { SqlConnection myConnection = new SqlConnection(connection string);
SqlCommand myCommand = new SqlCommand("blog_GetBlogEntriesForMonth", myConnection); myCommand.CommandType = CommandType.StoredProcedure
// selDate is the currently selected date... myCommand.Parameters.Add(new SqlParameter("@Year", selDate.Year)); myCommand.Parameters.Add(new SqlParameter("@Month", selDate.Month));
SqlParameter blogID = new SqlParameter(); blogID.Value = 0; blogID.ParameterName = "@BlogID"; myCommand.Parameters.Add(blogID);
// Fill the dates DataTable... SqlDataAdapter myAdapter = new SqlDataAdapter(myCommand); myAdapter.Fill(dates);
myConnection.Close();
// Keep track of how many records are in the DataTable... dateCount = dates.Rows.Count; } |
In addition to having the dates DataTable scoped at class level, I also have two additional ints: one keeps track of how many total entries there are for the month (dateCount), the other stored the index of the current record being examined in dates (this variable is named currentDate).
In the event handler for the Calendar control's DayRender event, I check to see if the current date being rendered equals the date in the current row in dates being examined. If it does, I change the TableCell's Text property to a hyperlink and update currentDate accordingly - otherwise I do nothing. The code for this event handler follows:
private void dayRender(object sender, DayRenderEventArgs e) { if (currentDate < dateCount && e.Day.Date == Convert.ToDateTime(dates.Rows[currentDate]["DateAdded"]).Date) { e.Cell.Text = "<A href="\" +="" ?? archive sowBlog> String.Format("{0:d2}{1:d2}{2:d4}", e.Day.Date.Month, e.Day.Date.Day, e.Day.Date.Year) + ".aspx\"><U>" + e.Day.Date.Day + "</U></A>"; // There might be multiple entries per day, so advance currentDate until // we're on a different day... do { currentDate++; } while ((currentDate < dateCount && e.Day.Date == Convert.ToDateTime(dates.Rows[currentDate]["DateAdded"]).Date)); } } |
There are some other slight details involved, but the above description spells out the bulk of the work that needed to be done. In order to insert the calendar view I edited the PageTemplate.ascx User Control for my blog's appropriate skin. I also had to do a bit of tweaking with the #leftmenu, #main, and #rightmenu CSS items to get the calendar to fit without forcing the user to have to scroll off to the right.
If you are interested, you download the complete source code for the Calendar User Control here.