PDA

View Full Version : Sử Dụng DataGrid.Net - Phần II



lazy-programmer
24-01-2003, 15:33
Sử Dụng DataGrid.Net Phần II

Note: Bạn có thể download bài viết dạng .doc và sourcecode gởi kèm

3. Nắm Toàn Quyền Điều Khiển Giao Diện DataGrid.Net

Cho đến giờ, bạn đã có một Datagrid có Combobox ở cột SupplierID nhưng bạn không thể hiển thị tên của các Suppliers thay vì các ID, ngoài ra cấu trúc của các cột phụ thuộc vào cấu trúc của dataset. Bạn sẽ phải làm gì nếu muốn thay đổi thứ tự các cột (VD: đưa cột “Discontinued” lên đầu tiên?)

Bạn hãy xem giao diện được cải thiện như dưới đây:
(To see picture, download attached file)
So với phiên bản trước, phiên bản này có những cải tiến sau:

Các cột có thể di chuyển tới vị trí bất kỳ, không phụ thuộc vào cấu trúc của datasource (datatable) nữa. VD: Cột “Discontinued” được di chuyển lên vị trí đầu tiên.
Các header cột thể hiện tên tùy ý. VD: “Unit Price” thay vì “UnitPrice”.
Cột “Supplier” với tên đầy đủ của các nhà cung cấp thay cho cột “SupplierID” với những mã số kém trực quan.


Để thực hiện được việc này, trước hết chúng ta hãy xem qua một vài kỹ thuật có thể áp dụng được trong Datagrid.Net:


Datagrid.Net có hai dạng cột (column styles) có sẵn là Textbox (DataGridTextBoxColumn) và Checkbox (DataGridBoolColumn), bạn có thể tạo/thêm các cột này vào lúc thiết kế hay runtime. Nếu không, khi bạn gắn Datagrid vào CSDL, nó sẽ tự tạo ra các cột tương ứng với các cột dữ liệu theo cấu trúc của Dataset, nếu các cột có dữ liệu dạng False/True thì sẽ được hiển thị trong DataGridBoolColumn còn các dạng khác sẽ bị biến thành dạng text hết và hiển thị trong DataGridTextBoxColumn. Ngoài ra, bạn có thể tự tạo ra các column style khác (custom) và gắn vào datagrid (tôi sẽ đề cập tới vấn đề này trong một bài khác).
Các cột của Datagrid.Net có thể gắn kết với một cột dữ liệu (bound) hay hoàn toàn độc lập với CSDL. Để gắn chính xác một cột của Datagrid.Net với một cột trong datatable, ta sẽ sử dụng kỹ thuật Mapping Name - nghĩa là gán tên cột dữ liệu vào cột của Datagrid.
Ngoài ra ta cũng có thể thêm các cột dữ liệu unbound vào Datatable, các cột này sẽ không dùng để update CSDL chính mà chỉ dùng để thể hiện các dữ liệu theo ý của bạn.
Hình thức thể hiện (màu sắc, font chữ...) của Datagrid.Net có thể thay đổi thông qua các DataGridTableStyle gắn kết với nó. Xin các bạn xem lại đoạn code tạo và sử dụng TableStyle trong Phần I (ở thủ tục PopulateGrid()):
[/list=1]



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


Bây giờ chúng ta hãy bắt tay vào tạo dựng Datagrid của mình.

Bước 1: Thêm cột unbound “Supplier” vào datatable tblProducts

Trong thủ tục PopulateGrid(), sau phần tạo Combobox bạn thêm đoạn mã sau:



'Add an unbound column that comtain Combobox to main datatable
Dim dcolCombo As DataColumn

dcolCombo = New DataColumn("Supplier")
With dcolCombo
.DataType = System.Type.GetType("System.String")
.DefaultValue = ""
End With
tblProducts.Columns.Add(dcolCombo)


Lúc này cột dữ liệu mới thêm vào hoàn toàn trống rổng, bạn phải fill dữ liệu – tên các supplier – vào bằng cách gọi thủ tục:


FillUnboundColumn()

và viết code để fill tên Supplier tương ứng với SupplierID trong bảng “Products”. Hai thủ tục/hàm sau sẽ giúp bạn thực hiiện điều này:


Private Sub FillUnboundColumn()
Dim i As Integer
Dim dRow As DataRow

'Go to each row of unbound column "Supplier" and fill with meaningful data
For i = 0 To tblProducts.Rows.Count - 1
dRow = tblProducts.Rows(i)
'Fill "Supplier" column with supplier name inaccordance with SupplierID
dRow("Supplier") = FindSupplierName(dRow("SupplierID"))
Next

