利用ASP.NET日期控件制作“会议日程安排”
大家应该比较熟悉outlook里的日程安排,点进去就是一个日历版面,选择某日即可添加当天的日程安排,还有偶尔玩下开心网的兄弟们应该也知道有个日程组件,其实和outlook有点兄弟关系,只不过比outlook做的要漂亮些:) 从VS03到VS08里,ASP.NET一直带有个Calendar日历控件,我不知道历经三代岁月沧桑的交替,这个控件发生了多少变化,不是很清楚,因为从来就没在项目中用过,最近的一个项目倒是提到了这方面的需求,要求用户登录点“会议日程”能显示当前月的日期和相应具体日期有哪些事情等...... ,首先看下面个图,然后依此慢慢详述:
这个是运行系统的原图,下面具体说明下用ASP.NET的日历控件来重新完成这一功能,完整的demo在文章最后有链接地址供下载。
Calendar控件有一个DayRender事件,即是在呈现日时激发,我们的处理程序代码必须写在这个事件下才行,只有这样才能保证在呈现某个日时从数据库加载相应的日程安排来重绘当前日历控件日的日。
首先定义两个一维数组(当然也可以定义一个二维数组),一个记录当前月中的日,一个几个当前月中的日对应的会议标题,如
int[] intArray = new int[999];
title = new string[999];
假设选中的是12月份,从数据库取出的数据可能是这样的intArray [0] = 2,intArray [1] = 2,intArray [3] = 5等 对应的标题数组就是这样的
title[0] = "上午10点开会" title [1] = "下午XX需求讨论" title [2] = "客户系统演示"(没有日程安排的日,那么intArray [i] = 0,后面程序跳出循环的依据正式根据该项的值是否为0来判断的) 这个表示12月2日有两项会议日程安排,12月5日有一项日程安排,这里我定义的数组长度为999相当于每月平均每天30多次会议,一般也不会到这个数了呵呵,如果从数据库读出的当月会议项次超出999次当然会报异常,这里当然也是可以从数据库动态读,实际的必要性也不是很大吧。
添加日程安排的时候,可以选择跨天数,但不允许跨月(如果要跨月不是不可以,日期的拆分上要再作下处理,只是这个主要用来安排某日的议程,必要性不是很大)比如选择2008-12-1 至 2008-12-3 添加一条日程安排,日历呈现时会拆分成三条数据分别对应1,2,3号,表示该三天都有同一件会议安排。下面是添加日程的截图:
数据库字段为 [PLAN_ID] [PLAN_TITLE] [PLAN_CONTENT] [START_DATE] [END_DATE] [CREATE_DATE] [UPDATE_DATE]
根据日期安排的开始时间的年和月来查找出当前年当前月的日程记录,最终返回一个日期数组和包括一个引用类型的标题数组,方法如下:
/// 返回日期数组
/// </summary>
/// <param name="Year"></param>
/// <param name="Month"></param>
/// <param name="title"></param>
/// <returns></returns>
public List<int> GetList(int Year,int Month,out List<string> title)
{
//int[] intArray = new int[999];
//title = new string[999];
List<int> intArray = new List<int>(new int[999]); //设定一个月最多999次会议,当然也可以通过数据库记录动态赋值即下面的i值
title = new List<string>(new string[999]);
//从数据库里选取符合要求的记录,将日期存入数组(即符合所选的当前年当前月所有的会议记录)
StringBuilder strSql = new StringBuilder();
strSql.Append(" SELECT PLAN_TITLE,START_DATE,END_DATE ");
strSql.Append(" FROM WORK_PLAN ");
strSql.Append(" WHERE DATEPART(year,START_DATE)=" + Year);
strSql.Append(" AND DATEPART(month,START_DATE)=" + Month);
int i = 0;
string planName = string.Empty;
SqlDataReader dr = null;
try
{
dr = DataAccess.ExecuteSqlReader(conn, CommandType.Text, strSql.ToString(), null);
while (dr.Read())
{
DateTime sdate = DateTime.Parse(dr["START_DATE"].ToString());
DateTime edate = DateTime.Parse(dr["END_DATE"].ToString());
planName = dr["PLAN_TITLE"].ToString();
if (sdate == edate) //如果该会议安排没有跨天数
{
intArray[i] = sdate.Day;
title[i] = planName;
i++;
}
else if (sdate < edate) //跨天数(仅当前月内),如11日,12日都安排该日程,则在日历控件呈现时12日,12日都会显示改会议日程安排
{
for (int j = 0; j <= edate.Day - sdate.Day; j++)
{
intArray[i] = sdate.Day + j;
title[i] = planName;
i++;
}
}
}
return intArray;
}
catch (System.Exception ex)
{
throw ex;
}
finally
{
dr.Close();
conn.Close();
}
}
接下来就是加载呈现WEB页面的日历控件的操作,先定义相关的变量
//private int[] arrCurrentDays, arrPreDays, arrNextDays;
private List<int> arrCurrentDays;//, arrPreDays, arrNextDays;
//三个整型数组存放相对月份写有plan的日期
private int intCurrentMonth, intPreMonth, intNextMonth;
//string[] planName = new string[999];//在日期下面显示有会议安排的标题名称
List<string> planName;//在日期下面显示有会议安排的标题名称
string planTitle = string.Empty;//当前日所有标题拼接成一个字符串
DayRender事件里,每读到一个日,就会执行一次,加载时读到的第一个月并不是当前月,而是当前月的上一个月,
因为如果把日历控件看成二维数组的话,是5X7的(二月有时是4X7的,马上新的一年好像就是,呵呵),一个月最多只有31天,
所以每个次日历控件的日期呈现,至少会出现两个月的,代码贴在下面好了,也都有注释
{
CalendarDay d = ((DayRenderEventArgs)e).Day;
TableCell c = ((DayRenderEventArgs)e).Cell;
if (intPreMonth == 0)
{
//日历控件初始化时取得的是第一个月并不是当前月,而是前一个月的月份
intPreMonth = d.Date.Month;
intCurrentMonth = intPreMonth + 1;
if (intCurrentMonth > 12)
intCurrentMonth = 1;
intNextMonth = intCurrentMonth + 1;
if (intNextMonth > 12)
intNextMonth = 1;
//得到前一个月有plan的日期数组
//arrPreDays = getArrayDay(d.Date.Year, intPreMonth);
//得到当月有plan的日期数组
arrCurrentDays = getArrayDay(d.Date.Year, intCurrentMonth);
//得到下个月有plan的日期数组
//arrNextDays = getArrayDay(d.Date.Year, intNextMonth);
}
string strDate = d.Date.Year + "-" + d.Date.Month + "-" + d.Date.Day;
string title = d.Date.Month.ToString() + "月" + d.Date.Day.ToString() + "日";//鼠标移上时显示相应的月日
c.Controls.Clear();//绘制前先清除
//打开新窗口传递参数.
c.Controls.Add(new LiteralControl("<a href='#' onclick=javascript:OpenWin('ViewPlan.aspx?PlanDate=" + strDate + "'" + ",650,750,50,200) title='" + title + "'>" + d.Date.Day + "</a>"));
int j = 0;
int Rownum = 0;
if (d.Date.Month.Equals(intPreMonth))
{
c.Controls.Clear();//让上月日期不可见
//while (!arrPreDays[j].Equals(0))
//{
// if (d.Date.Day.Equals(arrPreDays[j]))
// {
// //放置逻辑处理
// }
// j++;
//}
}
else
if (d.Date.Month.Equals(intCurrentMonth))
{
title = d.Date.Month.ToString() + "月" + d.Date.Day.ToString() + "日";//鼠标移上时显示相应的月日
//IEnumerable<int> Days = from day in arrCurrentDays
// where day != 0 && d.Date.Day == day
// select day;
//
//foreach (int dd in Days)
//{
// Rownum++;
// planTitle += "(" + Rownum.ToString() + ")" + planName[x] + "<br />";//如果能取到索引值可以使用下LINQ语句 像上面那样
// c.Controls.Clear();
// c.BorderWidth = 1;
// c.BorderColor = System.Drawing.Color.Red;
// c.BackColor = System.Drawing.Color.Pink;
// c.Controls.Add(new LiteralControl("<a href='#' onclick=javascript:OpenWin('ViewPlan.aspx?PlanDate=" + strDate + "'" + ",650,750,50,200) title='" + title + "'><font color='blue' size='3'>" + d.Date.Day + "<font><br/><div style='text-align:left'><font color='blue' size='2'>" + planTitle + "<font></div></a>"));
//}
//=====若当月的会议次数为N,当月天数为M 则循环执行M*N次=============================//
while (!arrCurrentDays[j].Equals(0)) //没有会议对应的值即为整型数组的默认值0
{
if (d.Date.Day.Equals(arrCurrentDays[j])) //判断当前日期的第几天是否于
{
Rownum++;
planTitle += "(" + Rownum.ToString() + ")" + planName[j] + "<br />";//标题索引与天的索引是一一对应的
c.Controls.Clear();
//当前月有会议安排的日期并设置相应的字体格式于样式
c.BorderWidth = 1;
c.BorderColor = System.Drawing.Color.Red;
c.BackColor = System.Drawing.Color.Pink;
c.Controls.Add(new LiteralControl("<a href='#' onclick=javascript:OpenWin('ViewPlan.aspx?PlanDate=" + strDate + "'" + ",650,750,50,200) title='" + title + "'><font color='blue' size='3'>" + d.Date.Day + "<font><br/><div style='text-align:left'><font color='blue' size='2'>" + planTitle + "<font></div></a>"));
}
j++;
}
//每次循环后清空变量
planTitle = string.Empty;
}
else if (d.Date.Month.Equals(intNextMonth))
{
c.Controls.Clear();//让下月日期不可见
//while (!arrNextDays[j].Equals(0))
//{
// if (d.Date.Day.Equals(arrNextDays[j]))
// {
//放置逻辑处理
// }
// j++;
//}
}
}
按上面再解释下(其中有些作了注释就不多说了,也有个别问题注释里也说了,当然可以改进的),一个空的日历控件在WEB页面上浏览时,
鼠标移上去会有日期提示,但是每次重绘当前日时,必须要清空,不然日期数字会重叠,重绘了就不会有鼠标移上去的提示效果,
和普通的href链接一样,重加个title属性就可以了,如果只想让当前月的日期可见,上月和下月的日期不可见,可以在加载时作下判断,
如果是上月或下月,就作一个清空处理(如果要显示上下月的日程记录,要在日期数组返回前作处理了,本例中日期数组只返回当前月的日,
并没有上月和下月的会议日程记录),输出的格式不作处理的话,都是剧中显示的,所以手动加了个样式,把当前日的会议标题作为一个整字符串,
加上链接,转到详细也传递当前日作为参数就可以了。详细的显示也就不多说了,详细页的查看日程记录在实际的项目应用中可以和用户关联,
当前用户只可以可以编辑自己的日程安排和查看所有的日程安排(事实项目中也正是这么用的)。代码在下面下载好了,要测试的话把建表的脚本跑一下
(下载包里),就一个表。部分代码是从项目中COPY出来的,重新整理了下可以单独运行,是VS08的项目,VS05可能打不开,
不过把要用的代码直接COPY到05里也一样可以运行的。最好把测试运行的效果图截两张
到此结束,谢谢观赏 :) 实在没什么含量,看具体情况用用了 呵呵 决定还是放到首页过把瘾 赶上今天个特殊的天 兄弟们辛苦了 预祝圣诞快乐~~