PDA

View Full Version : Sử Dụng Datagrid.Net (Phần I)



lazy-programmer
12-01-2003, 10:42
Sử Dụng DataGrid Trong .Net để có một giao diện chuyên nghiệp (Phần I)

Đây là một bài viết dài (Sorry) nhưng rất chi tiết và đầy đủ - Bạn co thể download file .zip có bài viết này dưới dạng .doc với đầy đủ hình ảnh và source code

Có lẽ bất kỳ ai đã từng lập trình CSDL trong Access cũng đều phải thừa nhận sự dễ dàng trong thiết kế giao diện. Đặc biệt là khi sử dụng các Grid với các ComboBox phát sinh tự động (miễn là bạn định nghĩa trường Lookup trong khi thiết kế các Table).

Lập trình CSDL trong Visual Basic có nghĩa là bạn phải làm “thủ công” mọi chuyện. Có lẽ không có kỹ thuật nào hay thay đổi như kỹ thuật truy cập dữ liệu của Microsoft, từ RDO, đến ADO, và hiện nay là ADO.Net – điều đó có nghĩa là bạn phải luôn cập nhật, đổi mới cách lập trình của mình. Dù sao, .Net cũng là một bước nhảy lớn trong kỹ thuật lập trình và có lẽ cũng đáng để mắt một chút tới các thay đổi trong CSDL và các Control liên quan. Trong loạt bài này (hưởng ứng “Chương Trình Sao” của Sticky) tôi mong muốn chia sẻ một số kinh nghiệm khi sử dụng DataGrid, một công cụ không thể thiếu trong lập trình CSDL để giúp bạn có được một công cụ uyển chuyển và mạnh.

Tuy nhiên, đây chỉ là kỹ thuật nền tảng, không phải là giải pháp tối ưu vì vậy rất mong được sự góp ý thêm của các bạn và, nếu có thể, cùng nhau tạo ra các control đóng gói (thành các class) giúp giảm thời gian coding cho mọi nguời.


1. Giới thiệu về Datagrid.Net

Khi lập trình CSDL trong VB6, hiếm khi các nhà phát triển sử dụng Datagrid có sẵn của Microsoft mà thường phải dùng các Grid thương mại của các third-party (như FlexGrid, TrueDBGrid, Janus GridEX…) vì nó thiếu các chức năng cao cấp như tạo các cột có chứa hình ảnh, có các Drop-down combo…

Ấn tượng đầu tiên khi tiếp xúc với Datagrid của .Net là dường như nó không có gì thay đổi cả, vẫn chỉ là các cột “cứng” dùng để hiển thị các dữ liệu thô trong các bảng CSDL. Khi sử dụng các Grid dưới dạng các ActiveX trong .Net dữ liệu thường không được hiển thị tốt (nhất là khi cần định dạng) và nói chung các ActiveX control chạy không tốt lắm trong môi trường .Net, đa số lại không hỗ trợ Unicode - một tính năng tối cần thiết cho các LTV Việt Nam. Chính vì thế tôi phải quay về với Datagrid của .Net và thật may mắn tôi tìm thấy một số bài viết về cách mở rộng chức năng của nó trên Internet. Thì ra khác với vẻ ngoài của mình, Datagrid.Net là một Grid “mở”, bạn có thể:


Định dạng dữ liệu cho từng cột (kg có gì mới)
Các cột có thể là bound (tức là gắn với một field dữ liệu trong bảng) hay unbound (cột độc lập với dữ liệu - rất tốt khi để hiển thị các trường tính toán hay các trường định dạng đặc biệt)
Gắn các control khác vào mỗi cột (như Combobox, Datetimepicker…)
Và một chức năng cao cấp khác là tạo ra hẳn một Style Column - dạng cột mới.
[/list = 1]

Trong Datagrid.Net chỉ có hai ColumnStyle được build-in là: Textbox ColumnStyle và Checkbox ColumnStyle. Chắc các bạn cũng đoán ra chức năng của hai dạng cột này, một là để hiển thị các dữ liệu dạng text hay date/time, và cái kia là để hiển thị dữ liệu false/true dưới hình thức các checkbox. Một giải pháp hoàn chỉnh có lẽ là tạo ra các dạng cột mới để hiển thị các dữ liệu theo ý mình, nhưng nó đòi hỏi bạn phải viết các Class, events… mới khá phức tạp (tôi sẽ viết về vấn đề này trong một bài riêng). Tuy nhiên, ở mức độ phát triển ứng dụng nhanh và nếu bạn muốn tác động trực tiếp tới các hành vi của Datagrid.Net thì tốt nhất là bạn sử dụng ngay những cái có sẵn – chúng đủ mạnh cho hầu hết các chức năng thông thường. Trong phần sau, tôi sẽ trình bày một số kỹ thuật/thủ thuật để bạn có thể tạo ra các cột có chứa Combobox, Checkbox, Date Picker, hình ảnh và cho ẩn dấu các cột không cần thiết.


