• Vui lòng đọc nội qui diễn đàn để tránh bị xóa bài viết
  • Tìm kiếm trước khi đặt câu hỏi

Sử dụng Report chuẩn của .NET, tại sao không?

Các bài viết hướng dẫn về Visual Basic .NET và C#

Điều hành viên: QUANITGROBEST, tungcan5diop

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Sáu 17/12/2010 6:31 pm

Tên bài viết: Sử dụng Report chuẩn của .NET, tại sao không?
Tác giả: ThuongBat
Cấp độ bài viết: Trung bình
Tóm tắt: Cách sử dụng Report chuẩn của .NET thay cho Crystal Report (hướng dẫn thao tác với VB.NET)



Mới ghé qua trang web này thấy có một số giải thích và ví dụ mẫu khá hay về ReportViewer. Mình đưa link lên đây để bạn nào cần thì tham khảo (web tiếng Anh nhé): http://gotreportviewer.com/

1. Đặt vấn đề:
Mình tìm trên forum thấy có khá nhiều bài viết hướng dẫn cách tạo báo cáo với Crystal Report (tạm viết tắt là CR). Nhiều bạn thích dùng CR bởi tính chuyên nghiệp của nó và CR được sử dụng Free trong Visual Studio. Nhưng CR có một điểm hạn chế là khi đóng gói chương trình mang sang máy khác nó không chạy được. Muốn CR hoạt động được, hoặc là máy khách phải cài Crystal Report (cái này không miễn phí) hoặc là bạn phải đóng kèm ứng dụng của mình một cái Merge Module khá nặng (khoảng 25Mb đối với Crystal Report cho Visual Studio 2005) làm cho bộ Setup của bạn phình to ra.
Report chuẩn của .NET cũng giống như Data Report trong Vb6 nhưng nó đã được nâng cấp lên nên cũng chuyên nghiệp không kém CR. Ngoài ra, vì nó là công cụ chuẩn của .NET nên được hỗ trợ khá tốt. Bạn đóng gói ứng dụng cũng chỉ cần mang theo vài cái DLL nhỏ là có thể chạy tốt.

2. Sử dụng Report của .NET (tạm gọi là Data Report cho nó gọn):
Tìm hiểu thông qua ví dụ là dễ hiểu nhất, vì vậy mình sẽ đưa ra 1 cái ví dụ để các bạn chưa biết thì tham khảo. Mình sẽ sử dụng Data Report để làm 1 cái báo cáo chi tiết sử dụng cước viễn thông (bạn nào sử dụng di động trả sau thì giữa tháng hay được gửi tặng cái báo cáo này). Tuy nhiên, có hơi khác 1 tí là: báo cáo chi tiết cước viễn thông sẽ liệt kê các cuộc gọi mà ta gọi đi, còn báo cáo này của mình là liệt kê các cuộc gọi đến.
Report của mình sau khi in ra sẽ có dạng như sau:
printed_report.jpg

Phần Header và Footer sẽ trải dài từ trái qua phải, còn phần dữ liệu sẽ chia thành 2 cột (để tiết kiệm giấy)

2.1. Dữ liệu cần in:
Bảng dữ liệu của mình có cấu trúc như sau:
datatable.jpg

Đây là bảng dữ liệu mình đang làm (thiết kế trong MySQL), có 1 số cột không dùng đến nhưng mình không xóa đi (một phần là vì ngại thiết kế lại, một phần là muốn cho các bạn thấy là không cần thiết phải in ra tất cả các cột trong CSDL. Chỉ sử dụng những cột nào mình cần)
Ý nghĩa của các cột mình sẽ sử dụng như sau:
+ ID: là ID của bản ghi (số tự tăng)
+ Caller: số điện thoại của người gọi đến
+ StartAt: thời điểm bắt đầu kết nối cuộc gọi (có cả ngày và giờ)
+ Duration: thời gian đàm thoại (tính bằng giây)
+ BlockCount: số block của cuộc gọi (cái mình đang làm nó tính cước theo block). Các bạn chỉ cần hiểu đây là 1 trường Number là được
+ TotalCharge: tiền cước

2.2. Thiết kế bảng dữ liệu cần in trong Visual Studio:
Có nhiều bạn thích kết nối trực tiếp vào CSDL để in bằng mấy cái Data Source gì đó. Mình thì không làm theo cách đó. Mình chỉ tạo các Dataset và Datatable độc lập trong VS (có cấu trúc giống như cấu trúc trong CSDL) rồi thiết kế Report dựa vào các Datatable này. Khi nào cần in thì mới Fill dữ liệu vào Datatable để in. Để tạo ra Dataset độc lập trong VS, làm như sau:
+ Right Click vào tên Project trong cửa sổ Solution Explorer, chọn Add > New Item
+ Trong cửa sổ mới hiện ra, chọn Dataset
+ Nhập giá trị Name cho dataset là dsCallLogs rồi nhấn nút Add, bạn sẽ có một dataset là dsCallLogs.xsd trong Project của mình
Tiếp tục là việc tạo bảng cho Dataset:
+ Mở dsCallLogs.xsd ra,
+ Right CLick vào vùng trống của dataset và chọn Add > Datatable, bạn sẽ có 1 bảng là Datatable1
+ Sửa tên của Datatable từ Datatable1 thành tbl_Call_Logs
+ Right Click vào tbl_Call_Logs, chọn Add > Colum
+ Sửa tên column mới add thành ID
+ Tiếp tục add thêm các column khác để được 1 datatable có dạng như sau:
tbl_call_log.jpg
tbl_call_log.jpg (17.79 KiB) Đã xem 32080 lần


