2013年3月24日 星期日

[技巧] 動態更改 ReportViewer.LocalReport.ReportPath


Me.ReportViewer1.Reset()
'組件路徑 (不必將 report檔 ".rdlc" 丟到實際資料夾底下...)
Me.ReportViewer1.LocalReport.ReportEmbeddedResource = "eHRsys.Report2.rdlc"  

Note:
eHRsys.Report2.rdlc
組件名稱.檔案名稱.檔案副檔名

參考:
[MSDN]LocalReport.ReportPath 屬性
如何動態更換ReportViewer的RDLC及DataSource
收藏 RDLC动态绑定问题
如何使用LocalReport - WebForm (3)
动态的rdlc报表
顯示整頁模式
The WinForms ReportViewer and Multiple Report Definition Files
Binding DataSet and Generic *.rdlc Reports to a ReportViewer at Runtime

2013年3月20日 星期三

[學習] ReportViewer Drill-Through Reports 鑽研報表 (大陸譯:钻取报表)

主體屬性 與 報表屬性
報表規格A4紙 21寬 29.7長
邊界都為0


CODE:使用 自定義事件 DemoDrillthroughEventHandler
Imports Microsoft.Reporting.WinForms
Public Class Printer_Salary
    Private orderDetailsData As DataTable = Nothing
    Function LoadOrderDetailsData(ByVal a As String) As DataTable
        Dim salaryM As New Class_conn(ConnRegNfunction.connMode, _
                            ConnRegNfunction.連線字串Local, _
                            ConnRegNfunction.連線字串WebUri)
        Dim salaryDT = salaryM.DataTable("SELECT s.*,e.zhFname + e.zhName as 姓名,b.account FROM dbo.salaryM as s left join dbo.employee as e on s.staff_sn = e.staff_sn left join dbo.bank as b on s.staff_sn = b.staff_sn where s.staff_sn = " & a & " and s.ym = " & ComboBox3.Text.Trim & ComboBox2.Text.Trim & " and s.第幾次發薪 = " & TextBox1.Text.Trim & "", Nothing, Nothing)
        salaryM.Dispose()
        Return salaryDT
    End Function

    Private Sub DemoDrillthroughEventHandler(ByVal sender As System.Object, ByVal e As DrillthroughEventArgs)
        Dim myLocalReport As LocalReport
        myLocalReport = e.Report
        orderDetailsData = LoadOrderDetailsData(myLocalReport.GetParameters()("Report_Parameter_3").Values(0).Trim)
        myLocalReport.DataSources.Add(New ReportDataSource("yiTestDataSet_salaryM1", orderDetailsData))
    End Sub

    Private Sub Printer_Salary_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.ReportViewer1.RefreshReport()
    End Sub

    Private Sub Printer_Salary_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.FixedSingle

        Dim month() As String = {"01", "02", "03", "04", "05", "06", _
                                    "07", "08", "09", "10", "11", "12"}
        ComboBox2.Items.AddRange(month)

        For i As Integer = 2010 To Integer.Parse(Now.Date.Year.ToString)
            ComboBox3.Items.Add(i)
        Next

        ComboBox3.Text = Now.Date.Year.ToString
        ComboBox3.DropDownStyle = ComboBoxStyle.DropDown
        ComboBox3.AutoCompleteMode = AutoCompleteMode.SuggestAppend
        ComboBox3.AutoCompleteSource = AutoCompleteSource.ListItems

        ComboBox2.Text = Now.Date.Month.ToString("00")
        ComboBox2.DropDownStyle = ComboBoxStyle.DropDown
        ComboBox2.AutoCompleteMode = AutoCompleteMode.SuggestAppend
        ComboBox2.AutoCompleteSource = AutoCompleteSource.ListItems

        ComboBox1.SelectedIndex = 0

        Call Button1_Click(Me, Nothing)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim salaryM As New Class_conn(ConnRegNfunction.connMode, _
                            ConnRegNfunction.連線字串Local, _
                            ConnRegNfunction.連線字串WebUri)
        Dim salaryDT = salaryM.DataTable("SELECT s.*,e.zhFname + e.zhName as 姓名,b.account FROM dbo.salaryM as s left join dbo.employee as e on s.staff_sn = e.staff_sn left join dbo.bank as b on s.staff_sn = b.staff_sn where s.ym = " & ComboBox3.Text.Trim & ComboBox2.Text.Trim & " and s.第幾次發薪 = " & TextBox1.Text.Trim & "", Nothing, Nothing)
        Dim rds As ReportDataSource = New ReportDataSource("yiTestDataSet_salaryM", salaryDT) 
        ReportViewer1.LocalReport.DataSources.Clear()
        ReportViewer1.LocalReport.DataSources.Add(rds)

        Dim rp1 As ReportParameter = _
        New ReportParameter("Report_Parameter_0", ComboBox3.Text.Trim)
        Dim rp2 As ReportParameter = _
        New ReportParameter("Report_Parameter_1", ComboBox2.Text.Trim)
        Dim rp3 As ReportParameter = _
        New ReportParameter("Report_Parameter_2", TextBox1.Text.Trim)

        ReportViewer1.LocalReport.SetParameters(New ReportParameter() {rp1})
        ReportViewer1.LocalReport.SetParameters(New ReportParameter() {rp2})
        ReportViewer1.LocalReport.SetParameters(New ReportParameter() {rp3})

  AddHandler ReportViewer1.Drillthrough, AddressOf DemoDrillthroughEventHandler

        ReportViewer1.RefreshReport()
        salaryM.Dispose()
    End Sub