2. Tạo cột có chứa Combobox, Checkbox

Note:

- Để đơn giản hoá việc truy cập dữ liệu, các ví dụ ở đây đều sử dụng các table trong CSDL Access Northwind.mdb (bạn có thể tìm thấy CSDL này trong thư mục Samples của bộ Office)
- Trong phần này tôi giả sử bạn đã biết về lập trình CSDL trong VB.Net và sẽ không giải thích thêm về các khái niệm như data connection, data adapter hay dataset…

Bước 1: Tạo một dự án mới có tên FlexibleDatagrid trong Visual Basic.Net, đổi tên của Form1 thành “frmProducts” và Text (caption) thành “Product Grid”.

Bước 2: Tạo Dataset có chứa table “Products” là datasource cho Grid: Thêm vào một OleDataAdapter1, khi wizard hiện lên bạn kết nối vào CSDL Northwind.mdb, chọn table “Products”, SELECT các fields: ProductID, ProductName, SupplierID, QualityPerUnit, UnitPrice và Discontinued. Trong phần “Advanced Options…” bạn nhớ đánh dấu hộp kiểm “Generate Insert, Update, Delete statements” (mặc định), sau đó phát sinh (generate) table “Products” vào Dataset1.

Bước 3: Tạo table “Suppliers” dùng để làm datasource cho Combobox: Thêm vào một OleDataAdapter2, khi wizard hiện lên bạn kết nối vào CSDL Northwind.mdb, chọn table “Suppliers”, SELECT các fields: SupplierID, CompanyName. Trong phần “Advanced Options…” bỏ dấu hộp kiểm “Generate Insert, Update, Delete statements”, sau đó phát sinh (generate) table Suppliers vào Dataset1.

Bước 4: Thêm vào form một Datagrid control và đổi tên nó thành dgdProducts, đặt Dock = Fill để nó nở ra chiếm hết form.

Bước 5: Thêm vào các thủ tục để connect với database, nạp dữ liệu vào Dataset (Microsoft way):



Private Sub LoadDataset()
'Create a new dataset to hold the records returned from the call to FillDataSet.
'A temporary dataset is used because filling the existing dataset would
'require the databindings to be rebound.
Dim objDatasetTemp As FlexibleDatagrid.DataSet1
objDatasetTemp = New FlexibleDatagrid.DataSet1()

Try
'Attempt to fill the temporary dataset.
Me.FillDataSet(objDatasetTemp)
Catch eFillDataset As Exception
Throw eFillDataset
End Try

Try
'Empty the old records from the dataset.
DataSet11.Clear()
'Merge the records into the main dataset.
DataSet11.Merge(objDatasetTemp)
Catch eLoadMerge As Exception
Throw eLoadMerge
End Try
End Sub

Private Sub FillDataset(ByVal dataSet As FlexibleDatagrid.DataSet1)
'Turn off constraint checking before the dataset is filled.
'This allows the adapters to fill the dataset without concern
'for dependencies between the tables.
dataSet.EnforceConstraints = False
Try
'Open the connection.
Me.OleDbConnection1.Open()
'Attempt to fill the dataset through the OleDbDataAdapter1.
Me.OleDbDataAdapter1.Fill(dataSet)
'Attempt to fill the dataset through the OleDbDataAdapter2.
Me.OleDbDataAdapter2.Fill(dataSet)
Catch fillException As System.Exception
'Add your error handling code here.
Throw fillException
Finally
'Turn constraint checking back on.
dataSet.EnforceConstraints = True
'Close the connection whether or not the exception was thrown.
Me.OleDbConnection1.Close()
End Try
End Sub


Gọi thủ tục LoadDataset vào lúc load form:




Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
Try
LoadDataset()
Catch loaddataException As Exception
MessageBox.Show(loaddataException.Message)
'Close form if there is error in loading data
Me.Close()
End Try
End Sub

Bước 6: Tạo một Combobox, fill với dữ liệu từ table “Suppliers” và gằn Combobox này vào cột SupplierID

Tạo hai biến chung chứa các table Products và Suppliers:


