Crystal Report報表開發(七)_缺列補空白_Runtime參數設置_公式設置_避免多浪費空白頁的後端程式修正

 

在很久之前由於接獲需要用水報翻升廠內用ActiveX舊版報表程式

因而遇到有點挑戰的報表程式設計




特徵:

有格子框住頁首頁尾

每頁20筆(缺列補空白)

轉用水晶報表

有格子框住頁首頁尾 ==>可插入方塊




問題1.每頁20筆(缺列補空白)

這裡就先解決空白列問題,由於Crystal Report 設定細目(詳細資料)
資料源頭時候,主要透過ReportDocument物件SetDataSource的
方法,其中一個overload型態可以Assign DataTable。
這裡自定義一個回傳DataTable的Function,命名為
GetTableWithInSufficientEmptyRow
(考量到當只有一頁或不只一頁的問題)

傳入原本兜好資料的DataTable(可能11筆or55筆這種...剛好不足
每頁預顯示的基數的)
傳入每頁預指定顯示的資料筆數(目前驗證
當每頁水晶報表只有一個Grid時候最大可設到22,這裡設定20)==>設定每頁顯示列數請參考上一篇針對細目的公式設定


程式
 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
''' <summary>
    ''' 自動湊滿每頁N筆,缺列補空白列
    ''' </summary>
    ''' <param name="tbGridData"></param>
    ''' <param name="RowCountEachPage"></param>
    ''' <returns></returns>
    Function GetTableWithInSufficientEmptyRow(tbGridData As DataTable, RowCountEachPage As Integer) As DataTable
        Dim TotalDataRowNum As Integer = tbGridData.Rows.Count
        Dim TotalPageNum As Integer = Math.Ceiling(TotalDataRowNum / 20) ' 55 / 20 = 2.75 -> 3 
        'Math.Ceiling(2.5) -> 3
        'Math.Ceiling(2.3) -> 3

        '新增一個新的DataTable,所有Column DataType 都是string格式
        Dim tbNewGridData As New DataTable
        Dim arrDataCol(tbGridData.Columns.Count - 1) As DataColumn
        tbGridData.Columns.CopyTo(arrDataCol, 0)
        For idxColName As Integer = 0 To UBound(arrDataCol)
            tbNewGridData.Columns.Add(tbGridData.Columns.Item(idxColName).ColumnName, GetType(String))
        Next
        '將原先有不同dataType的資料表存入新定義的All-String Type DataTable
        Dim idxRow As Integer = -1
        For Each rowOrig As DataRow In tbGridData.Rows
            idxRow += 1
            Dim drTmp As DataRow = tbNewGridData.NewRow()
            Dim idxCol As Integer = -1
            For Each itemData As Object In rowOrig.ItemArray
                idxCol += 1
                drTmp.Item(tbNewGridData.Columns.Item(idxCol).ColumnName) = If((IsNothing(itemData) Or IsDBNull(itemData)), " ", itemData.ToString())
            Next
            tbNewGridData.Rows.Add(drTmp)
        Next

        '不足的資料列用空字串塞入確保每頁都有20列(缺項補空白資料項)
        '若總共只有11筆則補足到20 -> 補9列空白
        '若總共只有55筆則補足到60 -> 補5列空白 ....依此類推
        Dim InSufficientRowCount As Integer = 0
        If TotalPageNum = 1 Then
            If tbGridData.Rows.Count < RowCountEachPage Then
                InSufficientRowCount = RowCountEachPage - TotalDataRowNum
            End If
        Else
            '(RowCountEachPage * TotalPageNum) = 20 * 3 - 55
            InSufficientRowCount = (RowCountEachPage * TotalPageNum) - TotalDataRowNum
        End If
        For idxInSufficRow As Integer = 0 To InSufficientRowCount - 1
            Dim drTmp As DataRow = tbNewGridData.NewRow()
            For idxCol As Integer = 0 To UBound(arrDataCol)
                drTmp.Item(tbNewGridData.Columns.Item(idxCol).ColumnName) = " "
            Next
            tbNewGridData.Rows.Add(drTmp)
        Next

        Return tbNewGridData
    End Function