2.3. Tạo báo cáo:
Phần chuẩn bị dữ liệu đã xong, bây giờ đến bước tạo báo cáo.
+ Right Click vào tên Project trong Solution Explorer, chọn Add > New Item
+ Trong cửa sổ mới mở ra, chọn biểu tượng Report (lưu ý là Report chứ không phải Crystal Report nhé)
+ Nhập giá trị Name cho Report là rptCallLogs rồi nhấn nút Add. Bạn sẽ có một Report trong project của mình là rptCallLogs.rdlc

2.4. Thiết giao diện cho báo cáo: Phần này là hay nhất này. Các bạn có thể thấy việc thiết giao diện báo cáo này có khi còn đơn giản hơn cả Crystal Report (vậy mà không hiểu sao nhiều bạn vẫn thích dùng Crystal Report hơn :D). Chém gió tí cho vui vẻ, các bạn thông cảm nhé
+ Double Click vào rptCallLogs.rdlc để mở giao diện thiết kế báo cáo ra
+ Vào menu Report, tích vào 2 mục Page Header và Page Footer để hiện header và footer cho báo cáo
+ Kéo từ Toolbox vào phần Header 9 cái textbox, sắp xếp và gõ chữ để nó giống như thế này:
report_header.jpg

(Lưu ý: các textbox có giá trị với dấu = ở phía trước là các tham số của Report. Khi gọi report lên, ta nhập cho tham số là cái gì thì nó sẽ hiện lên cái đó ở trên report. Cái này rất hữu dụng để in các giá trị được truyền từ Form vào Report. Tạm thời các bạn có thể để trống các textbox này. Ta sẽ thảo luận nó sau ở phần Tham số của Report.)

+ Kéo từ Toolbox vào phần Body 1 cái Table. Table này sẽ dùng để hiển thị dữ liệu dưới dạng bảng. Trông nó cũng giống cái DataGrid phải không các bạn. (Crystal Report hình như là mình không thấy cái này). Table sẽ có 3 phần Header, Detail và Footer với mặc định là 3 cột. Right Click vào Talbe, chọn Insert colum 3 lần để được 1 cái Table có 6 cột:
insert_columns.jpg

+ Gõ tiêu đề cho các cột của table (ở phần header nhé) lần lượt như sau:
table_header.jpg

+ Vào Menu Data > Show Data Source để hiện cửa sổ Data lên (nếu nó chưa hiện). Bạn sẽ thấy cái Datatable mà mình thiết kế ở bước 2.2 hiện ra. Bạn chỉ việc kéo các Field từ Datatable vào các cột tương ứng của của Table trên Report (kéo vào phần Detail nhé). Ở đây có 2 cột Ngày và T.G đàm thoại cùng sử dụng chung dữ liệu của Field: StartAt
report_detail.png
report_detail.png (5.2 KiB) Đã xem 32080 lần


2.5. Nhóm dữ liệu trên cột "Ngày":
Ta sẽ nhóm các cuộc gọi vào theo từng ngày để tiện theo dõi, đồng thời cũng giúp cho cái báo cáo nó sáng sủa hơn 1 chút. Quy trình làm như sau:
+ Chọn toàn bộ Table (click và rê chuột bao quanh table) - nhớ là chọn Table nhé, chứ không phải chọn một cell của table đâu
+ Right click vào table và chọn Properties để mở ra bảng Property của Table
+ Chọn sang tab Groups
+ Click vào nút Add để thêm 1 Group mới
+ Trong cửa sổ mới hiện ra, nhập giá trị =Format(Fields!StartAt.Value,"MM/dd/yyyy") (nhớ là có cả dấu = nhé). Ta phải dùng lệnh Format ở đây là vì trường StartAt là trường DateTime (có cả ngày và giờ) mà ta lại chỉ muốn nhóm theo ngày thôi chứ không nhóm theo giờ, phút giây. Lệnh Format sẽ cắt giá trị giờ,phút giây đi
+ Bỏ 2 dấu tích Include Group Header và Include Group Footer đi (bạn có thể để lại nếu muốn, tuy nhiên mình thấy không có header, footer sẽ đẹp hơn)
+ Nhấn Ok để đóng các cửa sổ Property lại.

2.6. Format các giá trị hiển thị cho report trông đẹp mắt hơn:
A. Cột "Ngày": chỉ cần hiển thị ngày và tháng là đủ rồi. Năm với lại cả giờ, phút, giây là không cần thiết. Hơn nữa, ta cũng chỉ cần hiện mỗi giá trị ngày 1 lần thôi (có 100 bản ghi cùng 1 nhóm thì cũng chỉ hiện ngày trên 1 bản ghi). Vì vậy ta có thể Format nó như sau:
+ Chọn Cell tương ứng với cột ngày (ở phần Detail nhé), nhấn F4 để hiện cửa sổ Properties của nó ra
+ Nhập giá trị Value trên cửa sổ Properties là =Format(First(Fields!StartAt.Value),"dd/MM") (Có cả dấu = nhé). Cái này để format kiểu hiển thị
+ Chọn Hide Duplicates là Table1_Group1 để không hiện các ngày trùng nhau ở các hàng liên tục
B. Cột "Bắt đầu": chỉ cần hiện giờ, phút, giây thôi (vì ngày đã có ở cột "Ngày" rồi). Bạn lại làm như sau
+ Chọn Cell của cột "Bắt đầu" (phần Detail), nhấn F4 để hiện cửa sổ Properties
+ Nhập giá trị cho Value là = Format(Fields!StartAt.Value,"hh:mm:ss") (có cả dấu = nhé)