End Class

CODE:使用報表事件 ReportViewer1_Drillthrough
Imports Microsoft.Reporting.WinForms
Public Class Printer_Salary
    Private orderDetailsData As DataTable = Nothing
    Function LoadOrderDetailsData(ByVal a As String) As DataTable
        Dim salaryM As New Class_conn(ConnRegNfunction.connMode, _
                            ConnRegNfunction.連線字串Local, _
                            ConnRegNfunction.連線字串WebUri)
        Dim salaryDT = salaryM.DataTable("SELECT s.*,e.zhFname + e.zhName as 姓名,b.account FROM dbo.salaryM as s left join dbo.employee as e on s.staff_sn = e.staff_sn left join dbo.bank as b on s.staff_sn = b.staff_sn where s.staff_sn = " & a & " and s.ym = " & ComboBox3.Text.Trim & ComboBox2.Text.Trim & " and s.第幾次發薪 = " & TextBox1.Text.Trim & "", Nothing, Nothing)
        salaryM.Dispose()
        Return salaryDT
    End Function

    Private Sub Printer_Salary_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.ReportViewer1.RefreshReport()
    End Sub

    Private Sub Printer_Salary_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.FixedSingle
        Dim month() As String = {"01", "02", "03", "04", "05", "06", _
                                    "07", "08", "09", "10", "11", "12"}
        ComboBox2.Items.AddRange(month)

        For i As Integer = 2010 To Integer.Parse(Now.Date.Year.ToString)
            ComboBox3.Items.Add(i)
        Next

        ComboBox3.Text = Now.Date.Year.ToString
        ComboBox3.DropDownStyle = ComboBoxStyle.DropDown
        ComboBox3.AutoCompleteMode = AutoCompleteMode.SuggestAppend
        ComboBox3.AutoCompleteSource = AutoCompleteSource.ListItems

        ComboBox2.Text = Now.Date.Month.ToString("00")
        ComboBox2.DropDownStyle = ComboBoxStyle.DropDown
        ComboBox2.AutoCompleteMode = AutoCompleteMode.SuggestAppend
        ComboBox2.AutoCompleteSource = AutoCompleteSource.ListItems

        ComboBox1.SelectedIndex = 0
        Call Button1_Click(Me, Nothing)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim salaryM As New Class_conn(ConnRegNfunction.connMode, _
                            ConnRegNfunction.連線字串Local, _
                            ConnRegNfunction.連線字串WebUri)
        Dim salaryDT = salaryM.DataTable("SELECT s.*,e.zhFname + e.zhName as 姓名,b.account FROM dbo.salaryM as s left join dbo.employee as e on s.staff_sn = e.staff_sn left join dbo.bank as b on s.staff_sn = b.staff_sn where s.ym = " & ComboBox3.Text.Trim & ComboBox2.Text.Trim & " and s.第幾次發薪 = " & TextBox1.Text.Trim & "", Nothing, Nothing)
        Dim rds As ReportDataSource = New ReportDataSource("yiTestDataSet_salaryM", salaryDT) 
        ReportViewer1.LocalReport.DataSources.Clear()
        ReportViewer1.LocalReport.DataSources.Add(rds)

        Dim rp1 As ReportParameter = _
        New ReportParameter("Report_Parameter_0", ComboBox3.Text.Trim)
        Dim rp2 As ReportParameter = _
        New ReportParameter("Report_Parameter_1", ComboBox2.Text.Trim)
        Dim rp3 As ReportParameter = _
        New ReportParameter("Report_Parameter_2", TextBox1.Text.Trim)

        ReportViewer1.LocalReport.SetParameters(New ReportParameter() {rp1})
        ReportViewer1.LocalReport.SetParameters(New ReportParameter() {rp2})
        ReportViewer1.LocalReport.SetParameters(New ReportParameter() {rp3})

        ReportViewer1.RefreshReport()
        salaryM.Dispose()
    End Sub

    Private Sub ReportViewer1_Drillthrough(ByVal sender As System.Object, ByVal e As Microsoft.Reporting.WinForms.DrillthroughEventArgs) Handles ReportViewer1.Drillthrough
        Dim myLocalReport As LocalReport
        myLocalReport = e.Report
        'If orderDetailsData Is Nothing Then'

        orderDetailsData = LoadOrderDetailsData(myLocalReport.GetParameters()("Report_Parameter_3").Values(0).Trim)

        'End If'
        myLocalReport.DataSources.Add(New ReportDataSource("yiTestDataSet_salaryM1", orderDetailsData))
    End Sub