所以新回傳的DataTable主要會將原始資料的DataTable物件
轉為全部Column Data Type皆需要是字串的型態(備註:在.NET由於型態敏感,因
空白列若要指定空字串一定都要先轉Data Type)
而當補充空白列的時候又會有資料錄編號把空白列也自動編號的問題產生。






問題2.空白列也會產生出自動列號

接著遇到的問題目前邏輯撈到的資料就只有11筆(這裡自動編號採用特殊欄位==>資料錄編號)

這方法會有個問題空白列也會產生出自動列號!!!




這裡需要用到水晶報表兩個技巧
(1)Runtime設定參數
選擇.rpt報表設計的定義專案後=>到欄位總管下的參數欄位
新增自定義參數,這裡型態我設成數字,由於後續公式中要拿來做數字比對。




我們希望水晶報表在Runtime期間接收實際原始資料真實資列列總數(尚未補足空白列)
這邊務必要注意SetParameterValue一定要放在SetDataSource之後,不然會跳要人輸入的窗。






(2)設定公式
對資料錄(特殊欄位)右鍵選物件格式=>切分頁看到抑制顯示後面的x-2點按進去編寫公式
回傳true代表使其在特定條件不會顯示內容
設定完要記得先按儲存關閉然後確定(有兩次要按!!!!)






問題3.多印出空白浪費的紙張頁


看起來一切都很安穩了結果放上去運行幾個月就有特殊異常發生

多印出空白頁

因此只能想一下修正方法

原來是因為品名(該欄位有設置CanGrow)有的太長導致頁面多跑出一張空白的....>~<

思路首先我要先有辦法得知目前水報給我自動弄出來的總頁數是幾張



透過ReportViewer當中可以跳至最後一頁的方法

我們在去取該頁碼即可得知Total Page Count


之後是處理浪費頁的校正函數

透過遞迴查檢扣掉多餘(補)的資料列

 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
Sub ProcessWastePage(ByVal RealRecordNum As Integer, ByVal PerPageNum As Integer,
                         ByVal TotalReportPageInRunTime As Integer,
                         ByVal docReport As ReportDocument,
                         ByVal tbDetail As DataTable,
                         ByVal dicParam As Dictionary(Of String, Object),
                         ByVal RpttViewer As CrystalDecisions.Web.CrystalReportViewer,
                         Optional ByVal IsHaveParam As Boolean = False)
        Dim ReportPageWaste As Boolean = False
        '判斷[總頁數若不只一張] 且 [倒數第二頁資料筆數不滿實際資料筆數]
        If TotalReportPageInRunTime > 1 And RealRecordNum < PerPageNum Then
            '原本拿捏是每頁13列(缺列捕空白),若資料只有8列就補5列空白Record給Detail Section。
            'Case1.兩張的情況
            'Page1 -> 8筆資料(補4列空白列)
            'Page2 -> 1筆空白列
            Dim NewPerPageNum As Integer = PerPageNum - 1
            Dim tbReimburseDetailWithEmptyNew As DataTable = GetTableWithInSufficientEmptyRow(tbDetail, NewPerPageNum)
            docReport.SetDataSource(tbReimburseDetailWithEmptyNew)

            If IsHaveParam Then
                If dicParam.Keys.Count > 0 Then
                    For Each itemParam As KeyValuePair(Of String, Object) In dicParam
                        docReport.SetParameterValue(itemParam.Key, itemParam.Value)
                    Next
                End If
            End If
            IsHaveParam = dicParam.Count > 0
            RpttViewer.ReportSource = docReport
            RpttViewer.ShowLastPage()
            Dim TotalPageNum As Integer = RpttViewer.ViewInfo.PageNumber
            ProcessWastePage(tbDetail.Rows.Count, NewPerPageNum, TotalPageNum, docReport, tbDetail, dicParam, RpttViewer, IsHaveParam)
        End If
    End Sub



留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header