2.7 Tính tổng:
Phần tính tổng sẽ được làm trên Footer của Table, Nhập các giá trị cho Footer của Table như sau:
+ Cột ngày (phần Footer), nhập giá trị "Tổng" - cái này chỉ là Text đơn thuần thôi
+ Cột "Người gọi" (phần footer): mình sẽ in tổng số cuộc gọi trên cột này,vì vậy bạn nhập giá trị cho nó là: =Count(Fields!Id.Value)
+ Cột "T.G": Tính tổng thời gian gọi, vì vậy bạn nhập giá trị cho nó là: =Sum(Fields!Duration.Value)
+ Cột "Blocks": tính tổng số block, vì vậy giá trị cần nhập là: =Sum(Fields!BlockCount.Value)
+ Cột "Tiền": tính tổng số tiền bằng công thức: =Sum(Fields!TotalCharge.Value)

Sau khi nhập các giá trị, format dữ liệu, kéo các cột to nhỏ cho hợp lý, bạn sẽ được cái table có dạng như sau:
table_completed.png
table_completed.png (4.7 KiB) Đã xem 32080 lần

Các bạn thấy không. Thao tác với Data Report đơn giản đấy chứ

2.8. Tham số của Report:
Bạn muốn truyền 1 giá trị nào đó từ Form vào Report, bạn chỉ việc tạo tham số cho report. Cách tạo tham số như sau:
+ Từ menu Report chọn muc Report Parameters
+ Click vào nút Add để thêm tham số mới
+ Nhập tên vào mục Name, chọn kiểu dữ liệu trong Data Type (mình chưa rành về mục này lắm nên toàn bộ kiểu dữ liệu mình đều để là String cho dễ thao tác. Nếu để các kiểu khác - ví dụ: datetime - thì khi chạy hay bị exception)
+ Tiếp tục add các Parameter khác, nhấn OK khi xong việc

Trong phần Report header, mình có mấy cái textbox có để parameter. Đó là các Report ở phần "Số máy", "Từ ngày", "Đến ngày". Vậy mình sẽ tạo ra 3 parameter là tương ứng là "PhoneNumber", "FromDate", "ToDate". Hãy nhớ tên của các Parameter này (hay ít nhất cũng là nhớ chỗ cần phải mở ra để xem nó) vì bạn còn cần dùng nó để truyền giá trị từ Form vào.
Sau khi thêm Parameters xong thì bạn chọn textbox để hiển thị các Parameter này. Nó chính là các textbox ở phần Report Header.
+Right Click vào textbox bên cạnh cái textbox có chữ "PhoneNumber" và chọn mục Expression
+ Trong cửa sổ hiện ra, chọn mục Parameters ở treeview bên tay trái
+ Double Click vào giá trị "PhoneNumber" ở listbox bên phải để thêm parameter này vào textbox. Bạn sẽ thấy nội dung của textbox có dạng =Parameters!phoneNumber.Value
+ Làm tương tự với các textbox còn lại
+ Riêng textbox chỗ có chữ "Trang" thì bạn nhập giá trị =Globals!PageNumber & "/" & Globals!TotalPages trong cửa sổ Expression của nó. Mấy cái giá trị PageNumber... bạn có thể tìm thấy trong nút Global của treeview

Cách truyền tham số cho Report trên đây áp dụng cho Visual Studio 2005 và 2008. Phiên bản VS2010 thì thao tác khác với cách trên 1 chút. Cảm ơn bạn Phung Manh Ninh đã cung cấp một ví dụ về cách truyền tham số cho Report trong VS2010. Các bạn có thể xem ví dụ đính kèm (có cả tệp hướng dẫn bằng Word trong đó)
MSReport.rar
(200.29 KiB) Đã tải 2150 lần


2.9. Chia cột cho Report:
Vì cái vùng Data của mình tương đối hẹp về chiều ngang nên để tiết kiệm giấy ta sẽ in report trên 2 cột.
+ Vào Menu Report, chọn Report Properties
+ Chọn sang Tab Layout
+ Ở mục Columns, nhập giá trị 2

Vậy là đã xong phần thiết kế, bây giờ cái report của bạn sẽ có hình dạng như thế này:
report_completed.png


Còn phần Form để show cái Report này lên, em sẽ post trong bài sau. Các bác thông cảm nhé
Sửa lần cuối bởi thuongbat vào ngày T.Ba 05/06/2012 1:09 am với 4 lần sửa.
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Sử dụng Report chuẩn của .NET, tại sao không? <tiếp theo>

Gửi bàigửi bởi thuongbat » T.Bảy 18/12/2010 9:17 am

2.10. Tạo Form để hiển thị Report
Form để hiển thị Report cần nhất là 1 cái ReportViewer. Bạn có thể kéo cái control này vào Form từ thanh Toolbox. Khi bạn kéo ReportViewer1 vào trong Form, VS có thể sẽ hỏi bạn chọn Report cần hiển thị trong ReportViewer. Bạn chỉ việc bỏ qua bước này (Vì Report của ta gắn với 1 cái Datatable rỗng chứ không kết nối trực tiếp vào database nên bạn cần phải có 1 ít code để show report lên viewer thay vì chọn sẵn). Trên Form bạn cũng có thể bố trí thêm 1 số điều khiển khác để lọc dữ liệu cần hiển thị. Form của mình thiết kế đơn giản như sau:
report_form.png

