客户端计时器控件(clientTimer)的c#源码

    技术2022-05-11  56

          设计一个在线考试系统,卷面计时是必须解决的一个问题,因为考试都有一个答题时间限制,时间一到,针对那些仍未交卷的考生,系统应该有强制收卷的功能。当然,对于一个在线考试系统,最重要的还应该是他的答案保存功能,这里不做讨论,只分析卷面计时问题,最终设计出一个运行在客户端、超时后可以调用服务器端方法的计时器控件。

    问题分析

    (1)考生打开装载试题的页面标志着考试的开始,所以应该从这一刻起开始计时。(2)服务器只能在有客户端请求的时候才会提供数据,而不会主动向浏览器post信息,所以必须在客户端实现计时。(3)强制交卷本质上就是保存答案并退出答题界面,需要回发数据,因而该操作应该是一个服务器端方法。(4)应该有一个友好界面,提示考生还剩多少时间。(5)为了防止某些考生以给考试界面抓图保存、退出系统后按图做题、然后回来填写答案的方式作弊,开始答题的同时交卷时间确定。(6)对于那些受网络掉线、死机等不确定性因素影响而在考试过程中意外退出答题界面的考生,因为无法准确判断他们和蓄意作弊考生的区别,我找不到合适的解决方法,只能算他们倒霉,浪费掉那些等待时间。你要有办法,可以讨论一下大家。提出方案    针对以上的分析,可以提出一个大概的解决方法。

        在数据库方面,在考试信息表中应该包含考生标识(string,用考号就可以)、开始答题时间(DateTime)、答题结束时间(DateTime)、已交卷(bool)四个字段(当然还得有其他的必要字段,这里就不详细说明了,毕竟我要说的只是卷面计时问题)。

        在客户端方面,答题页面onload的时候调用一个javascript函数开始计时,这个函数是循环执行的,以便随时保存已用时间,这里设置其循环周期为1分钟,在函数体内,首先需要判断是否已到限制时间,若是则强制交卷,若否则显示友好界面的计时信息,然后等待下一次调用,相关js代码如下:

    < script language = " JavaScript " > var  myTimeOut = 30 ;     // 可用时间,单位为分钟  var  myPassTime = 0 ;     // 已用时间,单位为分钟  window.attachEvent( " onload " , myTimer);     // 绑定到onload事件 function  myTimer()  {    if(myPassTime<myTimeOut){    //已用时间是否小于可用时间                myPassTime+=1;    //保存客户端已用时间        //显示友好界面的计时信息  这里先空着            }else{        //执行强制交卷        //可以通过模拟点击一个linkbutton来实现,        //在服务器端把强制交卷的代码先在linkbutton的Click里就可以了    }    window.setTimeout("myTimer()",60000);//一分钟循环一次} </ script >

        在服务器代码方面,Page_Load事件中对考试信息进行初始化:if(根据标识检索到当前考生的考试信息){    if(已交卷){        反馈已交卷信息     } else {        if(当前时间<答题结束时间){            设置好已用时间,让考生继续答题        } else {            强制交卷        }     }} else {    添加考生的考试信息    设置好开始答题时间(设为当前时间)、答题结束时间(当前时间加上总的可用时间)、已交卷为(false)    正常进入考场}

        考试页面放置一个linkbutton,在该控件的Click里编写强制交卷代码,以供js模拟点击的时候执行。设计控件

        为了方便以后使用,这里把计时相关的功能封装成一个自定义控件。

        控件名称:clientTimer,从PlaceHolder继承,命名空间为myControl。

        公开属性:

        属性名:TimeOutUnits    类  型:TimeOutUnitsType    介  绍:计时单位,有秒、分钟、小时三种,默认为分钟。

        属性名:TimeOutLength    类  型:int    介  绍:计时超时时间(单位与TimeOutUnits属性一致)。

        属性名:PassTimeLength    类  型:int    介  绍:已用去的时间(单位与TimeOutUnits属性一致)。

        属性名:TimerEnabled    类  型:bool    介  绍:是否启用计时器。    属性名:CountDown    类  型:bool    介  绍:是否以倒计时的方式显示友好界面,是则显示还剩多少时间,否则显示用了多少时间。

        公开事件:

        事件名:onTimeOut    介  绍:超时的时候执行,可以把强制交卷的代码放里头执行

        控件源码:

    using  System; using  System.IO; using  System.Web; using  System.Web.UI; using  System.Web.UI.WebControls; using  System.ComponentModel; using  System.ComponentModel.Design; namespace  myControl {    /**//// <summary>    /// 客户端计时器clientTimer控件    /// 在线考试系统中卷面计时所用,你可以自由修改    /// 丛兴滋(cncxz)    2005-12-3    /// </summary>    [Description("客户端计时器clientTimer")]    [Designer(typeof(clientTimerDesigner))]    [ToolboxData("<{0}:clientTimer runat=server></{0}:clientTimer>")]    public class clientTimer: System.Web.UI.WebControls.PlaceHolder    {        public onTimeOutEventHandler onTimeOut;        //超时事件        private LinkButton myLB;        private Label myLabel;        "公共属性""公共属性"        public clientTimer()        {            myLB=new LinkButton();                        myLB.Click+=new EventHandler(myLB_Click);            myLabel=new Label();        }        private void myLB_Click(object sender, System.EventArgs e){            if(onTimeOut!=null){                onTimeOut();            }        }        protected override void OnLoad(EventArgs e)        {            if(this.TimerEnabled)            {                myLB.ID=this.ClientID+"_LB_TimeOut";                myLB.Text="";                myLabel.ID=this.ClientID+"_Label_Msg";                myLabel.Text="";                this.Controls.Add(myLB);                this.Controls.Add(myLabel);            }            base.OnLoad(e);                    }        protected override void Render(HtmlTextWriter writer)         {            if(this.TimerEnabled)            {                switch(this.TimeOutUnits)                {                    case TimeOutUnitsType.Second:                        writer.Write(this.strJS(1000," 秒"));                        break;                    case TimeOutUnitsType.Minute:                        writer.Write(this.strJS(60000," 分钟"));                        break;                    case TimeOutUnitsType.Hour:                        writer.Write(this.strJS(3600000," 小时"));                        break;                }            }            base.Render(writer);        }        private string  strJS(int intCycLength,string strUnits){                        string strFunction=this.ClientID+"_Timer";            string strTimeOut=this.ClientID+"_TimeOut";            string strPassTime=this.ClientID+"_PassTime";            string scriptString =" ";            scriptString += @"<script language=""JavaScript"">"+" ";            scriptString += @"    <!--"+" ";            scriptString += "var "+strTimeOut+"="+this.TimeOutLength.ToString()+"";            scriptString += "var "+strPassTime+"="+this.PassTimeLength.ToString()+"; ";            scriptString += @"        window.attachEvent(""onload"", "+strFunction+");"+" ";            scriptString +="function "+strFunction+"() { ";            scriptString += "    if("+strPassTime+"<"+strTimeOut+"){ ";            scriptString += @"        //未超时"+" ";            scriptString += "        "+strPassTime+"+=1; ";            if(this.CountDown)            {                scriptString += "        var myNum="+strTimeOut+"-"+strPassTime+"; ";                scriptString += @"        document.getElementById("""+this.myLabel.ClientID+@""").innerText=""剩余时间:""+myNum+"""+strUnits+@""";"+" ";            }            else            {                scriptString += @"        document.getElementById("""+this.myLabel.ClientID+@""").innerText=""已用时间:""+"+strPassTime+@"+"""+strUnits+@""";"+" ";            }                        scriptString += "    }else{ ";            scriptString += @"        //时间到"+" ";            scriptString += @"        document.getElementById("""+this.myLB.ClientID+@""").click();"+" ";            scriptString += "    } ";            scriptString += @"    window.setTimeout("""+strFunction+@"()"","+intCycLength.ToString()+@");"+" ";            scriptString += "} ";                        scriptString += @"//-->"+" ";            scriptString += @"</script>"+" ";                        return scriptString;        }    }    /**//// <summary>    /// 计时单位的类型。    /// </summary>    public enum TimeOutUnitsType:byte    {        /**//// <summary>        /// 秒。        /// </summary>        Second,        /**//// <summary>        /// 分钟。        /// </summary>        Minute,        /**//// <summary>        /// 小时。        /// </summary>        Hour    }    public delegate void onTimeOutEventHandler();    public class clientTimerDesigner:System.Web.UI.Design.ControlDesigner    {        private clientTimer CT;        public clientTimerDesigner(){        }        public override string GetDesignTimeHtml()        {            CT=(clientTimer)Component;            string str="";            str+=@"<span style=""height:20px;padding:2px 10px 2px 10px;border-left:1px solid #fafafa;border-top:1px solid #fafafa;border-bottom:1px solid #d0d0d0;border-right:1px solid #d0d0d0;FILTER: progid:DXImageTransform.Microsoft.Gradient(startColorStr='#f5f5f5', endColorStr='#e5e5e5', gradientType='0');"">";            str+=CT.ID+@"</span>";            return str;        }    }    }  

    控件测试

    1、将控件源码保存并编译成一个dll文件,然后添加到vs的控件面板

    2、新建一个WebApplication工程(WebApplication1)

    3、向默认的WebForm1.aspx添加一个clientTime控件(clientTime1),一个Label控件(Label1),随便排列一下位置

    4、选中clientTime1,在属性面板中设置:

    clientTime1.TimerEnabled属性为trueClientTimer1.TimeOutUnits属性为Second  //便于观察效果ClientTimer1.TimeOutLength属性为30 ClientTimer1.PassTimeLength属性为5ClientTimer1.CountDown属性为true //倒计时

    5、在WebForm1.aspx的空白处双击,切换到codebehind视图,加入如下代码:

    private   void  Page_Load( object  sender, System.EventArgs e) // 在此处放置用户代码以初始化页面 this.ClientTimer_Test.onTimeOut+=new myControl.onTimeOutEventHandler(this.ClientTimer1_onTimeOut);} private   void  ClientTimer1_onTimeOut() this.ClientTimer_Test.TimerEnabled=false; Label1.Text=DateTime.Now.ToString()+"到时间了";}

    6、按F5编译运行,在WebForm1.aspx界面上可以看到 一个读秒的倒计时,归零后会在Label1那里显示 当前时间和到时间了

    控件使用

    1、将控件源码保存并编译成一个dll文件,然后添加到vs的控件面板

    2、拖动一个控件到考试页面(假设其id为clientTime1)

    3、Page_Load事件中注册clientTime1的onTimeOut事件,当然,还得有考试信息初始化的代码

    private   void  Page_Load( object  sender, System.EventArgs e) this.ClientTimer_Test.onTimeOut+=new myControl.onTimeOutEventHandler(this.ClientTimer1_onTimeOut);// if(根据标识检索到当前考生的考试信息){//  if(已交卷){//   ClientTimer1.TimerEnabled=false; //不用计时了//   反馈已交卷信息//  } else {//   if(当前时间<答题结束时间){//    ClientTimer1.TimerEnabled=true; //启用计时功能//    ClientTimer1.TimeOutUnits=myControl.TimeOutUnitsType.Minute;//设置单位为分钟//    ClientTimer1.TimeOutLength=答题结束时间 与 开始答题时间 之差; //设置答题总时间//    ClientTimer1.PassTimeLength=答题结束时间 与 当前时间 之差; //设置已用时间  //    //考生继续答题//   } else {//    ClientTimer1.TimerEnabled=false; //不用计时了//    强制交卷//   }//  }// } else {//  添加考生的考试信息//  设置好开始答题时间(设为当前时间)、答题结束时间(当前时间加上总的可用时间)、已交卷为(false) //  ClientTimer1.TimerEnabled=true; //启用计时功能//  ClientTimer1.TimeOutUnits=myControl.TimeOutUnitsType.Minute;//设置单位为分钟//  ClientTimer1.TimeOutLength=总的可用时间; //设置答题总时间//  ClientTimer1.PassTimeLength=0; //设置已用时间 //  正常进入考场// }}   private   void  ClientTimer1_onTimeOut() this.ClientTimer1.TimerEnabled=false//不用计时了 //这里放 强制交卷 的代码}

    补充说明

        使用中注意计时单位的选取,整体上要一致,建议使用分钟。

        另外就是,我没仔细考虑整个考试系统的设计,只是选取了卷面计时这一点来分析,希望对将要设计考试系统的朋友有所帮助。


    最新回复(0)