There were a couple of requests for showing multi-day events in the calendar. I took a look at the calendar code, and came up with the following fix. Note I only did some brief testing, but it seemed to work for the cases I tried.
Firstly, you'll need the calendar project, which can be found at http://www.asp.net/StarterKits/Downloads/EventCalendar.zip
This is a C# dll project, so you'll need vs standard or C# express sku to open it. In the EventCalendar.cs code:
a) Add the following property. It specifies the name of the field representing the end date:
[DefaultValue("")]
[Themeable(false)]
public virtual string EndDayField
{
get
{
object o = ViewState["EndDayField"];
if (o != null)
{
return (string)o;
}
return String.Empty;
}
set
{
ViewState["EndDayField"] = value;
if (Initialized)
{
OnDataPropertyChanged();
}
}
}
b) Replace the existing versions of the following methods:
private int CreateDataBoundChildren(System.Data.DataView dv, Table table, DateTime todaysDate, DateTime visibleDate, System.Globalization.Calendar threadCalendar)
{
DateTime firstDay = FirstCalendarDay(this.VisibleDate);
dv.Table.Locale = new CultureInfo("en-US");
int dayoffset = 0;
string dayField = this.DayField;
string endDayField = this.EndDayField;
for (int iRow = 0; iRow < 6; iRow++)
{
TableRow row = new TableRow();
table.Rows.Add(row);
for (int iDay = 0; iDay < 7; iDay++)
{
DateTime d = firstDay.AddDays(dayoffset);
//Initialize the cell
CalendarDay day = getDay(d, TodaysDate, visibleDate, threadCalendar);
TableCell cell = CreateDayCell(day);
row.Cells.Add(cell);
//Process real data for this day
dv.RowFilter = string.Format("IsNull({1},{0}) >= #{2}# AND {0}<#{3}#", dayField, endDayField, d.ToString("MM/dd/yyyy"), d.AddDays(1).ToString("MM/dd/yyyy"));
if (dv.Count > 0 && this.DayEventTemplate != null)
{
foreach (System.Data.DataRowView drv in dv)
{
DataBoundCalendarItem dataitem = new DataBoundCalendarItem(drv, day);
DayEventTemplate.InstantiateIn(dataitem);
//add the controls to both collections
cell.Controls.Add(dataitem);
//databind the data item
dataitem.DataBind();
}
}
else if (this.DayEmptyTemplate != null)
{
DataBoundCalendarItem dataitem = new DataBoundCalendarItem(null, day);
DayEmptyTemplate.InstantiateIn(dataitem);
//add the controls to both collections
cell.Controls.Add(dataitem);
}
dayoffset++;
}
}
return 1;
}
and
void cacheDataInViewstate(System.Data.DataView dv)
{
DateTime firstDay = FirstCalendarDay(this.VisibleDate);
DateTime lastDay = EndDate(this.VisibleDate);
System.Collections.Generic.Dictionary<DateTime, int> ctrlcount = new System.Collections.Generic.Dictionary<DateTime, int>();
foreach (System.Data.DataRowView drv in dv)
{
DateTime startdate = ((DateTime)drv[DayField]).Date;
DateTime enddate = (drv[EndDayField] != DBNull.Value) ? ((DateTime)drv[EndDayField]).Date : startdate;
DateTime rowdate = startdate;
while (rowdate <= enddate)
{
if (rowdate >= firstDay && rowdate <= lastDay)
{
if (ctrlcount.ContainsKey(rowdate))
{
ctrlcount[rowdate] += 1;
}
else
{
ctrlcount[rowdate] = 1;
}
}
rowdate = rowdate.AddDays(1);
}
}
ViewState[ViewStateDataKey] = ctrlcount;
}
That should be all you need in the calendar. Build it and either reference it from the website, or copy the output to the bin directory.
The eventscalendar.aspx page needs to be modified to query for the end data as part of the sql datasource and to set the name of the enddate field on the calendar control. For example:
<asp:SqlDataSource id=SqlDataSource1 SelectCommand="SELECT [id], [starttime], [endtime], [title], [description] FROM [Events]" ConnectionString="<%$ ConnectionStrings:ClubSiteDB %>" runat="server"></asp:SqlDataSource>
<ec:EventCalendar id=eventscalendar CssClass="eventmonthtable" runat="server" ShowTitle="true" EndDayField="endtime" DayField="starttime" BorderWidth="0" DataSourceID="sqldatasource1">
...
</ec:EventCalendar>
That should be all that you need to have long running events show up on each day that they occur.