+ 2 cái DateTimePicker dùng để lọc các bản ghi từ ngày...đến ngày
+ 1 cái Textbox có Label là Caller ID: dùng để lọc những bản ghi có số điện thoại người gọi giống với nhập vào textbox
+ 1 cái Combobox dùng để chọn loại báo cáo. Một Form này có thể show nhiều kiểu báo cáo khác nhau (tất nhiên là bạn phải thiết kế thêm các report khác). Ở đây mình mới thiết kế mẫu 1 cái report nên tạm thời không dùng đến combo này
+ 1 Button dùng để load report lên form khi click
+ 1 Reportviewer là nơi hiển thị report

Ta bắt đầu viết code cho cái Button "Show Report"
  1. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnShowReport.Click
  2.         Dim dt As DataTable = Nothing 'datable dùng để query dữ liệu từ database và gán vào report
  3.         Dim oDb As New CMySqlDao()  'đối tượng này sẽ kết nối với CSDL MySQL và query dữ liệu, các bạn có thể dùng kết nối của mình theo cách khác
  4.         Dim sql As String                   'câu sql cần query
  5.         sql = "SELECT * FROM tbl_call_log"
  6.         sql &= " WHERE DATE(startAt) BETWEEN '" & dtpFromDate.Value.ToString("yyyy-MM-dd") & "' AND '" & dtpToDate.Value.ToString("yyyy-MM-dd") & "'"  'câu SQL dùng để Query (mình viết cho MySQL). với các loại CSDL khác có thể câu SQL sẽ hơi khác 1 chút
  7.         If (txtCallerId.TextLength > 0) Then  'nếu người sử dụng có nhập số điện thoại vào ô CallerId thì thêm điều kiện lọc này
  8.             sql &= " AND caller LIKE '" & oDb.Quote(txtCallerId.Text.Replace("*", "%")) & "'"
  9.         End If
  10.         dt = oDb.ExecuteSql(sql)      'truy vấn vào CSDL để lấy dữ liệu vào Datatable
  11.         ReportViewer1.Reset()         'reset cái Reportviewer
  12.         ReportViewer1.LocalReport.ReportEmbeddedResource = "MyTestProgram.rptCallLogs.rdlc" 'gán cái Report mà ta đã thiết kế ở trên vào Reportviewer ("MyTestProgram" chính là tên NameSpace gốc - với VB.NET thì tên namespace gốc mặc định trùng với tên Project)
  13.         ReportViewer1.LocalReport.DataSources.Clear()    'Clear DataSource cũ của Report (lúc thiết kế report, ta làm trên Datatable rỗng nên ở đây ta clear nó đi để thêm Datatable thực sự của ta vào)
  14.         Dim newDataSource As Microsoft.Reporting.WinForms.ReportDataSource = New Microsoft.Reporting.WinForms.ReportDataSource("dsCallLogs_tbl_Call_Logs", dt)  'tạo DataSource mới cho Report. Lưu ý: tên "dsCallLogs_tbl_Call_Logs" chính là tên ghép của Dataset và Datatable ta thiết kế ở bước 2.2.
  15.         ReportViewer1.LocalReport.DataSources.Add(newDataSource)      'gán DataSource mới tạo vào Report
  16.         Dim Parameters As List(Of ReportParameter) = New List(Of ReportParameter)  'Tạo danh sách các Parameter để truyền cho Report
  17.         Dim param As ReportParameter
  18.         param = New ReportParameter("fromDate", dtpFromDate.Value.ToString("dd/MM/yyyy")) 'parameter "FromDate" của report
  19.         Parameters.Add(param)
  20.         param = New ReportParameter("toDate", dtpToDate.Value.ToString("dd/MM/yyyy"))     'parameter "ToDate" của report
  21.         Parameters.Add(param)
  22.         param = New ReportParameter("phoneNumber", txtCallerId.Text)   'parameter "PhoneNumber" của Report
  23.         Parameters.Add(param)
  24.         ReportViewer1.LocalReport.SetParameters(Parameters)   'gán danh sách các Parameter vào Report
  25.         ReportViewer1.RefreshReport()                                   'gọi RefreshReport() để bắt đầu hiển thị
  26.         ReportViewer1.LocalReport.DisplayName = "Call Logs"     'nếu bạn bỏ qua bước này, khi report hiện ra và bạn muốn export nó ra excel hoặc PDF thì VS sẽ lấy tên mặc định cho file export là rptCallLogs.
  27.         ReportViewer1.SetDisplayMode(DisplayMode.PrintLayout) 'bắt Reportviewer hiển thị ở chế độ PrintLayout (trông sẽ đẹp mắt hơn)
  28.         ReportViewer1.ZoomMode = ZoomMode.Percent            'đặt chế độ Zoom cho report là theo phần trăm
  29.         ReportViewer1.ZoomPercent = 100                             'và zoom nó lên 100%
  30. End Sub
  31.  


Quy trình thực hiện đã xong. Và đây là thành quả:
report_viewer.png


Trông cũng không đến nỗi tệ phải không các bạn.
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Bảy 18/12/2010 12:04 pm

2.3 Thảo luận thêm:
2.3.1. Lọc dữ liệu nâng cao:
Với Report trên, tất cả các số điện thoại (cả số cố định và số di động) đều nằm chung trong 1 bảng dữ liệu. Bây giờ tôi muốn tách các số di động ra trên 1 bảng, các số cố định ra 1 bảng, còn các số khác (số hiển thị sai, hoặc không có hiển thị số do người gọi dùng dịch vụ dấu số) ra 1 bảng để tiện theo dõi hơn. Vậy thì phải làm như thế nào?