End Class

步驟:
STEP1.
各自建立報表 report1.rdlc & report2.rdlc 及報表來源

注意:
報表來源不可以有沒使用到的數據來源
不然會一直出錯,沒有 DataSet_dt 數據來源



STEP2.
在父報表Report2設定
欄位導覽 跳至報表Report1 (所要鑽取的報表)
並設定要給予的參數(Report_Parameter_3 參數值 是此欄位的值)
(此參數在 Report1 及 Report2 參數名稱要相同)


範例畫面:
主(父)報表Report2


鑽取下的報表Report1


延伸:
若有多個欄位 鑽研不同的Report
則...
  Select Case e.ReportPath
   Case "Parent"
    Me.List_Customers_OrderTotalTableAdapter.Fill(Me.MyDataSet1.List_Customers_OrderTotal)
    RptrDS = New ReportDataSource("DataSet_1", Me.MyDataSet1.Tables("List_Customers_OrderTotal"))

   Case "Level1"
    Me.Show_OrderDetailsTableAdapter.Fill(Me.MyDataSet1.Show_OrderDetails, Integer.Parse(sParameter))
    RptrDS = New ReportDataSource("DataSet_2", Me.MyDataSet1.Tables("Show_OrderDetails"))

   Case "Level2"
    Me.Show_ProductsTableAdapter.Fill(Me.MyDataSet1.Show_Products, Integer.Parse(sParameter))
    RptrDS = New ReportDataSource("DataSet_3", Me.MyDataSet1.Tables("Show_Products"))

   Case Else
    Me.List_Customers_OrderTotalTableAdapter.Fill(Me.MyDataSet1.List_Customers_OrderTotal)
    RptrDS = New ReportDataSource("DataSet_1", Me.MyDataSet1.Tables("List_Customers_OrderTotal"))
  End Select


