考试系统开发总结(二)——实现、代码

这篇主要讲讲怎么实现之前的设计,之前设计有2个问题要首先解决,不然没办法继续搞:1、多层对象结构在asp.net页面上的表达和数据收集 2、多层对象的持久化保存和还原。这两个问题其实都是一个事情:复杂的对象结构如何表现和更新。

首先设计图出来后还是建立数据库、生成O/R mapping,我使用的MultiTierLinqToSql作为DAL,泛化的Linq2Sql底层,控制类Controller只需要继承基类并指定实体类,就可以得到Insert()、Update()、Delete()、GetList()等等方法了,不用写什么代码,超级方便!(关于MultiTierLinqToSql将来会有文章专门介绍)

然后是建立类型,编写类型的属性等等,包括对象间关系全部设置好。

再次是把持久化相关部分都写起来,包括数据库持久化部分和XML持久化。

之后编译完成了就成了下面的这个图,这个图只保留了最核心的部分,其他的太多了就省略掉了。

类的实现代码

至此,做了个测试,把testpaper进行了XML持久化保存,得到的XML文件类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-16"?>
<TestPaper xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Title>测试试卷标题</Title>
  <Description>默认的试卷描述说明</Description>
  <Point>150</Point>
  <Time>60</Time>
  <TopicCollection>
    <TopicBase xsi:type="RandomTopic">
      <Title>测试的一个题目类型(选择题)</Title>
      <Type>Choice</Type>
      <Count>10</Count>
      <EachPoint>5</EachPoint>
      <Subject>Other</Subject>
    </TopicBase>
    <TopicBase xsi:type="RandomTopic">
      <Title>问答题</Title>
      <Type>Question</Type>
      <Count>20</Count>
      <EachPoint>2</EachPoint>
      <Subject>Management</Subject>
    </TopicBase>
  </TopicCollection>
</TestPaper>

可以序列化了,做到了第一步,后面是更加艰巨,显示渲染到页面,当然是用repeater这种控件,一层层嵌套和绑定,具体操作的比较简单,就是绑定后用item.FindControl()来找到子控件的repeater,再绑定,再找子控件,反正就是3-4层,写几次确实有点麻烦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<asp:Repeater runat="server" ID="rptTopic" OnItemDataBound="rptTopic_OnItemDataBound">
            <HeaderTemplate> <ol> </HeaderTemplate>
            <ItemTemplate>
                <strong class="topicTitle"><%#Eval("Title") %></strong> (每题<%#Eval("EachPoint")%>分,共<%#Eval("Count")%>题)</li>
                <asp:Repeater runat="server" ID="rptChoice">
                    <HeaderTemplate> <ol> </HeaderTemplate>
                    <ItemTemplate>
                        <uc1:choice ID="choice" runat="server" Choice='<%#Eval("MatterGeneric") %>' />
                    </ItemTemplate>
                    <FooterTemplate> </ol> </FooterTemplate>
                </asp:Repeater>
                <asp:Repeater runat="server" ID="rptJudge">
                    <HeaderTemplate> <ol> </HeaderTemplate>
                    <ItemTemplate>
                        <uc3:judge ID="judge" runat="server" Judge='<%#Eval("MatterGeneric") %>' />
                    </ItemTemplate>
                    <FooterTemplate> </ol> </FooterTemplate>
                </asp:Repeater>
                <asp:Repeater runat="server" ID="rptFillblank">
                    <HeaderTemplate> <ol> </HeaderTemplate>
                    <ItemTemplate>
                        <uc2:fillblank ID="fillblank" runat="server" Fillblank='<%#Eval("MatterGeneric") %>' />
                    </ItemTemplate>
                    <FooterTemplate> </ol> </FooterTemplate>
                </asp:Repeater>
                <asp:Repeater runat="server" ID="rptQuestion">
                    <HeaderTemplate> <ol> </HeaderTemplate>
                    <ItemTemplate>
                        <uc4:question ID="question" runat="server" Question='<%#Eval("MatterGeneric") %>' />
                    </ItemTemplate>
                    <FooterTemplate> </ol> </FooterTemplate>
                </asp:Repeater>
            </ItemTemplate>
            <FooterTemplate> </ol> </FooterTemplate>
        </asp:Repeater>

其中最子一级用了userControl,是具体显示题目内容的,比如选择、填空、判断、问答,由它们完成继承类多态的表达,还有数据的收集。直接把对象绑到子控件的属性上,具体里面是怎么实现就不用调用的页面来操心了,如果想更泛化一点,需要对这种控件要求接口。不过目前是原型设计,要求还不那么高,就硬编码就可以了。

1
2
3
4
5
6
7
8
<li> <strong> </asp:Literal runat="server" ID="litTitle"> </strong> </li>
<asp:Repeater runat="server" ID="rpt">
<HeaderTemplate> <ol> </HeaderTemplate>
<ItemTemplate>
<li class="option"> </asp:Label runat="server" ID="lab" AssociatedControlID="cbx" Text='<%#Eval("Content")%>'> <asp:CheckBox ID="cbx" runat="server" /> </li>
</ItemTemplate>
<FooterTemplate> </ol> </FooterTemplate>
</asp:Repeater>

1
2
3
4
5
6
7
8
9
10
11
12
13
    public Choice Choice { get; set; }
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Choice != null)
        {
            litTitle.Text = Choice.Title;
            rpt.DataSource = Choice.Option;
            if (!Page.IsPostBack)
            {
                rpt.DataBind();
            }
        }
    }

数据收集有点麻烦,我在绑定的时候在用户控件的中提供了些输入框,但如何采集呢,先想的是用IPostBackXXXX接口,但实现起来不是很靠谱,还有什么ViewState什么的状态,受到Page的IsPostback的限制等等,后来想了个办法,直接在子控件中提供一个Readonly的属性,Page需要获取子控件信息的时候,通过属性去获取,而.net的属性其实是属性方法,会在要求获取时执行,就完成了数据的采集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public List<int> OptionIndexs
    {
        get
        {
            List<int> idx = new List<int>();
            for (int i = 0; i < rpt.Items.Count; i++)
            {
                CheckBox cbx = rpt.Items[i].FindControl("cbx") as CheckBox;
                if (cbx != null && cbx.Checked)
                {
                    idx.Add(i);
                }
            }
            return idx;
        }
    }

最后,在Page的提交时,只要使用下面的代码,对绑定的子控件进行遍历,就能取得所有子控件对象(对象引用)或者对象属性,进行组合后就可以持久化了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
            for (int it = 0; it < rptTopic.Items.Count; it++)
            {
                Repeater rpt = rptTopic.Items[it].FindControl("rptChoice") as Repeater;
                if (rpt != null)
                {
                    for (int i = 0; i < rpt.Items.Count; i++)
                    {
                        ASP.ocx_paper_choice_ascx choiceUC = rpt.Items[i].FindControl("choice") as ASP.ocx_paper_choice_ascx;
                        if (choiceUC != null)
                        {
                            Choice choice = ap.TopicCollection[it].MatterCollection[i].MatterGeneric as Choice;
                            choiceUC.OptionIndexs.ForEach(delegate(int w)
                            {
                                choice.Option[w].Answer = true;
                            });
                        }
                    }
                }
            }

至此,最麻烦的两个问题就解决了。核心逻辑都实现后,再对表现层的用户体验进行优化,很快,项目的大头朝下了。

 

考试系统开发总结(一)——计划、设计

考试系统开发总结(二)——实现、代码

考试系统开发总结(三)——精华、结论

posted @ 2009-08-31 13:10  肖坤  阅读(440)  评论(2编辑  收藏  举报