'Set default value for "SupplierID" column, so that when you add new row
'the Datagrid will behave correctly
tblProducts.Columns("SupplierID").DefaultValue = 1
End Sub

Private Function FindSupplierName(ByVal ID As Integer) As String
Dim i As Integer
Dim dRow As DataRow
For i = 0 To tblSuppliers.Rows.Count - 1
dRow = tblSuppliers.Rows(i)
If dRow(0) = ID Then
Return dRow(1).ToString
End If
Next
End Function

Bước 2: Tạo mới các column trong Datagrid

Như vậy hiện giờ tblProducts có 7 cột dữ liệu, để thể hiện chúng theo ý mình, bạn cần tạo ra 7 cột tương ứng trong Datagrid. Nếu bạn muốn cột đó có chứa CheckBox thì bạn tạo loại cột DataGridBoolColumn, còn không bạn tạo dạng DataGridTextBoxColumn. Ở đây ta muốn đưa cột “Discontinued” là dạng False/True lên đầu tiên để tiện theo dõi những hàng nào không còn đặt mua nữa. Ta thêm đoạn code sau vào ngay sau phần tạo và format DataGridTableStyle vừa trình bày ở trên:



Private Sub PopulateGrid()

If (Not dgdProducts.TableStyles.Contains("Products")) Then


Dim i As Integer
For i = 0 To 6
If i <> 0 Then
Dim gridcol As New DataGridTextBoxColumn()
dgdtblStyle.GridColumnStyles.Add(gridcol)
Else
Dim gridcol As New DataGridBoolColumn()
dgdtblStyle.GridColumnStyles.Add(gridcol)
End If
Next
End If
End Sub

Bước 3: Gán các cột trong datatable tblProducts vào các cột của Datagrid.Net

Sau khi tạo ra các cột, việc tiếp theo là chúng ta phải làm cho Datagrid hiểu cột nào sẽ thể hiện dữ liệu của cột nào trong datatable và định ra header text, chiều rộng của các cột. Thêm vào phần code như dưới đây:


Private Sub PopulateGrid()
...
If (Not dgdProducts.TableStyles.Contains("Products")) Then
...
...
'Mapping datagrid columns to column names of “tblProducts” and
'format header text and column width.
Dim colStyle As GridColumnStylesCollection

colStyle = dgdProducts.TableStyles(0).GridColumnStyles

colStyle(0).MappingName = "Discontinued"
colStyle(0).HeaderText = "Discontinued"
'
colStyle(1).MappingName = "ProductID"
colStyle(1).HeaderText = "Product ID"
'
colStyle(2).MappingName = "ProductName"
colStyle(2).HeaderText = "Product Name"
colStyle(2).Width = 150
'
colStyle(3).MappingName = "Supplier"
colStyle(3).HeaderText = "Supplier"
colStyle(3).Width = "150"
'
colStyle(4).MappingName = "QuantityPerUnit"
colStyle(4).HeaderText = "Quantity"
'
colStyle(5).MappingName = "UnitPrice"
colStyle(5).HeaderText = "Unit Price"
'
colStyle(6).MappingName = "SupplierID"
colStyle(6).Width = 0
End If

'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. Supplier).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(3)

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

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


=>Ở đây bạn lưu ý hai điểm sau:
[list]
Cột SupplierID được đưa ra sau cùng và có chiều rộng là 0, nghĩa là người sử dụng sẽ không thấy được cột này.
Bạn phải đặt DataSource cho datagrid sau khi đã mapping name nếu không khi chạy chương trình sẽ báo lỗi là không thể Mapping name được vì tên này đã có rồi.

Bước 4: Bỏ qua hoàn toàn cột SupplierID

Mặc dù ở bước trên, bạn đã cho cột SupplierID ẩn dấu nhưng nó chưa thực sự “biến mất” hoàn toàn. Nếu bạn dùng tab di chuyển giữa các ô của Datagrid bạn sẽ nhận thấy nó vẫn dừng lại ở cột cuối cùng dù không nhìn thấy. Để bỏ qua cột này, chúng ta phải thêm một thủ tục để khi một cell trong cột này nhận focus nó sẽ chuyển ngay focus về cell của cột đầu tiên, hàng tiếp theo.

Muốn vậy, bạn thêm một handler điều khiển việc nhận focus của textbox trong cột SupplierID (cột 6). Gõ vào đoạn mã này vào cuối thủ tục PopulateGrid():


'Add handlers to control grid navigation so that all hided columns will be passed by
dgtb = dgdProducts.TableStyles(0).GridColumnStyles(6)
AddHandler dgtb.TextBox.GotFocus, AddressOf Col6_GotFocus

