环境:
vs2005+ActiveReportsNet2
本节代码下载:http://www.cnblogs.com/Files/batoosai/SimpleExample10.rar
学习了前面的一些基础,我们来实际开发一张帐票吧。
1,帐票式样
<!--[if !vml]-->
<!--[endif]-->
2,帐票说明:
1,抽出条件:
1-1班级:必選,多選
1-2科目:必選, 多選
2,用紙サイズ: A4 横
3,改頁条件:班级
4,印刷順序:行:生徒出席番号升排序
列:科目順位
4,如果某学生某subject没有成绩的话,也要显示该数据(只是把格子留空)
分析下帐票,我们应该用3个子模版(如下图,其中Sub3不需要取数,老师手动填)
<!--[if !vml]-->
<!--[endif]-->
3,好,我们项目一般的架构如下:
<!--[if !vml]-->
<!--[endif]-->
在我们的示例中,方便起见,就用简单的3层架构吧,当中的web service去掉。创建Project如图:
<!--[if !vml]-->
<!--[endif]-->
1)表示层:Form,ARTemplate
2)业务逻辑层:BR
3)数据层:DA
4,数据库如下:
<!--[if !vml]-->
<!--[endif]-->
具体数据表的数据:
1)Class
Class | |||
ClassID | ClassName | TeacherName | DisplayOrder |
1 | A班 | Tony Gong | 1 |
2 | B班 | Tony Wang | 2 |
3 | C班 | Tony Li | 3 |
2)Student
Student | |||
StudentID | ClassID | No | Name |
11 | 1 | 1 | Tony |
12 | 1 | 2 | Zhu |
13 | 1 | 3 | Li |
14 | 1 | 4 | Zhang |
15 | 1 | 5 | Zha |
16 | 1 | 6 | Sun |
21 | 2 | 1 | Wang |
22 | 2 | 2 | Gong |
23 | 2 | 3 | Tian |
24 | 2 | 4 | Su |
25 | 2 | 5 | Xiao |
31 | 3 | 1 | Xu |
32 | 3 | 2 | Liu |
33 | 3 | 3 | Tom |
34 | 3 | 4 | Mary |
3)Subject
Subject | ||
SubjectID | SubjectName | DisplayOrder |
1 | 古典 | 1 |
2 | 現代文 | 2 |
3 | 語文 | 3 |
4)Score
Score | ||||
ScoreID | StudentID | SubjectID | Score | GradeOrder |
1 | 11 | 1 | 70 | 11 |
2 | 11 | 2 | 75 | 23 |
3 | 11 | 3 | 55 | 1 |
4 | 12 | 1 | 6 | 15 |
5 | 12 | 2 | 77 | 6 |
6 | 13 | 1 | 8 | 6 |
7 | 13 | 2 | 77 | 7 |
8 | 13 | 3 | 66 | 8 |
9 | 14 | 1 | 55 | 9 |
10 | 14 | 3 | 44 | 10 |
11 | 15 | 2 | 32 | 11 |
12 | 16 | 3 | 100 | 12 |
13 | 21 | 1 | 11 | 13 |
14 | 21 | 2 | 14 | 14 |
15 | 21 | 3 | 15 | 1 |
16 | 22 | 1 | 16 | 2 |
17 | 22 | 2 | 76 | 3 |
18 | 22 | 3 | 18 | 4 |
19 | 23 | 1 | 99 | 5 |
20 | 23 | 3 | 89 | 6 |
21 | 24 | 1 | 21 | 7 |
22 | 25 | 1 | 44 | 8 |
23 | 31 | 1 | 23 | 9 |
24 | 31 | 2 | 24 | 10 |
25 | 32 | 1 | 25 | 1 |
26 | 32 | 3 | 26 | 2 |
27 | 33 | 1 | 27 | 3 |
28 | 34 | 1 | 28 | 4 |
29 | 34 | 2 | 29 | 5 |
30 | 34 | 3 | 30 | 6 |
5,ok,开工,先add 如下文件
<!--[if !vml]-->
<!--[endif]-->
其中Form中
frmScore让用户选择抽出条件
frmShowAR用来显示report
6,在form上放2个多选的条件控件,Class和Subject。
实际项目中,这2个控件的内容应该取数据表里的值。我这里方便起见,直接把值写死在控件上。
<!--[if !vml]-->
<!--[endif]-->
btnPreview的click事件如下:
If Me .listClass.SelectedIndex = - 1 OrElse Me .listSubject.SelectedIndex = - 1 Then
Return
End If
' Get the Parameter
Dim classID As String = ""
Dim subjectID As String = ""
For index As Int32 = 0 To Me .listClass.SelectedIndices.Count - 1
classID &= Me .listClass.SelectedIndices(index) + 1 & " , "
Next
For index As Int32 = 0 To Me .listSubject.SelectedIndices.Count - 1
subjectID &= Me .listSubject.SelectedIndices(index) + 1 & " , "
Next
classID = classID.TrimEnd(Convert.ToChar( " , " ))
subjectID = subjectID.TrimEnd(Convert.ToChar( " , " ))
' Send parameters to the BR and get the dataset.
Dim br As New BR.brScore()
Dim finalDS As DataSet = br.GetData(classID, subjectID)
' Send dataset to the form
Dim frm As New frmShowAR(finalDS)
frm.Show()
End Sub
7,br层,由于业务太简单了,代码很简单。
Try
' 創建DA
Dim objDA As New DA.daScore()
Dim ds As DataSet = objDA.GetData(classID, subjectID)
' 返回値
Return ds
Catch ex As Exception
' 抛出異常
Throw ex
End Try
End Function
8, DA层,根据参数执行sql语句,返回结果Dataset
DA的任务,是根据参数,作select语句,得出2张table,放到ds中return。
假设Class选了”B,C”,Subject选了”古典,现代文”
其中table1(用于Sub1和主模版)数据应该如下:(9条记录)
Query1 | |||||||
Class.ClassID | ClassName | TeacherName | DisplayOrder | StudentID | Student.ClassID | No | Name |
2 | B班 | Tony Wang | 2 | 21 | 2 | 1 | Wang |
2 | B班 | Tony Wang | 2 | 22 | 2 | 2 | Gong |
2 | B班 | Tony Wang | 2 | 23 | 2 | 3 | Tian |
2 | B班 | Tony Wang | 2 | 24 | 2 | 4 | Su |
2 | B班 | Tony Wang | 2 | 25 | 2 | 5 | Xiao |
3 | C班 | Tony Li | 3 | 31 | 3 | 1 | Xu |
3 | C班 | Tony Li | 3 | 32 | 3 | 2 | Liu |
3 | C班 | Tony Li | 3 | 33 | 3 | 3 | Tom |
3 | C班 | Tony Li | 3 | 34 | 3 | 4 | Mary |
table2(用于Sub2)数据应该这样做:
9条生徒 * 2门科目,然后left join Score的内容,最终得到18条记录(假如某人某科没成绩的话,该字段也会显示出来,只是留空而已)。
<!--[if !vml]-->
<!--[endif]-->
PS:由于Access的Left join 俺实在是搞不懂,没法做left join,所以只能把Score的纪录填满,然后用普通查询。
再PS:Access的参数化查询我也搞不太清楚,所以代码中直接把”@classid”等替换成字符串了。
最后的PS:假如是mssql的话,sub2的查询语句大概如下:
Select * from student,class
cross join Subject
left join score
on score.subjectID=Subject.SubjectID
and score.StudentID=student.StudentID
Where s.ClassID=c.ClassID
And c.ClassID in (@ClassID)
<!--[if !vml]-->
<!--[endif]-->
Sub3就不需要查寻了。
9,frmShowAR接收到数据源,并显示帐票
Sub New ( ByVal ds As DataSet)
Me .finalDS = ds
' 此调用是 Windows 窗体设计器所必需的。
InitializeComponent()
' 在 InitializeComponent() 调用之后添加任何初始化。
End Sub
Private finalDS As DataSet
Private Sub frmShowAR_Load( ByVal sender As Object , ByVal e As System.EventArgs) Handles Me .Load
Dim rpt As New ARTemplate.rptScore
rpt.DataSource = finalDS
rpt.DataMember = finalDS.Tables( 0 ).TableName
' A4 Landscape
rpt.PageSettings.PaperKind = Printing.PaperKind.A4
rpt.PageSettings.Orientation = DataDynamics.ActiveReports.Document.PageOrientation.Landscape
rpt.Run()
Me .Viewer1.Document = rpt.Document
End Sub
End Class
10,主模版和子模版主要属性及代码(完整的请看下载的代码)
1),主模版
<!--[if !vml]-->
<!--[endif]-->
GroupHeader1:DataFied=”ClassID”
NewPage=”Before”
txtClassNo: DataField=”ClassName”
txtTeacher: DataField=”TeacherName”
代码:
Report_start中布局代码
Detail_Format里的生成子模版的代码:
2),Sub1
<!--[if !vml]-->
<!--[endif]-->
txtID:DataField=”No”
txtName:DataField=”Name”
3),Sub2
<!--[if !vml]-->
<!--[endif]-->
GroupHeader1:DataField=” SubjectID”
NewPage=”Before”
lblSubject:DataField=”SubjectName”
txtScore:Datafield=”Score”
txtOrder:Datafield=”gradeOrder”
4),Sub3
<!--[if !vml]-->
<!--[endif]-->
11,最终效果,比较粗糙,大家自己改进吧。
<!--[if !vml]-->
<!--[endif]-->
' subReport1
Dim sub1 As New sub1
Me .subReport1.Report = sub1
' 為子報表設置数据源
Dim dvStudent As DataView = New DataView( CType ( Me .DataSource, DataSet).Tables( 0 ), " ClassID=' " & Me .Fields( " ClassID " ).Value.ToString & " ' " , "" , DataViewRowState.CurrentRows)
Me .subReport1.Report.DataSource = dvStudent
' subReport2
Dim sub2 As New sub2
Me .subReport2.Report = sub2
' 為子報表設置数据源
Dim dvScore As DataView = New DataView( CType ( Me .DataSource, DataSet).Tables( 1 ), " ClassID=' " & Me .Fields( " ClassID " ).Value.ToString & " ' " , "" , DataViewRowState.CurrentRows)
With CType ( Me .subReport2.Report, sub2)
.DataSource = dvScore
' Set subReport's ColumnCount
.RealColumnCount = CInt (dvScore.Count / dvStudent.Count)
End With
' subReport3
Dim sub3 As New sub3
Me .subReport3.Report = sub3
Me .subReport3.Report.DataSource = dvStudent
End Sub
' <--------Step (1)---------->
' Set contols' width
' me.lblClass.Width=xxx
'
'
' <--------Step (1)---------->
' <--------Step (2)---------->
' Arrange Controls.
Me .lblYear.Left = 0.5
Me .lblYear.Top = 0.5
Me .txtClassNo.Left = Me .lblYear.Left
Me .txtClassNo.Top = Me .lblYear.Top + Me .lblYear.Height
Me .Label3.Left = Me .txtClassNo.Left + Me .txtClassNo.Width * 2
Me .Label3.Top = Me .txtClassNo.Top
Me .txtTeacher.Left = Me .Label3.Left + Me .Label3.Width
Me .txtTeacher.Top = Me .Label3.Top
' <--------Step (2)---------->
' <--------Step (3)---------->
Dim sub1 As New sub1
Me .subReport1.Width = sub1.ReportWidth
Dim sub2 As New sub2
With CType ( Me .DataSource, DataSet)
Me .subReport2.Width = sub2.ReportWidth * CInt (.Tables( 1 ).Rows.Count / .Tables( 0 ).Rows.Count)
End With
Dim sub3 As New sub3
Me .subReport3.Width = sub3.reportWidth
' <--------Step (3)---------->
' <--------Step (4)---------->
Me .subReport1.Left = Me .txtClassNo.Left
Me .subReport1.Top = Me .txtClassNo.Top + Me .txtClassNo.Height
Me .subReport2.Left = Me .subReport1.Left + Me .subReport1.Width
Me .subReport2.Top = Me .subReport1.Top
Me .subReport3.Left = Me .subReport2.Left + Me .subReport2.Width
Me .subReport3.Top = Me .subReport1.Top
' <--------Step (4)---------->
' <--------Step (5)---------->
' Set all sections & PrintWidth
Me .PageHeader.Height = Me .TextBox2.Height
Me .Detail.Height = 0
' <--------Step (5)---------->
' <--------Step (6)---------->
' Set PrintWidth
Dim realWidth As Single = Me .subReport3.Left + Me .subReport3.Width
Dim defaultWidth As Single
If PageSettings.Orientation = PageOrientation.Portrait Then
defaultWidth = PageSettings.PaperWidth - PageSettings.Margins.Left - PageSettings.Margins.Right
Else
defaultWidth = PageSettings.PaperHeight - PageSettings.Margins.Left - PageSettings.Margins.Right
End If
If realWidth > defaultWidth Then
Me .PrintWidth = realWidth
Else
Me .PrintWidth = defaultWidth
End If
' <--------Step (6)---------->
End Sub