Trong CSDL của tôi có 1 trường là CallerIdType (kiểu số nguyên). Giá trị của trường này sẽ thể hiện số điện thoại của người gọi thuộc kiểu gì (di động, cố định hay không rõ số). Tất nhiên các bạn có thể có phương pháp riêng của mình để quy định các điều kiện lọc. Nhưng như ví dụ này của tôi thì quy định như sau: Giá trị của CallerIdType sẽ bằng:
+ 0: nếu số điện thoại của người gọi là 1 số cố định
+ 1: nếu số điện thoại là số di động
+ -1: nếu số điện thoại không có hoặc không rõ thuộc kiểu nào
(Tất nhiên các giá trị này tôi đã tính toán trong chương trình của mình trước khi Insert 1 bản ghi vào bảng CallLogs)
Vì vậy, bây giờ tôi muốn có 1 bảng hiện chỉ các số cố định thôi, dĩ nhiên là tôi sẽ lọc với CallerIdType = 0...
Việc bổ sung các Field phục vụ cho công tác lọc dữ liệu vào bảng trong Database có thể sẽ gây dư thừa dữ liệu (vì từ giá trị số điện thoại đã lưu, bạn có thể tính toán để cho ra kết quả số đó thuộc kiểu gì bất cứ lúc nào) nhưng sẽ giúp cho việc xử lý report nhanh hơn và đỡ phức tạp hơn (không cần tính toán nhiều trong Report).
Bây giờ tôi sẽ sửa lại cái báo cáo rptCallLogs để hiện ra 3 bảng với 3 loại số điện thoại khác nhau trên cùng 1 report. Quy trình như sau:
+ Mở report rptCallLogs ở chế độ Design.
+ Copy cái Table trong phần Detail của report và Paste vào phần trống của Detail 2 lần nữa, ta sẽ được 3 cái bảng giống hệt nhau (VS sẽ tự đặt tên cho các table là Table1, Table2, Table3). Sắp xếp 1 chút và thêm vào các Textbox chú thích. Ta sẽ có cái Report mới trông như thế này:
report_completed_2.png

(Sắp xếp thứ tự của các Table từ trên xuống dưới là Table1, Table2, Table3)

+ Mở Properties Window của Table1 (bằng cách chọn Table1, right click vào nó và chọn Properties)
+ Chọn sang tab Filters
+ Trong Filter List, ở hàng đầu tiên, chọn Expression là =Fields!callerIdType.Value
+ Chọn Operator là dấu =
+ Cột Value, nhập giá trị là =1 (nhớ là có cả dấu = nhé. không có dấu = sẽ bị lỗi đấy)
+ Các bước vừa rồi là ta đã filter cho bảng Table1 chỉ hiện các bản ghi có CallerIdType=1 (chỉ hiện các số điện thoại di động). Làm tương tự như thế với 2 bảng còn lại (Table2 phải nhập Value cho filter là =0, còn Table3, giá trị cho filter là =-1)
Vậy là đã gần xong rồi đấy. Chỉ còn 1 bước nhỏ nữa thôi. Các bạn có nhớ là ở bước 2.6 ta đã chọn giá trị Hide Duplicates cho giá trị ở cột "Ngày" không? Hide Duplicates sẽ làm ẩn đi các giá trị ngày giống nhau ở cột "Ngày" (chỉ hiện giá trị trên hàng đầu tiên) làm cho Report trông sáng sủa hơn và ta cũng tiết kiệm được kha khá mực in. Bảng Table1 có một nhóm ta đã tạo để nhóm các bản ghi trong cùng 1 ngày lại với nhau. Khi bạn copy ra 2 bảng nữa thì trên mỗi bảng mới cũng sẽ có một nhóm tương tự (nhưng tên nhóm sẽ khác đi). Vì vậy ta phải chọn lại giá trị cho Hide Duplicates trên 2 bảng mới này (bảng 1 thì không cần vì nhóm của nó không thay đổi)
+ Chọn Cell tương ứng với cột "NGày" trên Table2, nhấn F4 để mở Properties của nó ra.
+ CHọn giá trị cho Hide Duplicates trong Properties Window là: table2_Group1
+ Tương tự, chọn Hide Duplicates trong Properties Window cho Cell của Table3 là table3_Group1

Đã xong, bạn lưu lại cái report đã sửa và chạy chương trình. Còn đây là kết quả:
report_viewer_2.png

Việc Filter dữ liệu hoàn toàn có thể thực hiện trên Report. Bạn không cần phải viết lại 1 dòng code nào cả.
2.3.2. Cài đặt trang in
Đa số báo cáo khi in ra, các bạn đều muốn in trên giấy A4 (có thể có bạn muốn khi trên khổ giấy to hơn hoặc nhỏ hơn). Tuy nhiên cái mình muốn nói đến là việc chúng ta sử dụng giấy A4 để in, trong khi thằng Microsoft lại đặt kiểu giấy mặc định cho cái Report là Letter. Giấy Letter có bề ngang to hơn giấy A4 1 chút nhưng nếu bạn nào không để ý thì thiết kế xong in ra sẽ bị cắt mất 1 đoạn ở lề bên phải. Trên Reportviewer cũng có nút Page Setup, nhưng nếu bạn để cái report của mình to hơn khổ A4 thì khi chạy chương trình lên, bạn sẽ không thể dùng nút Page Setup để chuyển khổ giấy từ Letter về A4. Để định dạng giấy in của mình là A4 các bạn làm như sau:
+ Mở Report ở chế độ Design
+ Từ menu Report, chọn Report Properties
+ Chọn sang Tab Layout
+ Nhập kích thước Page Width = 8.27, Page Height = 11.69. Đây là kích thước của giấy A4
+ Trên Report, sắp xếp các điều khiển, co giãn kích thước sao cho vừa mắt nhưng phải luôn chú ý, thuộc tính Size của Report Header và Report Footer không bao giờ được vượt quá kích thước ở trên. Nếu bạn để các điều khiển tràn sang bên phải làm chiều ngang của các Section lớn hơn 8.27 dù chỉ 1 chút thôi thì thằng ReportViewer sẽ tự động chuyển loại giấy sang Letter và bạn sẽ không thể chỉnh lại được bằng nút Page Setup lúc chạy chương trình