延伸:
若要多筆資料分頁
則...
Step1.將設計的Table(無資料列 只留表頭或表尾) 拉進 List裡


Step2.設定List屬性


顯示畫面:



自己想的報表:(應該滿多人會被這樣要求的, 不然紙張很浪費!!)
這一張報表剛好佔A4紙3分之1頁面
今天我想把三筆資料弄在同一張頁面

解決方式1:(很笨的方式)
查詢的資料結合,將每三筆資料結合成一組。
例如:

原始DataSet From DataBase
SN     名字     地址
1        陳         屏  
2        張         桃  
......
n        n           n             n


自定義DataSet, 每三筆組成一筆, 透過原始 DataSet 來組合
群組      row1     row2     row3     row4     row5     row6     row7     row8     row9
1           1            陳         屏         2           張         桃         3           x           x
2           4            x            x          5            x           x           6           x           x
......
n           n-2         x            x          n-1         x           x           n           x           x


同一個List,同樣的表格畫三個,並分別放入 row1~row9
第一個表格 row1~row3 第二個表格 row4~row6 第三個表格 row7~row9
分頁設定則是依 "群組" 來分頁


若資料剛好不足3筆成一個record時
則沒資料列的地方要補空白
不然格式會跑掉
而且畫出來的格式 如果有顏色
則必須再報表設計時 設定如果沒有值 得border為白色
(1.不知從程式有沒有辦法處理 報表的設定)
(2.不要用hiden 因為格式也會跑掉)
當然如果紙張不是白色的 就依那個顏色
(1.就嘿嘿嘿...囧 自己慢慢選顏色, 缺點...)

解決方法2:結尾的分頁符號不要勾選


顯示畫面:


注意:
A4紙直式輸出 會自動弄三頁
A4紙橫式輸出 會自動弄二頁
若要輸出為中一刀 寬21 長14
則報表上也要設計為中一刀格式
否則輸出依然是A4格式輸出
中一刀設定


參考:
Create Drill-Through Reports using ReportViewer in ASP.NET 2.0
ReportViewer教程(14)-钻取报表和传入参数
ReportViewer.Drillthrough 事件
使用RDLC报表(四)--钻取式报表
RDLC研取子报表
MSDN報表教學 - 加入鑽研報表
MSDN報表教學 - 第 5 課:加入傳遞至鑽研報表的參數
ReportViewer Control 相關的 Sample Code
如何控制reportviewer驅動RDLC一筆記錄呈現一頁

Reporting Services
Beginning SQL Server 2005 Reporting Services Part 1
Beginning SQL Server 2005 Reporting Services Part 2
Beginning SQL Server 2005 Reporting Services Part 3: The Chart Control
Beginning SQL Server Reporting Services Part 4

RDL(C) Report Design Step by Step 2: SubReport  <-- 這不是鑽研式報表
LocalReport.SubreportProcessing 事件 <-- 這不是鑽研式報表

ReportViewer SubReport 子報表

Difficulty setting ReportParameter

使用 PIVOT 和 UNPIVOT 讓資料多列變成一列
SQL - 使用 PIVOT
SQL資料轉行
續:SQL 資料轉行

待解決的設計: 思考一下別人的報表 如果是我要如何去設計...
請問該如何利用Report Viewer製作如內文所述報表?


2013年3月17日 星期日

[技巧] Using GetUpperBound(0) 取得儲存多筆Record的DataRow


Dim 病假() As DataRow = Me.MyCallForm.ds.Tables("attend").Select("type = '病假' and ym like '" & ComboBox1.Text & "%'")

For i As Integer = 0 To 病假.GetUpperBound(0)
    MsgBox(病假(i)("ym") + 病假(i)("type"))
Next

備註:
Dim 病假() As DataRow = Me.MyCallForm.ds.Tables("attend").Select("type = '病假' and ym like '" & ComboBox1.Text & "%' and substring(ym,6,2) <= " & Integer.Parse(ComboBox2.Text) & "")