Dim tblProducts, tblSuppliers As DataTable

Tạo một thủ tục có tên PopulateGrid() và thêm vào đoạn mã sau:


Private Sub PopulateGrid()
tblProducts = DataSet11.Tables("Products")
tblSuppliers = DataSet11.Tables("Suppliers")

'Create new ComboBox, fill it with data from table "Suppliers"
Dim cboSupplier As New ComboBox()

With cboSupplier
.DropDownStyle = ComboBoxStyle.DropDownList
.Dock = DockStyle.Fill
.DataSource = tblSuppliers
.ValueMember = tblSuppliers.Columns(0).ToString
.DisplayMember = tblSuppliers.Columns(1).ToString
End With



'set style property when first time the grid loads, next time onwards it
'will maintain its property
If (Not dgdProducts.TableStyles.Contains("Products")) Then
'Create a DataGridTableStyle object
Dim dgdtblStyle As New DataGridTableStyle()

'Set its properties
dgdtblStyle.MappingName = tblProducts.TableName 'its table name of dataset
dgdProducts.TableStyles.Add(dgdtblStyle)
dgdtblStyle.AlternatingBackColor = Color.Yellow
dgdtblStyle.AllowSorting = True
dgdtblStyle.RowHeadersVisible =
dgdtblStyle.HeaderFont = New System.Drawing.Font("Microsoft Sans Serif", 9.0F, System.Drawing.FontStyle.Bold, GraphicsUnit.Point, 0)
dgdtblStyle.GridLineColor = Color.DarkGray
dgdtblStyle.PreferredRowHeight = 22
dgdProducts.BackgroundColor = Color.White
End If

'Set DataGrid source as the table "Products"
dgdProducts.DataSource = tblProducts

'To add the combo box dynamically to the data grid, you have to take the
'Text Box that is present (by default) in the column where u want to add
'this combo box (here it is third column i.e. SupplierID).From the
'tablestyles of the data grid take the grid column styles of the column
'where you want to add the combo box respectively.

Dim dgtb As DataGridTextBoxColumn = dgdProducts.TableStyles(0).GridColumnStyles(2)

'Add the combo box to the text box taken in the above step
dgtb.TextBox.Controls.Add(cboSupplier)
End Sub

Cuối cùng bạn gọi thủ tục này sau khi load dataset:


Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)

PopulateGrid()
End Sub

Cho chạy chương trình, khi bạn vào cột “SupplierID”, một Combobox sẽ hiện ra với tên các nhà cung cấp như hình dưới đây:


Figure 1: Product Grid with ComboBox in SupplierID column

Bước 7: Làm cho ComboBox phản ánh dữ liệu trong từng cell

Khi chạy chương trình bạn có thể nhận thấy ngay là mặc dù Combobox có xuất hiện nhưng các Supplier mà nó hiển thị chẳng “ăn nhập” gì với dữ liệu trong cột và khi bạn chọn một nhà cung cấp mới thì mã nhà cung cấp trong cột SupplierID cũng không được cập nhật. Để thực hiện điều này bạn phải thêm vào hai thủ tục:
[list]
(1) Thủ tục làm cho khi ComboBox hiện ra, nó sẽ phản ánh Supplier phù hợp với SupplierID
(2) Thủ tục khi có sự thay đổi khi chọn Supplier mới, mã trong cột SupplierID sẽ được cập nhật.

Bạn có thể làm điều này qua hai event của ComboBox là: VisibleChanged và SelectionChangeCommitted. Bạn thêm vào hai Handler vào ngày dưới phần khởi tạo Combobox trong thủ tục PopulateGrid() như sau:


With cboSupplier
.DropDownStyle = ComboBoxStyle.DropDownList
.Dock = DockStyle.Fill
.DataSource = tblSuppliers
.ValueMember = tblSuppliers.Columns(0).ToString
.DisplayMember = tblSuppliers.Columns(1).ToString
End With

'Add handlers to ComboBox
AddHandler cboSupplier.VisibleChanged, AddressOf cboSupplier_VisibleChanged
AddHandler cboSupplier.SelectionChangeCommitted, AddressOf cboSupplier_SelectionChanged

Và viết các thủ tục tương ứng:


Private Sub cboSupplier_VisibleChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim cbo As ComboBox = sender
If cbo.Visible = True Then
Dim rownum As Integer = dgdProducts.CurrentRowIndex
If rownum < tblProducts.Rows.Count Then
cbo.SelectedValue = tblProducts.Rows(rownum).Item(2)
Else
cbo.SelectedIndex = 0
End If
End If
End Sub