Update

2.4 Sử dụng Report chuẩn với LINQ:
Như các phần trên các bạn đã thấy, khi tạo Report, trước hết ta phải chuẩn bị dữ liệu cho chúng (là các Datatable, Dataset). Nhưng khi làm việc với LINQ, các khái niệm như Datatable, Dataset đã không còn được sử dụng nữa. Vậy làm cách nào mà ta đưa được dữ liệu vào trong Report?
Các bạn vẫn có thể tạo ra các Datatable, rồi dùng vòng For hay một số phương pháp nào đó khác để đưa dữ liệu từ kết quả của các Query trong LINQ vào những datatable này để gán cho Report, nhưng cách này quả thực là rất phiền phức. Có một phương pháp khác nhanh hơn và đơn giản hơn để đưa dữ liệu từ LINQ vào Report. Đó chính là nội dung mà tôi sẽ hướng dẫn dưới đây:
A. Chuẩn bị
Giả sử tôi có một bảng trong CSDL là tbl_contact. Cách thức để tạo ra cái DataContext cho CSDL như thế nào thì cũng không cần nói nữa vì đây là 1 cái căn bản nhất của LINQ rồi. Tôi đã tạo ra 1 cái DataContext như sau trong chương trình của tôi:
datacontext.png
datacontext.png (9.96 KiB) Đã xem 29418 lần


Sau khi tạo DataContext cho CSDL, bạn thêm vào Project của mình các thành phần như sau:
+ 1 cái Winform: đặt tên là Form1.cs đi. Form này sẽ làm form hiển thị báo cáo
Trong Form1.cs, bạn kéo vào 1 cái Reportviewer (mặc đinh sẽ tên là Reportviewer1)
+ 1 cái Report: đặt tên là Report1.rdlc để hiển thị dữ liệu
Sau khi thêm vào các thành phần như trên, Project sẽ có dạng như sau:
solution_explorer.png
solution_explorer.png (12.02 KiB) Đã xem 29418 lần


B. Bắt đầu thiết kế Report:
+ Double Click vào Report1.rdlc trong Solution Explorer để mở Report ra trong chế độ thiết kế
+ Từ menu Data, chọn Add New Data Source để mở cửa sổ Data Source Configuration Wizard.
data_source_configuration_wizard.png

+ Trên cửa sổ vừa mở ra, chọn Object, rồi click Next
+ VS sẽ tự tìm các Object trong Project cho bạn (bao gồm cả cái tbl_contact trong DataContext bạn đã tạo ở trên). Bạn chỉ việc click vào dấu (+) ở tên Project để Expand cái Project của mình ra, tìm đến chỗ có tbl_contact. Chọn nó và click Finish.
data_source_configuration_wizard_2.png

+ Vậy là bạn đã có DataSource để thiết kế Report rồi. Nếu cửa sổ DataSource chưa xuất hiện, bạn có thể vào Menu: Data > Show Data Sources để hiện nó lên. Còn nếu đã nhìn thấy data source rồi, thì cứ kéo nó vào Report thôi
design_report.png


C. Viết Code để Show Report:
Sau khi thiết kế Report xong, bạn cần viết code để hiện cái Report này lên trên Form1 như sau:
  1. private void Form1_Load(object sender, EventArgs e)
  2.         {
  3. //Chỗ này là Select thuần túy trong LINQ
  4.             DataClasses1DataContext context =new DataClasses1DataContext();
  5.             List<tbl_contact> ContactList = (from c in context.tbl_contacts
  6.                                             select c).ToList();
  7. //bắt Reportviewer1 hiển thị cái Report1 ta vừa thiết kế
  8.             reportViewer1.LocalReport.ReportEmbeddedResource = "WindowsFormsApplication1.Report1.rdlc";
  9. //Gán datasource cho Report (bạn có thể gán List, Array, IENumerable... làm DataSource cho Report)
  10.             reportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("WindowsFormsApplication1_tbl_contact", ContactList));
  11.             reportViewer1.RefreshReport();
  12.         }
  13.  


Chạy chương trình, và bạn sẽ thấy Report xuất hiện.
Sửa lần cuối bởi thuongbat vào ngày T.Hai 18/04/2011 3:52 pm với 1 lần sửa.
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

boy1234
Guru
Guru
Bài viết: 435
Ngày tham gia: T.Hai 13/10/2008 3:12 pm
Đến từ: Dĩ An - Bình Dương
Been thanked: 24 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi boy1234 » CN 19/12/2010 12:07 pm

Mình có 1 thắc mắc! Không biết khi Preview chúng ta có thể quay ngang trang A4 được không (bên vb6.0 thì hơi rắc rối tí). Không biết bên vb.net có cải thiện vấn đề này không? Sr: vì spam nhé :D
Dạo này nghiện honda SS50