Và viết thủ tục Col6_GotFocus:


Private Sub Col6_GotFocus(ByVal sender As Object, ByVal e As EventArgs)
Dim colnum As Integer = dgdProducts.CurrentCell.ColumnNumber
If colnum <> 6 Then Exit Sub

'Set focus to the cell of first column, next row
Dim cell As New DataGridCell(dgdProducts.CurrentRowIndex + 1, 0)
dgdProducts.CurrentCell = cell
End Sub

Bước 5: Làm cho ComboBox cập nhật đúng dữ liệu

Khi bạn chọn một item mới trong ComboBox ở cột “Supplier”, ComboBox sẽ phải cập nhật phần Text vào cột “Supplier” (cột 3) và phần Value vào cột “SupplierID” (cột 6). Bạn sửa lại hai thủ tục cboSupplier_VisibleChanged và cboSupplier_SelectionChanged như sau:


Private Sub cboSupplier_VisibleChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim cbo As ComboBox = sender
Dim rownum As Integer = dgdProducts.CurrentRowIndex

Dim intSupplierID As Integer = 0
Try
intSupplierID = dgdProducts.Item(rownum, 6).ToString()
Catch Err As Exception
'Do nothing here
Finally
cbo.SelectedValue = intSupplierID
End Try
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

'Set value to column "SupplierID"
dgdProducts.Item(rownum, 6) = cbo.SelectedValue
'Set value to unbound column "Supplier"
dgdProducts.Item(rownum, 3) = cbo.Text
End Sub

Bước 6: Cập nhật CSDL gốc

Đến đây bạn đã có một Datagrid.Net với giao diện hoàn chỉnh. Nhưng như bạn đã biết, ADO.Net là dạng disconnected nên những gì bạn sửa đổi ở trên giao diện chỉ có tác dụng khi bạn update CSDL gốc bằng một thủ tục tường minh. Thiết nghĩ các bạn quá rành việc này rồi (còn nếu chưa xin các bạn tham khảo các cuốn sách về VB.Net). Trong phần tutorial này tôi xin nhường cho các bạn viết thủ tục update này vì không muốn là hỏng CSDL Northwind.mdb.

Cảm ơn các bạn đã đọc.

xbacala
06-02-2003, 12:32
Bài viết của bạn khá hay đó !

Thông thường, với những chương trình đòi hỏi giao diện phức tạp thì DataGrid của MS không thể đáp ứng được. Theo tôi, chúng ta có thể sử dụng những DataGrid có độ chuyện nghiệp cao hơn như:
- NetAdvantage
- ComponentOne
- Janus
- GidX
- . . .
Các thành phần này không có free nhưng có rất nhiếu đã được ***** và post lên Internet, việc tìm và download không có khó khăn gì lắm !

TDCT
17-02-2003, 16:44
Dưới dạng .dll hay là source code dzậy huynh?

xbacala
23-02-2003, 12:34
DLL. Chỉ 1 số có source code thôi, viết bằng C++ hoặc C#. Nhưng mà làm sao đọc nổi mà đọc. Học cách sử dụng thôi là ngất ngư rồi ! :D

anhquan
31-03-2003, 16:36
thế bạn có thể cho biết địa chỉ download bản ***** của các tool đó không. thanx.

ham_tim_hieu
16-04-2003, 08:20
Cho tôi hỏi thêm và DataGrid với
- làm thế nào kiểm soát hay ngăn chặn việc thêm hay xoá 1 dòng trong grid mà trong khi vẫn có thể sửa được các ô hiện có ( có nghĩa là thuộc tính ReadOnly vẫn phải đặt là False)
- khi thêm 1 ô CheckBox vào 1 cell, nó sẽ có 3 trạng thái Check, Uncheck và Gray. Làm thế nào để bỏ cái Gray đi, chỉ để lại 2 trạng thái Check, Uncheck thôi.

hyvongmauxanh
20-04-2003, 19:59
Chúng mày sao ngu như bò thế hả. Bộ điên hết rồi à. Cái thằng ViKhoa gì đó, kinh doanh mắc như chó. Chỉ lợi dụng các bạn thôi, công nhận làm chỗ sân chơi cũng tốt, nhưng lừa bịp lợi dụng bạn bè hơi bị nhiều. Có ngày tao sẽ kill cái trang web này. Còn mấy thằng bên box ***curity gì đó, ngu cả một lũ, để trang web bị hack hoài. Đúng là một lũ thùng rỗng kêu to. Một lũ mất dạy. Chúc tụi bay vui vẻ nhé.

huonglan
21-04-2003, 09:06
Hi ham_tim_hieu!
Bạn không cần phải ReadOnly, chỉ cần khóa việc thêm và xóa trong DataGrid thôi.

