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

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

问题分析

(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属性为true
ClientTimer1.TimeOutUnits属性为Second  //便于观察效果
ClientTimer1.TimeOutLength属性为30 
ClientTimer1.PassTimeLength属性为5
ClientTimer1.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//不用计时了
 
//这里放 强制交卷 的代码
}



补充说明

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

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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值