Insus.NET一直想把單選項試題實現的想法寫成博文。想實現單選項試題,有幾個問題需要清楚的:
第一是選項內容,由幾個選項組成,一個,二個還是三個四個等,選項的內容是A,B,C,還是其它內容,考員作答選擇時,是存儲Key值,還是存儲顯示值?因此有設計這些時,能夠實現單選選項能有幾種形式。
第二是單選題,標題內容,以及用一個字段來存儲標准答案(本次演示),也可以把答案存放入另外一個單獨的表中。
第三是,考員的答卷,需要存儲,在考試時間之內,可以更改自己的答案。因此此表的字段有 用戶ID,試題ID,答案,時間,其實真正的設計,也許需要考慮一個用戶可以考幾次,選擇的題庫等等...
本次演示,只是實現試題顯示,考員作答存儲,以及讀取等等功能,試題庫創建與產生,在此不作演示。
首先創建一個表,作為存儲單選項類型,主要是為了解決單選的選項多少,內容不一樣的情況。

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: Insus.NET -- Create date: 2013-07-17 -- Description: 單選項類別. -- ============================================= CREATE TABLE [dbo].[SingleChooseType] ( [sct_nbr] TINYINT IDENTITY(1,1) NOT NULL PRIMARY KEY, [Type] NVARCHAR(30) NOT NULL ) GO
單選項表:

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: Insus.NET -- Create date: 2013-07-17 -- Description: 單選項. -- ============================================= CREATE TABLE [dbo].[SingleChoose] ( [sc_nbr] TINYINT IDENTITY(1,1) NOT NULL PRIMARY KEY, [sct_nbr] TINYINT NOT NULL FOREIGN KEY REFERENCES [dbo].[SingleChooseType] ([sct_nbr]) [Content] NVARCHAR(30) ) GO
單選項試題:

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: Insus.NET -- Create date: 2013-07-17 -- Description: 單選試題。 -- ============================================= CREATE TABLE [dbo].[SC_Questions] ( [scq_nbr] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, [Questions] NVARCHAR(500) NOT NULL, [sct_nbr] TINYINT NOT NULL FOREIGN KEY REFERENCES [dbo].[SingleChooseType] ([sct_nbr]), [Std_Answer] TINYINT NULL FOREIGN KEY REFERENCES [dbo].[SingleChoose] ([sc_nbr]) --考慮到單選項項目多少,還是存儲key值。 )
下面為演示准備,創建一些選項類別,選項以及單選項試題。
選項類別中,Insus.NET創建四種類別,當然這些名字,任你自由發揮。
每種類別選項內容,看實際情況而定,來設定選項。
下面Insus.NET嘗試添加一些選擇題。
接下來,Insus.NET還要設計一張表,是存儲每一位考員的考試題。真正的考試,應該是考員對應題庫號,但現在只是演示單選,因此直接存儲選擇題目。在考員進入考試時,會把題目復制過來。表結構大約如下:

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: Insus.NET -- Create date: 2013-07-17 -- Description: 用戶考卷 -- ============================================= CREATE TABLE [dbo].[Test] ( [test_nbr] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, [User_Test_num] VARCHAR(20) NOT NULL, [scq_nbr] INT NOT NULL FOREIGN KEY REFERENCES [dbo].[SC_Questions] ([scq_nbr]), [Answer] TINYINT NULL --考員有可以不選擇,因此設為可空 --當然還有考試時間,是否提交考卷,得分成績,評卷情況..... ) GO
下面是用戶注冊成功之后,系統需要執行一個存儲過程,創建用戶的試題,或登錄考試系統之后,需要選擇一份試題。

-- ============================================= -- Author: Insus.NET -- Create date: 2013-07-17 -- Description: 用戶注冊成功系統產生試卷或是選擇一份試卷 -- ============================================= CREATE PROCEDURE [dbo].[usp_test_Examination] ( @User_Test_num VARCHAR(20) ) AS IF NOT EXISTS (SELECT TOP 1 1 FROM [dbo].[Test] WHERE [User_Test_num] = @User_Test_num) INSERT INTO [dbo].[Test] ([User_Test_num],[scq_nbr]) SELECT @User_Test_num,[scq_nbr] FROM [dbo].[SC_Questions] GO
OK,考員("EU_001")開始作題時,需要把試卷顯示於網頁上。