quangps
Thành viên năng nổ
Thành viên năng nổ
Bài viết: 52
Ngày tham gia: T.Hai 13/04/2009 5:25 pm

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi quangps » T.Hai 20/12/2010 8:55 am

xin lỗi bạn Thuongbat cho mình hỏi tí nhé.
mình thiết kế report theo hướng dẫn của bạn trên chuẩn .net như hình bên dưới đây:
Như bạn nhìn thấy mình có 2 bảng, bảng đầu tiên tạm gọi là bảng A , bảng thứ 2 là bảng ghi chú mình sẽ đổ dữ liệu từ CSDL lên 2 bảng này (mỗi bảng chứa dữ liệu của một bảng riêng đã được thiết kế trong CSDL).
bây giờ mình muốn trên Report sẽ in làm 2 cột (tiết kiệm giấy và cho đúng với mẫu báo cáo ấy mà) nhưng cột thứ 2 chỉ hiển thị nguyên dữ liệu tiếp theo của bảng thứ 2 vậy phải làm thế nào?
mong bạn giúp. Xin lỗi vì SPan bài nhé.
Tập tin đính kèm
aa.jpg

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Hai 20/12/2010 10:14 am

Theo cách sắp xếp của bạn thì dữ liệu từ bảng A sẽ in trên Table ở bên trái, còn dữ liệu từ bảng ghi chú sẽ in trên Table ở bên phải. Như vậy cũng tạo thành 2 cột rồi còn gì.
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Hai 20/12/2010 10:22 am

boy1234 đã viết:Mình có 1 thắc mắc! Không biết khi Preview chúng ta có thể quay ngang trang A4 được không (bên vb6.0 thì hơi rắc rối tí). Không biết bên vb.net có cải thiện vấn đề này không? Sr: vì spam nhé :D


THường thì khi tạo báo cáo, bạn đã thiết kế mẫu in của riêng mình thì cũng phải định kích thước sẵn cho khổ giấy (A4 hay A3....) và kiểu in (in dọc hay in ngang) rồi. Nếu bạn tạo báo cáo trên trang A4, in dọc mà khi in ra bạn lại chọn xoay ngang thì có phải sẽ thừa giấy không? Tuy nhiên, nếu bạn vẫn muốn xoay ngang giấy thì trên ReportViewer có nút PageSetup rồi đó. KHi đang Preview, bạn chỉ việc click vào nút PageSetup và chọn Orientation là LandScape thì giấy sẽ xoay ngang thôi (ngoài ra, bạn còn có thể đặt lề để canh chỉnh nội dung theo ý muốn)
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

quangps
Thành viên năng nổ
Thành viên năng nổ
Bài viết: 52
Ngày tham gia: T.Hai 13/04/2009 5:25 pm

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi quangps » T.Hai 20/12/2010 10:50 am

bạn hiểu sai ý mình hỏi rồi.giả sử bây giờ ở cột "ghi chú " có 50 dòng, nhưng ta chỉ cho phép nó in dữ liệu trên mỗi bảng (như đã thiết kế) là 20 dòng, như vây còn 30 dòng nữa, bây giờ mình muốn sẽ có thêm một cột "ghi chú nữa" trên cùng trang của report này. Vậy là in được 40 dòng của dữ liệu rồi, còn 10 dòng nữa thì nó sẽ in bên trang thứ 2...
Ý mình muốn làm là vậy. Thank ThuongBat vì đã trả lời bài nhé. :)

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Hai 20/12/2010 11:28 am

Cũng phải thừa nhận là mình chưa hiểu sâu về cái Report chuẩn này. Các hướng dẫn ở trên là những điều mình đã tìm hiểu được và muốn chia sẻ cùng các bạn. Qua đây mình cũng muốn các bạn trao đổi thêm để chúng ta cùng nâng cao kiến thức.
Về vấn đề của bạn: theo những gì mình đã biết thì việc chia phần Detail của report thành các cột sẽ được report xử lý trong toàn bộ nội dung của phần Detail. Có nghĩa là: nó sẽ in tất cả các dữ liệu ở trong Section Detail trên cột 1, sau khi in đến cuối trang thì dữ liệu sẽ được in sang cột 2 và in đầy cột 2 rồi mới nhảy sang trang tiếp theo. Trong section Detail của bạn có 2 bảng xếp ngang hàng nhau. Nếu bạn muốn cả 2 bảng đều được in ra đầy cột 1 rồi nhảy sang cột 2 thì bạn có thể xem hướng dẫn của mình ở bước 2.9. Còn nếu bạn muốn dữ liệu của bảng A in trên 1 cột, dữ liệu bảng Ghi chú in trên 2 cột thì mình không biết cách xử lý
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

quangps
Thành viên năng nổ
Thành viên năng nổ
Bài viết: 52
Ngày tham gia: T.Hai 13/04/2009 5:25 pm

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi quangps » T.Hai 20/12/2010 11:34 am

đúng là mình đang muốn thể hiển trên report như vậy nhưng thấy khó quá, dù sao cũng cảm ơn bạn rất nhiều.

Hình đại diện của người dùng
vuathongtin
Điều hành viên
Điều hành viên
Bài viết: 1024
Ngày tham gia: CN 02/05/2010 10:03 pm
Đến từ: Sở thông tin và truyền thông tỉnh Phú Yên
Has thanked: 2 time
Been thanked: 100 time
Liên hệ:

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi vuathongtin » T.Hai 20/12/2010 1:35 pm

thuongbat có biết cách hiển thị kiểu Boolean theo ý muốn của mình hok. Ví dụ : như mình hiển thị Cột Giới tính là Nam/Nữ
Bùi Thành Nhân
Chuyên viên CNTT - Sở Thông tin & Truyền thông tỉnh Phú Yên
giasulaptrinh.com

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Hai 20/12/2010 1:55 pm