CurrencyManager cm = (CurrencyManager)this.BindingContext[dataGrid1.DataSource,dataGrid1.DataMember];
((DataView)cm.List).AllowNew=false; //không được thêm,
((DataView)cm.List).AllowDelete=false;// không được xóa

hoangminh
02-05-2003, 12:13
Anh lazy-programmer oi cho em xin phần "Sử Dụng DataGrid.Net Phần I" di, hiện giờ em chi co "Sử Dụng DataGrid.Net Phần II" thoi, mail cua em la hoangminh0317@yahoo.com cam on anh nhiều!

lazy-programmer
03-05-2003, 11:14
Bạn cho mình d/c e-mail, mình sẽ gởi bạn toàn bộ bài viết và sourcecode.

hoangminh
04-05-2003, 16:29
Mail cua em la hoangminh0317@yahoo.com cam on anh nhieu!

vanlang
12-05-2003, 14:34
gửi cho mình nữa nhé pharaoh_diamic@yahoo.com

buitrungtin
16-05-2003, 14:36
xin lỗi các bạn cho kẻ mù này nói vài câu ngu muội theo kiểu "kẻ ngoại đạo". Tui mới vừa phát hiện ra là datagrid có hỗ trợ sử dụng tamplate nên nếu muốn tạo một combobox trong data grid thì chỉ cần làm như sau: (cái đoạn này tui copy and paste trực tiếp từ vs.net ra, đoạn này auto generated by vs.net khi tui thiết kế trong design view):


<asp: DataGrid id="DataGrid2" style="Z-INDEX: 102; LEFT: 407px; POSITION: absolute; TOP: 187px" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateColumn>
<ItemTemplate>
<asp: DropDownList id="DropDownList2" runat="server"></asp: DropDownList>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp: DataGrid>



vậy là ta có một cột combo box ngon lành, có điều.....tui vẩn chưa catch được cái event khi mà selected index của combo box changed. tui đã coi documentation nhung cũng làm không ra vì khi thử thì event handler của datagrid là ItemCommand không có tác dụng chi ráo (không catch được event nào từ combo box ở trong)
nếu bạn nào có ngiên cứu qua, xin chỉ giúp. càng sớm càng tốt.
đa tạ,

buitrungtin
16-05-2003, 20:38
xin phép tự diễn luôn, tuy chưa thử nhưng tui nghĩ là do tui quen gắn cái attribute "commandName" vô nên datagrid không chịu nhân event từ dropdownlist, ngày mai lên trường sẽ thử. nếu các bạn không thấy nói năng gì ráo tức là tui đã nghĩ đúng rồi đó.
như vậy đaọn trên nên thêm một cái attribute như sau:

<asp: DataGrid id="DataGrid2" style="Z-INDEX: 102; LEFT: 407px; POSITION: absolute; TOP: 187px" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateColumn>
<ItemTemplate>
<asp: DropDownList id="DropDownList2" commandName="DropDownListCommand2" runat="server"></asp: DropDownList>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp: DataGrid>

vp209
19-05-2003, 19:47
Bạn xbacala hoặc nào co ***** hoặc địa chỉ của ***** cho minh xin với. Cám ơn nhiều
- NetAdvantage
- ComponentOne
- Janus
- GidX
mail cho minh la vp209@yahoo.com

buitrungtin
19-05-2003, 20:33
tui vân chưa có điều kiện thử nên không biết có đúng không, cáo lỗi.

buitrungtin
25-05-2003, 16:52
sorry bà con, Lazy Programmer đang nói về datagrid trong windows form mà tui làm biếng đọc quá nên tưởng là trong ASP.Net.
Cáo lỗi,

tcvn_hack
10-03-2006, 15:24
chào mọi người tui tham gia với, mới bắt đầu tập tành VB.Net mong mọi người chỉ giáo

DTNGA75
04-12-2007, 15:07
xin chao
cac ban co the cho minh hoi 1 cau dc ko
lam the nao minh co the hien thi du lieu trong combobx khi minh dua no vao datagrid, minh muon ,khi click vao combobox thi du lieu se hien thi o cac cot con lai cua datagrid

DTNGA75
04-12-2007, 15:08
minh moi hoc vb nen ko ranh lam
mong cac ban chi dum minh
cam on nhieu

thuanchinapro07
30-06-2013, 00:29
Hi
Mình Có cell cần check dữ liệu nếu dữ liệu nhập sai yêu cầu thì không cho rời khỏi cell , nhập đúng cho next sang cell khác.
bạn có giải pháp nào giúp mình với
Cảm ơn vì bài viết của bạn.