ym欄位的資料型態為nchar
資料內容為六位數的 "月份日期" 組合
201003
201201
201202
201203
201302

可運用 substring() 來進行分割搜尋...
從條件來看 假設 ComboBox1.Text = 2012 , ComboBox2.Text = 02
則DataTable.Select()的filter結果為
201201
201202

參考:
DataTable.Select 方法 (String)
[C#] Datatable.Select 的運算式用法
C# [轉載] Datatable.Select 的運算式用法
DataTable.Select()中的表达式可使用的函数
dataTable 的處理
Convert DataRow Array to DataTable, DataTable Filter function DataTable.Select return DataTable
DataTable Select Function (datarow 轉為 datatable)

SQL函數 查詢SQL資料欄位相符的字串
MSSql 中Charindex ,Substring的使用
CHARINDEX (Transact-SQL)

2013年3月12日 星期二

[SQL] 字串切割與截取

資料庫資料[tb1]: (location 沒有 atomic)
----------------------------------------
欄位名稱     Location
----------------------------------------
欄位內容     Seattle, WA
                 Natchez, MS
                 Las Vegas, NV
                 Palo Alto, CA
                 NYC, NY
----------------------------------------

問題:
只想取右邊兩位數簡碼。

方法:
SELECT     RIGHT(Location, 2)     FROM     [tb1];
SELECT     SUBSTRING_INDEX(Location, ',', 1)     FROM     [tb1];

參考:
[書籍]HEAD FIRST SQL
使用SQL語法分割字串問題 目前ms-sql應該沒有字串分割的函數
字串函數 (Transact-SQL)
寫 SQL 的邏輯/技巧:字串切割
sql server中如何切割字串
分割字串 (Split)
SQL字串切割
切割字串另類方法
字串分割後轉成Table
SQL-切割字串
字串分割 / String.Split
SQL函數 查詢SQL資料欄位相符的字串
MSSql 中Charindex ,Substring的使用
CHARINDEX (Transact-SQL)

2013年2月19日 星期二

[學習] 讓視窗保持在最上層


(一)
Dim frm備註 As New 詢價單備註編輯
frm備註.MyCallForm = Me
frm備註.ShowDialog()




(二)
此段程式碼是寫在同一個視窗(Form)

ShowDialog 的焦點會一直在被開啟的Form上
與之不同的是 Show 的焦點不會在開啟的Form上

所以當開啟時若要一直在焦點上的話
就必須在主視窗的Activated事件下寫段程式

又因為被開啟的Form 並不是MDI表單
所以必須在 Application.OpenForms 下去搜尋

在圖一的紅色框的範圍內連點兩下,則會使主視窗縮放
在紅色框外及黃色框外的範圍都無法點擊
雖然可點擊黃色框內的 button,但都是沒有反應的(ex:會更新主視窗的資料)
應該是因為 Activated 事件觸發後,其它事件(或反應)就會被攔截掉...(尚待解釋)
而 ShowDialog 則除本視窗外,其它視窗都無法點擊

Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click

     Dim frm As New 詢價單費用編輯
     'frm.TopMost = True
     'frm.Owner = Me.ParentForm
     'frm.Parent = Me.ParentForm
     'frm.Focus()
     'frm.Activate()
     frm.Show()
End Sub



Private Sub 詢價單資料輸入作業_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Activated
        For Each f As Form In Application.OpenForms
            If f.Text.Equals("詢價單費用編輯") Then
                f.Activate()
                Exit For
            End If
        Next
End Sub




(三)
若要讓視窗長駐最上層
則使用 TopMost = True
此時的可以點擊其它視窗
只是被開啟的視窗會一直長駐在最上層而己
即使使用者切換至其它應用程式



Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click

     Dim frm As New 詢價單費用編輯
     frm.TopMost = True
     'frm.Owner = Me.ParentForm
     'frm.Parent = Me.ParentForm
     'frm.Focus()
     'frm.Activate()
     frm.Show()
End Sub




而(一)及(二)
當使用者點選其它應用程式時,並不會顯示在最上層。



參考:
vb.net find form by title and edit control
VB.net視窗控制問題
利用SetWindowPos使表單永遠放到最上層!
如何在VB裡讓程式表單能夠最上層顯示
如何將 Form 顯示在最上層?
如何顯示其他Form卻又不讓其獲得Focus?
vb.net 轉移程式焦點
VB.Net Form關閉按鈕以及最上層顯示問題
請問如何讓開啟的form只在此視窗中最上層顯示
請問視窗最上層的問題
最上層FORM的鎖定
VB.Net Form顯示為最上層
當程式的前景被其他程式拿走時判斷並拿回前景
[C#]透過 SHDocVw 與 GetForegroundWindow 取得正在使用的 Internet Explorer 網址
[VB.NET]把.NET視窗嵌入.NET視窗或控制項

2013年2月5日 星期二

[除錯] ComboBox 繫結 DataSource 顯示 System.Data.DataRowView

程式:
Dim sqlQuery1 As String = "SELECT (convert(nvarchar(4),系統ID) + '(' + 系統名稱 + ')') as 系統 FROM [系統別資料表] WHERE 系統ID <> 0;"
dt_Sys = basic.reDataset(sqlQuery1, Nothing, Nothing)

   For Each row As DataRow In dt_Sys.Rows
        If row.Item(0).ToString = "0" Then
             'way1 / way2
             ComboBox1.Items.Add(row.Item(0).ToString)
        End If
     Next

'dataTable 是可以顯示正常的...
'MsgBox(dt_Sys.Rows(0)("系統").ToString)

(way1) combobox1 每個row都顯示 System.Data.DataRowView
ComboBox1.DisplayMember = "系統"
ComboBox1.ValueMember = "系統"
ComboBox1.DataSource = dt_Sys
[C# CODE] 參考... 轉型 DataRowView
foreach(var dr in cbo_客戶編號.Items)
{
    MessageBox.Show(((DataRowView)dr)["中文名稱"].ToString());
}


(way2) 正常
For Each row As DataRow In dt_Sys.Rows
     ComboBox1.Items.Add(row.Item(0).ToString)
Next

備註:
我的程式裡並沒有 SelectedIndexChanged & SelectedValueChanged 的事件...
參考的資料無法解決問題…
還是(use way2)照原方式處理
但效率比較差...

2013/02/18 改way1 又正常了XD
應該跟以下有關係: (把obj的方式 變更為 datatable 就解決了)
form1
    'cbbox1 系統 資料繫結
    Dim dt_Sys As DataTable = New DataTable
    Public Property _dt_Sys() As DataTable
        Get
            _dt_Sys = dt_Sys
        End Get
        Set(ByVal value As DataTable)
            dt_Sys = value
        End Set
    End Property

    'Private obj As Object()
    'Public Property cbbox1() As DataTable
    '    Get
    '        cbbox1 = obj
    '    End Get
    '    Set(ByVal value As Object)
    '        obj = value
    '    End Set
    'End Property

     '將 combobox1 的item 複製到 系統別的combobox1
     'obj = New Object(ComboBox1.Items.Count - 1) {}
     'ComboBox1.Items.CopyTo(obj, 0)

form2
      '將form1的combobox1上的所有item 加入到 form2的combobox1
      'ComboBox1.Items.AddRange(Me.MyCallForm.cbbox1)

參考:
combobox.DisplayMember property
自訂ComboBox的DisplayMember及ValueMember
DataSet&DataTable如何绑定下拉列表控件获取不重复的值,如何添加一列自定义文字,并在下拉列表控件中显示自定义文字
Combobox出现System.Data.DataRowView的原因,以及指定ValueMember的时机问题
C#comboBox的DataSource获取数据显示System.Data.DataRowView
#VB ComboBox 問題集