có thể đặt giá trị cho cột giới tính như sau: trong Properties của cột giới tính, đặt Value là =IIf(Fields!GioiTinh.Value=True,"Nam","Nữ")
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

lubu08
Bài viết: 2
Ngày tham gia: CN 02/01/2011 3:57 pm

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi lubu08 » T.Ba 04/01/2011 12:58 am

@thuongbat: anh up file vidu lên đi
như thế anh em dễ tìm hiểu hơn

Hình đại diện của người dùng
nhunv.vbard
Thành viên chính thức
Thành viên chính thức
Bài viết: 38
Ngày tham gia: T.Ba 04/01/2011 10:41 am
Đến từ: HV Ngân hàng
Liên hệ:

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi nhunv.vbard » T.Ba 04/01/2011 10:49 am

@thuongbat: Em làm nhu­­ hu­o­ng dẫn mà không đu­o­c anh o­i, trong đoạn code của anh "Dim Parameters As List (Of ReportParameter)=Ne­­w List(Of Reportparameter)" thì nó gạch màu xanh du­oi tu "ReportParameter". Cái lỗi này thì làm gì để hết lỗi vậy anh? u đúng rồi anh port cả chuong trình lên đi anh. Thank anh rất nhiều.

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Ba 04/01/2011 11:18 am

+ Đối tượng ReportParameter nó nằm trong thư viện Microsoft.Reporting.WinForms. Bạn phải Import cái thư viện này ở đầu Form thì nó mới không bị lỗi
+ Về ví dụ mẫu: cái lúc trước mình thiết kế với CSDL là MySQL nên đưa ví dụ lên cũng hơi rắc rối. Đợi vài hôm nữa mình có thời gian sẽ viết một cái ví dụ cho các bạn với CSDL là Access
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

Hình đại diện của người dùng
lungocqua
Guru
Guru
Bài viết: 1225
Ngày tham gia: T.Ba 18/08/2009 11:51 am
Đến từ: Phú Hữu - Nhơn Trạch - Đồng Nai
Been thanked: 5 time
Liên hệ:

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi lungocqua » T.Ba 04/01/2011 11:42 am

Bài viết này của bạn hay đấy, trên diễn dàn đa số điều hỏi về Crystal Report, qua tới VB 2010 thì không thấy Crystal Report tích hợp vào nữa làm phải chạy đi tìm. Có cái này thì tiện thiết :)
Ta đã trở lại và quên hết tất cả! :D

Hình đại diện của người dùng
nhunv.vbard
Thành viên chính thức
Thành viên chính thức
Bài viết: 38
Ngày tham gia: T.Ba 04/01/2011 10:41 am
Đến từ: HV Ngân hàng
Liên hệ:

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi nhunv.vbard » T.Ba 04/01/2011 12:21 pm

thuongbat đã viết:+ Đối tượng ReportParameter nó nằm trong thư viện Microsoft.Reporting.WinForms. Bạn phải Import cái thư viện này ở đầu Form thì nó mới không bị lỗi
+ Về ví dụ mẫu: cái lúc trước mình thiết kế với CSDL là MySQL nên đưa ví dụ lên cũng hơi rắc rối. Đợi vài hôm nữa mình có thời gian sẽ viết một cái ví dụ cho các bạn với CSDL là Access

Thank anh nhiều nhé, em làm đu­­oc rồi, em hiện đang làm vó­i CSDL là SQL 2k5 có gì anh giúp nhé.

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Ba 04/01/2011 2:30 pm

Tranh thủ buổi trưa viết cái ví dụ mẫu cho các bạn nào quan tâm :)
Tập tin đính kèm
MSReportSample.rar
(203.3 KiB) Đã tải 3366 lần
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

Hình đại diện của người dùng
nhunv.vbard
Thành viên chính thức
Thành viên chính thức
Bài viết: 38
Ngày tham gia: T.Ba 04/01/2011 10:41 am
Đến từ: HV Ngân hàng
Liên hệ:

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi nhunv.vbard » T.Ba 04/01/2011 6:05 pm

VD này anh viết trên version bao nhiêu nhỉ, em mỏ­ bà­ng VB.net 2008 nó cho conver nhung không chạy đu­o­c, em soan nhu vi du trên thi nó nói nỗi ỏ­ phần "ReportVie­er1.LocalReport.SetParameters(Parameters)" lỗi là "An error occurred during local report processing" mà em xem lại rồi report thiết kế có sai chỗ nào đâu nhỉ, anh chỉ giúp vo­i. Thank

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 345
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 78 time

Re: Sử dụng Report chuẩn của .NET, tại sao không?

Gửi bàigửi bởi thuongbat » T.Ba 04/01/2011 9:27 pm

Mình viết trên VB2005. Mình chạy thử ngon lành rồi mới post lên. Có lẽ là trong quá trình convert nó đã có thay đổi gì đó chăng?
Bạn có thể thử cách sửa đổi nội dung file Solution bằng Notepad để cho nó lên VB2008 thay vì sử dụng cách Convert
+ Mở file MSReportSample.sln bằng Notepad
+ Sửa chỗ 9.0 thành 10.0
+ Sửa chỗ 2005 thành 2008
+ Save lại và mở bằng Visual Studio
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.


Quay về “[.NET] Bài viết hướng dẫn”

Đang trực tuyến

Đang xem chuyên mục này: Không có thành viên nào trực tuyến.0 khách