Private Sub cboSupplier_SelectionChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim cbo As ComboBox = sender
Dim rownum As Integer = dgdProducts.CurrentRowIndex
dgdProducts.Item(rownum, 2) = cbo.SelectedValue
End Sub


Giờ bạn đã có một Datagrid với ComboBox khá hoàn chỉnh. Tuy nhiên, nó có những hạn chế sau:

Người dùng không thấy được tên các nhà cung cấp (trừ phi nhấp vào cột SupplierID) mà chỉ thấy mã nhà cung cấp – các con số kém trực quan.

Các cột và Header cố định và phụ thuộc vào cấu trúc của datasource.

Trong phần tiếp theo tôi sẽ trình bày cách mà bạn có thể hiển thị tên các Supplier thay vì các ID và cách nắm toàn quyền việc hiển thị dữ liệu trong Datagrid.Net

Cảm ơn các bạn đã đọc bài viết này.

quangvu
22-01-2003, 08:29
Bài khá hay ,nhưng sau không tiếp tục đi chớ ?

Cyber
23-01-2003, 14:29
Làm ơn cho hỏi với nếu viết
dgdProducts.DataSource = tblProducts
thì các column trong datagrid có tên là tên các fields trong database như thế không đẹp lắm. Nếu muốn thay đổi thì làm thế nào. Tôi tìm mãi mà không thấy

lazy-programmer
24-01-2003, 09:49
Mình sẽ đề cập tới vấn đề này trong Phần II, sorry vì dạo này cuối năm hơi bận nên không tập trung viết dc.

Cyber
25-01-2003, 12:00
nhanh len nhe. :)

KeDuMuc
23-07-2004, 18:27
Có huynh nào có bản Licence của "DataGridColumn.DLL( trên www.RustemSoft.com)" không. Nó để chèn Hình, ComboBox, CheckBox, Memo... vào DataGrid.
Nếu có cho đệ xin vơí, đang cần gấp để hoàn thành đồ án, không có chắc tiêu quá.

Trên trang www.RustemSoft.com chỉ có bản demo thôi,sau 1 tháng nó cắt. Lúc đầu đệ không biết nên đã dùng nó khá nhiêù trong Đồ án. Giờ gần xong rồi thì nó không cho dùng nữa.
Nếu không kiếm được bản Licence chắc phải viết lại cái DA qúa.
Cưú đệ với mấy huynh ơi.
Nếu ai có bản Licence, xin mail cho đệ: thaychua31@yahoo.com
Xin hậu tạ.

zhiivn
24-07-2004, 09:46
Cho mình xin file zip được không? Thanks.

KeDuMuc
24-07-2004, 10:07
Bạn lên ngay trang chủ của nó có phần cho bạn Down liền đó.

hungK35A
28-07-2004, 07:29
Trang nàoooooooooooooo ???

PoorKidDinosaur
28-07-2004, 07:39
chắc chắn sửa được tên field trong dataGrid đó, vọc đi. Tui làm rồi, mò 2 tiếng mới ra được.

hueduongit
28-07-2004, 23:12
Đâu có thấy file zip nào đâu!? ~)

minhnhat2807
29-12-2007, 09:34
Làm ơn cho hỏi với nếu viết
dgdProducts.DataSource = tblProducts
thì các column trong datagrid có tên là tên các fields trong database như thế không đẹp lắm. Nếu muốn thay đổi thì làm thế nào. Tôi tìm mãi mà không thấy

C1: bạn có thể select FieldColumn as [Tên bạn muốn] trong SQL Server
C2: trên tầng xử lí bạn phải tạo 1 Table mới sau đó đổ sữ liệu từ Table kia vào, cuối cùng thì gán vào DataGridView
C3: bạn dung Control DataGrid trong phần mềm DevExpress tích hợp vào Visual, có trên mạng

willse7en
29-12-2007, 20:21
híc, có ai thấy cái file zip nó nằm ở đâu ko zậy

xsamxungx
31-12-2007, 13:10
Làm ơn cho hỏi với nếu viết
dgdProducts.DataSource = tblProducts
thì các column trong datagrid có tên là tên các fields trong database như thế không đẹp lắm. Nếu muốn thay đổi thì làm thế nào. Tôi tìm mãi mà không thấy

bạn có thế xét thuộc tínnh of datagrid.Columns["tên trong database "].HeaderText = "Tên tên cần hiển thị";

duonghungictu
25-10-2008, 00:58
sao ko thây file zip nhỉ? bài rất hay?