-- ============================================= -- Author: Insus.NET -- Create date: 2013-07-17 -- Description: 用戶作題試卷 -- ============================================= CREATE PROCEDURE [dbo].[usp_Test_GetByUser] ( @User_Test_num VARCHAR(20) ) AS --這里需要作些判斷,如是否提交,時間過期,試卷狀態等等。 SELECT [test_nbr],[User_Test_num],q.[scq_nbr],[Questions],[sct_nbr],[Answer] FROM [dbo].[Test] AS t LEFT JOIN [dbo].[SC_Questions] AS q ON (t.[scq_nbr] = q.[scq_nbr]) WHERE [User_Test_num] = @User_Test_num GO
他的試卷在數據庫初始信息如下:
在顯示考員題目時,還是把選擇顯示出來。

-- ============================================= -- Author: Insus.NET -- Create date: 2013-07-17 -- Description: 選項內容 -- ============================================= CREATE PROCEDURE [dbo].[usp_SingleChoose_GetByType] ( @sct_nbr TINYINT ) AS SELECT [sc_nbr],[sct_nbr],[Content] FROM [dbo].[SingleChoose] WHERE [sct_nbr] = @sct_nbr GO
為了試題與選項顯示於網頁上,Insus.NET兩個類別,能讓網頁與數據連接與通信,即是邏輯層的物件。

using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Web; /// <summary> /// Summary description for Test /// </summary> namespace Insus.NET { public class Test { private string user_number; public string UserNumber { get { return user_number; } set { user_number = value; } } BusinessBase objBusinessBase = new BusinessBase(); public Test() { // // TODO: Add constructor logic here // } public DataTable GetTestByUser() { Parameter[] param = { new Parameter ("@User_Test_num",SqlDbType.VarChar,-1,user_number) }; return objBusinessBase.GetDataToDataSet("usp_Test_GetByUser", param).Tables[0]; } } }

using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Web; /// <summary> /// Summary description for SingleChoose /// </summary> namespace Insus.NET { public class SingleChoose { private byte _type; public byte Type { get { return _type; } set { _type = value; } } BusinessBase objBusinessBase = new BusinessBase(); public SingleChoose() { // // TODO: Add constructor logic here // } public DataTable GetSingleChooseByType() { Parameter[] param = { new Parameter ("@sct_nbr",SqlDbType.TinyInt,1,_type) }; return objBusinessBase.GetDataToDataSet("usp_SingleChoose_GetByType", param).Tables[0]; } } }
試卷作答,全部選擇完成之后,再提交卷。為了更好的互動,Insus.NET把試題與選項分開實現,然后再組合。
為了解決網頁Page與用戶控件UserControl互動通信,Insus.NET在下面寫兩接口:
創建選項用戶控件:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Options.ascx.cs" Inherits="Options" %> <asp:RadioButtonList ID="RadioButtonListSingleChoose" runat="server" RepeatColumns="10" RepeatDirection="Horizontal"></asp:RadioButtonList>
在Options.ascx.cs代碼,需要實作上面兩個接口:
在顯示試題時,還要為每條單選題動態加載用戶控件,因此Insus.NET還得設計一個接口:
用戶控件OPtions再實作這個接口:
准備好了,我們顯示單選題目,使用輕量級的Repeater控件來呈現。
上面有兩個地方,一是OnItemDataBound事件,還有是PlaceHolder控件,是用來顯示選項的。
上圖中,序號0位,是找到Repeater控件的PlaceHolder控件。
序號1位,是動態加載用戶控件,並獲取用戶控件。
序號2位,是為用戶控件動態設置參數。
考員看到的單選項題,如下:
我們還要為考員所選擇的存儲起來。需要創建一個更新的存儲過程:

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: Insus.NET -- Create date: 2013-07-17 -- Description: 員選擇作答 -- ============================================= CREATE PROCEDURE [dbo].[usp_Test_UpdateAnswer] ( @test_nbr INT, @Answer TINYINT ) AS UPDATE [dbo].[Test] SET [Answer] = @Answer WHERE [test_nbr] = @test_nbr GO
由於Repeater控件沒有如GridView的DataKeyNames屬性,因此放一個HiddenField控件,還要添加一個銨鈕,讓用戶能交卷的動作。
上圖中的序號1,是獲取主鍵;序號2是獲取選擇的用戶控件;序號3是獲取用戶選擇的值。另外,你設計試卷時,應該是交卷之后,再不能看到試卷了,應該是提示信息已交卷。
如果考員作了如下選擇:
點擊“交卷”銨鈕之后,可以看到存儲數據表的數據:
好的,整篇的演示完成了。讓大家對RadioButtonList控件應用有所護展。本博文有涉及到數據庫,存儲過程,用戶控件,重點在於網頁與用戶控件之間的互通,這還涉及到接口,動態加載用戶控件,怎樣在Repeater控件外的銨鈕事件中獲取repeater控件內的一些值,如主鍵等。
其實,作為更好的試卷設計,應該讓考員能查看已經批改的試卷。系統應該是自動對比標准答案,來判斷錯與對。