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

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

1. Đặt vấn đề:

Mình tìm trên mạng 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:

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:

Đâ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

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 ).
+ 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

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

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

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

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:

+ 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”

 private void Button1_Click(System.Object sender, System.EventArgs e)
{
	DataTable dt = null;
	//datable dùng để query dữ liệu từ database và gán vào report
	CMySqlDao oDb = 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
	string sql = null;
	//câu sql cần query
	sql = "SELECT * FROM tbl_call_log";
	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
	//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
	if ((txtCallerId.TextLength > 0)) {
		sql += " AND caller LIKE '" + oDb.Quote(txtCallerId.Text.Replace("*", "%")) + "'";
	}
	dt = oDb.ExecuteSql(sql);
	//truy vấn vào CSDL để lấy dữ liệu vào Datatable
	ReportViewer1.Reset();
	//reset cái Reportviewer
	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)
	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)
	Microsoft.Reporting.WinForms.ReportDataSource newDataSource = 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.
	ReportViewer1.LocalReport.DataSources.Add(newDataSource);
	//gán DataSource mới tạo vào Report
	List<ReportParameter> Parameters = new List<ReportParameter>();
	//Tạo danh sách các Parameter để truyền cho Report
	ReportParameter param = default(ReportParameter);
	param = new ReportParameter("fromDate", dtpFromDate.Value.ToString("dd/MM/yyyy"));
	//parameter "FromDate" của report
	Parameters.Add(param);
	param = new ReportParameter("toDate", dtpToDate.Value.ToString("dd/MM/yyyy"));
	//parameter "ToDate" của report
	Parameters.Add(param);
	param = new ReportParameter("phoneNumber", txtCallerId.Text);
	//parameter "PhoneNumber" của Report
	Parameters.Add(param);
	ReportViewer1.LocalReport.SetParameters(Parameters);
	//gán danh sách các Parameter vào Report
	ReportViewer1.RefreshReport();
	//gọi RefreshReport() để bắt đầu hiển thị
	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.
	ReportViewer1.SetDisplayMode(DisplayMode.PrintLayout);
	//bắt Reportviewer hiển thị ở chế độ PrintLayout (trông sẽ đẹp mắt hơn)
	ReportViewer1.ZoomMode = ZoomMode.Percent;
	//đặt chế độ Zoom cho report là theo phần trăm
	ReportViewer1.ZoomPercent = 100;
	//và zoom nó lên 100%
} 

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

Trông cũng không đến nỗi tệ phải không các bạn.

Bạn thấy bài viết này như thế nào?: 
Average: 6.2 (159 votes)
Ảnh của Tommy Tran

Tommy owner Express Magazine

Drupal Developer having 9+ year experience, implementation and having strong knowledge of technical specifications, workflow development. Ability to perform effectively and efficiently in team and individually. Always enthusiastic and interseted to study new technologies

  • Skype ID: tthanhthuy

Bình luận (0)

 

Add Comment

Filtered HTML

  • Các địa chỉ web và email sẽ tự động được chuyển sang dạng liên kết.
  • Các thẻ HTML được chấp nhận: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Tự động ngắt dòng và đoạn văn.

Plain text

  • No HTML tags allowed.
  • Các địa chỉ web và email sẽ tự động được chuyển sang dạng liên kết.
  • Tự động ngắt dòng và đoạn văn.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.

Advertisement

 

jobsora

Dich vu khu trung tphcm

Dich vu diet chuot tphcm

Dich vu diet con trung

Quảng Cáo Bài Viết

 
Nhìn lại 12 tháng đầy những biến động của Apple

Nhìn lại 12 tháng đầy những biến động của Apple

2011 có thể là năm đáng nhớ nhất trong lịch sử Apple, với nhiều sự kiện và biến động. Ngoài những thành công đạt được với các sản phẩm mới...

34 câu hỏi về iPad mới (Phần 1)

34 câu hỏi về iPad mới (Phần 1)

Giải đáp thắc mắc về màn hình Retina, độ phân giải, camera và chất lượng Facetime, RAM,... trong iPad mới đời 2012.

Giới thiệu Warm Introduction to the Drupal Community

Giới thiệu Warm Introduction to the Drupal Community

The Drupal Community is an incredibly friendly, welcoming place. 

Công ty diệt chuột T&C

 

Diet con trung