209
MC LC Phn 1 Cơ bn v ngôn ng lp trnh C#..................4 Bi thc hnh 1.1. Chương trnh đu tiên...........................................................4 Tóm tắt...............................................4 Kỹ thut được trnh bày...............................4 Trnh tự thực hiện....................................4 Bi thc hnh 1.2. Module ha chương trnh.....................................................6 Tóm tắt...............................................6 Kỹ thut được trnh bày...............................6 Trnh tự thực hiện....................................6 Bi thc hnh 1.3. Tạo thư viện sử dụng chung.................................................8 Tóm tắt...............................................8 Kỹ thut được trnh bày...............................8 Trnh tự thực hiện....................................8 Mở rộng...............................................9 Bi thc hnh 1.4. Tam gic Pascal....................................................................10 Tóm tắt..............................................10 Kỹ thut được trnh bày..............................10 Trnh tự thực hiện...................................10 Mở rộng..............................................11 Bi thc hnh 1.5. Tam gic Pascal – array version.........................................12 Tóm tắt..............................................12 Kỹ thut được trnh bày..............................12 Trnh tự thực hiện...................................12 Mở rộng..............................................12 Bi thc hnh 1.6. MyTYPE...................................................................................13 Tóm tắt..............................................13 Kỹ thut được trnh bày..............................13 Trnh tự thực hiện...................................13 Mở rộng..............................................13 Bi thc hnh 1.7. Qun l sinh viên..................................................................14 Tóm tắt..............................................14

Giao trinh visual studio[bookbooming.com]

Embed Size (px)

Citation preview

Page 1: Giao trinh visual studio[bookbooming.com]

MUC LUC

Phân 1 Cơ ban vê ngôn ngư lâp trinh C#.......................................................................4

Bai thưc hanh 1.1. Chương trinh đâu tiên...................................................................4Tóm tắt.....................................................................................................................4Kỹ thuât được trinh bày...........................................................................................4Trinh tự thực hiện.....................................................................................................4

Bai thưc hanh 1.2. Module hoa chương trinh..............................................................6Tóm tắt.....................................................................................................................6Kỹ thuât được trinh bày...........................................................................................6Trinh tự thực hiện.....................................................................................................6

Bai thưc hanh 1.3. Tạo thư viện sử dụng chung..........................................................8Tóm tắt.....................................................................................................................8Kỹ thuât được trinh bày...........................................................................................8Trinh tự thực hiện.....................................................................................................8Mở rộng....................................................................................................................9

Bai thưc hanh 1.4. Tam giac Pascal..........................................................................10Tóm tắt...................................................................................................................10Kỹ thuât được trinh bày.........................................................................................10Trinh tự thực hiện...................................................................................................10Mở rộng..................................................................................................................11

Bai thưc hanh 1.5. Tam giac Pascal – array version................................................12Tóm tắt...................................................................................................................12Kỹ thuât được trinh bày.........................................................................................12Trinh tự thực hiện...................................................................................................12Mở rộng..................................................................................................................12

Bai thưc hanh 1.6. MyTYPE......................................................................................13Tóm tắt...................................................................................................................13Kỹ thuât được trinh bày.........................................................................................13Trinh tự thực hiện...................................................................................................13Mở rộng..................................................................................................................13

Bai thưc hanh 1.7. Quan ly sinh viên.........................................................................14Tóm tắt...................................................................................................................14Kỹ thuât được trinh bày.........................................................................................14Trinh tự thực hiện...................................................................................................14Yêu câu thêm.........................................................................................................18

Phân 2 Lâp trinh ưng dung vơi winforms.................................................................19

Bai thưc hanh 2.1 helloWinForms.............................................................................19

Page 2: Giao trinh visual studio[bookbooming.com]

Tóm tắt...................................................................................................................19Kỹ thuât được trinh bày.........................................................................................19Trinh tự thực hiện...................................................................................................19Mở rộng..................................................................................................................30

Bai thưc hanh 2.2 usingControls...............................................................................31Tóm tắt...................................................................................................................31Kỹ thuât được trinh bày.........................................................................................31Trinh tự thực hiện...................................................................................................31

Bai thưc hanh 2.3 textFormat....................................................................................35Tóm tắt...................................................................................................................35Kỹ thuât được trinh bày.........................................................................................35Trinh tự thực hiện...................................................................................................35Mở rộng..................................................................................................................42

Bai thưc hanh 2.4 myCalculator................................................................................43Tóm tắt...................................................................................................................43Kỹ thuât được trinh bày:.......................................................................................43Trinh tự thực hiện...................................................................................................43Mở rộng..................................................................................................................47

Bai thưc hanh 2.5 myNotePAD..................................................................................48Tóm tắt...................................................................................................................48Kỹ thuât được trinh bày.........................................................................................48Trinh tự thực hiện...................................................................................................48Mở rộng..................................................................................................................52

Bai thưc hanh 2.6 Quan ly sinh viên - WinForms version.........................................53Tóm tắt...................................................................................................................53Kỹ thuât được trinh bày.........................................................................................54Trinh tự thực hiện...................................................................................................54Mở rộng..................................................................................................................59

Bai thưc hanh 2.7 myFileViewer...............................................................................60Tóm tắt...................................................................................................................60Kỹ thuât được trinh bày.........................................................................................60Trinh tự thực hiện...................................................................................................60Mở rộng..................................................................................................................70

Phân 3 Xư ly dư liêu vơi ADO.NET..........................................................................71

Kiến thức cơ ban về ADO.NET 2.0............................................................................713.1 Kiến trúc tổng quan của ADO.NET.................................................................713.2 Tổng quan vê các mô hinh xử lý dư liệu trong ADO.NET: Mô hinh Kết nối (Connected Model) và Mô hinh Ngắt Kết nối (Disconnected Model)...................73

Bai tập thưc hanh Chuyên đề Visual Studio .NET 2

Page 3: Giao trinh visual studio[bookbooming.com]

3.3 Làm việc với mô hinh Kết nối trong ADO.NET.............................................763.4 Làm việc với mô hinh Ngắt kết nối: DataSet và DataTable............................873.5 Lựa chọn giưa mô hinh Kết nối và mô hinh Ngắt kết nối..............................1083.5 Tạo đối tượng DataSet...................................................................................1103.6 Kết hợp giưa nhiêu bang...............................................................................1133.7 Thay đổi các ban ghi của cơ sở dư liệu..........................................................1183.8 Truy câp và hiển thị dư liệu...........................................................................1193.10 Câp nhât một dòng dư liệu...........................................................................1193.11 Xóa một dòng dư liệu...................................................................................1213.11 Tạo một dòng dư liệu mới............................................................................122

Phân 4 Xây dưng ưng dung Web vơi WebForms...................................................134

Phân 5 Phu luc...........................................................................................................158

Phụ lục A Chuỗi kết nối cho cac loại nguồn dữ liệu...............................................158

Phụ lục B Bang tương quan/chuyển đổi kiểu dữ liệu ở .NET Framework với cac Data Provider..........................................................................................................158

Phân 6 Tài liệu tham khao...........................................................................................160

Bai tập thưc hanh Chuyên đề Visual Studio .NET 3

Page 4: Giao trinh visual studio[bookbooming.com]

PPHÂHÂ NN 1 1 CCƠƠ BABA NN VÊVÊ NGÔNNGÔN NGƯNGƯ LÂLÂ PP TRITRI NHNH C# C#

Bai thưc hanh 1.1. Chương trinh đâu tiên

Tóm tắtBài thực hành này giúp bạn làm quen với môi trương Visual Studio 2005 và các thao tác nhâp xuât cơ ban thông qua giao diện bàn phim. Cu thể, chương trinh yêu câu ngươi sử dung nhâp hai số, sau đó in ra màn hinh tổng, tich và thương của hai số này.

Kỹ thuât được trinh bay

- Làm quen với môi trương Visual Studio 2005. Câu trúc một solution, project và các tài nguyên có liên quan

- Cách thưc sử dung thư viện MSDN để tra cưu, hướng dân- Sử dung thao tác nhâp xuât cơ ban

Trinh tư thưc hiên

1. Khởi động Microsoft Visual Studio 2005. Nhân Ctrl + Shift + N hoăc chọn menu tương ưng là File New Project để tạo mới một project

2. Chọn loại ưng dung cân phát triển là Visual C# Console Application. Chọn thư muc chưa project và đăt tên cho project. Vê măt thực chât, Visual Studio coi project thuộc vê một solution nào đó, và một solution có thể chưa nhiêu

Bai tập thưc hanh Chuyên đề Visual Studio .NET 4

Page 5: Giao trinh visual studio[bookbooming.com]

project. Tuy nhiên, trong nhiêu “bài toán” đơn gian (như vi du của chúng ta chẳng hạn), một solution chỉ có 1 project.

3. Đăt tên cho project của chúng ta thành firstApp. Sau khi nhân nút OK, hãy khao sát xem câu trúc của thư muc chưa solution của chúng ta. Bạn phai luôn nắm chắc vê ý nghĩa của các tâp tin, thư muc được tạo ra trong quá trinh làm việc.

4. Gõ mã lệnh như minh họa vào trong phân mã nguồn của tâp tin Program.cs

5. Sử dung MSDN để tra cưu các thông tin bạn chưa biết vê:a. Console và các phương thưc ReadLine(), WriteLine() của nób. Cách chuyển đổi kiểu chuỗi thành số, vi du như int.Parse()

6. Nhân Ctrl + F5 để thực hiện chạy chương trinh. Sau đó quan sát câu trúc thư muc của solution, cho biết sự thay đổi của nó so với khi mới được tạo ra ở bước 3.

7. Thử thay đổi kết câu lệnh

float thuong = (float)x / y; thành float thuong = x / y;

rồi chạy chương trinh, quan sát kết qua và rút ra kết luân.

8. Sử dung thêm các câu trúc lệnh khác để tinh chỉnh hoạt động của chương trinh (xử lý phép chia cho 0, …)

Bai tập thưc hanh Chuyên đề Visual Studio .NET 5

Page 6: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 1.2. Module hóa chương trinh

Tóm tắt Viết chương trinh nhâp vào một số nguyên N tư bàn phim. Sau đó

a. In ra màn hinh giá trị N!.b. Nhâp thêm một số nguyên K tư bàn phim. Sau đó in ra CK

N = N!/(K!*(N-K)!)

Kỹ thuât được trinh bay

- Câu trúc, cách quan lý logic và vât lý, cách làm việc của solution và project- Thực hiện chia nho ưng dung thành để chuyên môn hóa các phân- Cơ ban vê các kiểu phương thưc trong một lớp

Trinh tư thưc hiên

1. Mở solution đã làm ở Bài thực hành 1.1. Chỉnh sửa tên của solution tư “firstApp” thành “day1” cho có ý nghĩa. Xem câu trúc thư muc của solution sau khi thay đổi.

2. Thêm một project vào solution này bằng menu lệnh File Add New project… . Tương tự như cách tạo mới project ở bài thực hành trước, chọn thể loại project là Console Application. Đăt tên cho project mới là “modular”.

3. Quan sát câu trúc cây thư muc của solution trong cửa sổ Solution Explorer và ca trong Windows Explorer. Để ý rằng, trong cửa sổ Solution Explorer, project firstApp được tô đâm. Điêu này có nghĩa, firstApp đóng vai trò là “Startup

Bai tập thưc hanh Chuyên đề Visual Studio .NET 6

Page 7: Giao trinh visual studio[bookbooming.com]

project”. Khi nhân Ctrl + F5 thi project này sẽ được gọi thực thi chư không phai là project modular mà ta mới tạo ra.

Trong cửa sổ Solution Explorer, nhắp phai chuột lên “modular”. Trong menu hiện ra, chọn menu lệnh “Set as Startup project” để thiết lâp lại startup project cho solution.

4. Việc nhâp n, tinh n! rồi in kết qua bạn hoàn toàn có thể thực hiện được bằng các câu lệnh đơn gian. Tuy nhiên, để tăng tinh rõ ràng và tái sử dung, bạn nên tạo ra một phương thưc để hỗ trợ việc tinh toán n!. Xem mã lệnh bên dưới

5. Chạy thử chương trinh để xem kết qua. Hãy để ý rằng, khai báo phương thưc giaiThua là static long giaiThua(int n). Thử xóa static trong khai báo này rồi chạy lại chương trinh. Lỗi nhân được cho biết chỉ cac phương thức static mới được triệu gọi, sử

dụng lẫn nhau6. Bằng cách tạo ra phương thưc long giaiThua() như trên, chúng ta có thể giai

quyết được vân đê tinh Ckn một cách dễ dàng. Lơi gọi để tinh Ck

n như sau: GiaiThua(n)/(GiaiThua(n-k)*GiaiThua(k))

7. Hãy tạo ra một phương thưc để tinh tổ hợp châp k của n phân tử (bạn tự quyết định các tham số và kiểu dư liệu tra vê).

Bai tập thưc hanh Chuyên đề Visual Studio .NET 7

Page 8: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 1.3. Tạo thư viên sư dung chung

Tóm tắtTrong thực tế, một ứng dụng có thể là có kha năng thực thi (executable) hoăc chỉ đơn thuân là thư viện để chưa các chưc năng, lớp đối tượng.

Bài thực hành này hướng dân bạn tạo thư viện chưa các phương thưc thương dùng. Với muc đich minh họa, thư viện này chỉ chưa 2 hàm tiện ich giúp tinh giai thưa và tổ hợp châp. Sau khi biên dịch, bạn sẽ có được một file nhị với phân mở rộng là DLL. Thư viện này, khi cân, sẽ được tham chiếu đến trong các ưng dung khác.

Kỹ thuât được trinh bay

- Tạo loại ưng dung loại thư viện

Trinh tư thưc hiên

1. Tạo mới một project, đăt tên là commonUtils (common utilities - các tiện ich dùng chung). Chú ý chọn loại ưng dung cân tạo là Class Library

2. Măc định Visual Studio 2005 sẽ tạo ra trong namespace CommonUtils một lớp tên là Class1. Đổi tên lớp này lại thành Math. Sau đó cài đăt các phương thưc như sau:

3. Rõ ràng, đây không phai là một chương trinh để chạy như các ưng dung bạn đã viết trước đó - class Math không có phương thưc static public Main() – tưc là bạn không thể nhân Ctrl + F5 để chạy chương trinh. Biên dịch project này bằng menu lệnh Build Build commonUtils. Kết qua, bạn sẽ có một thư viện commonUtils.dll trong thư muc bin\Release hoăc bin\Debug của project tùy

Bai tập thưc hanh Chuyên đề Visual Studio .NET 8

Page 9: Giao trinh visual studio[bookbooming.com]

theo cách chọn chế độ biên dịch. Thư viện này sẽ được dùng để tham chiếu đến trong các ưng dung cân nó.

Mở rộngBổ sung các phương thưc thương dùng khác vào thư viện, chẳng hạn như phương thưc xác định xem một số có phai là nguyên tố hay không, phương thưc hoán đổi giá trị của hai số cho trước, …

Bai tập thưc hanh Chuyên đề Visual Studio .NET 9

Page 10: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 1.4. Tam giac Pascal

Tóm tắtViết chương trinh nhâp một số nguyên N tư bàn phim, sau đó in ra màn hinh N dòng đâu tiên của tam giác Pascal.

Kỹ thuât được trinh bay

- Sử dung thư viện có sẵn

Trinh tư thưc hiên

1. Tạo mới một ưng dung kiểu Console Application. Đăt tên project là pascalTriangle1

2. Thực hiện bổ sung tham khao đến thư viện commonUtils bằng cách:- Nhắp phai chuột vào project pascalTriangle1 trong cửa sổ Solution

Explorer- Trong menu hiện ra, chọn Add Reference…

Trong tab Browse của hộp thoại Add Reference, tim đến thư viện commonUtils.dll đã tạo ra trước đó. Dễ thây rằng thư viện được tham khao đến không chỉ có dạng DLL mà có thể có các dạng khác, bao gồm EXE, OCX, …

3. Hoàn thiện phân mã nguồn có sử dung tham chiếu đến thư viện vưa bổ sung như hinh dưới:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 10

Page 11: Giao trinh visual studio[bookbooming.com]

Mở rộngHãy tự rút ra nhưng ghi chú cân thiết vê việc:

- Khai báo phương thưc C(int n, int k) trong commonUtils là

public static long C(int n, int k)

static, public ở đây có ý nghĩa gi, có thể thay thế hoăc bo đi?

- Tương tự cho phương thưc giaiThua(int n);- Tại sao trong quá trinh sử dung phương thưc C() lại phai ghi đây đủ là

commonUtils.Math.C()? Chỉ cân ghi Math.C() có được không?

Bai tập thưc hanh Chuyên đề Visual Studio .NET 11

Page 12: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 1.5. Tam giac Pascal – array version

Tóm tắtSử dung array để xây dựng tam giác Pascal như Bài thực hành 1.4.

Kỹ thuât được trinh bay

- Sử dung array

Trinh tư thưc hiên

1. Tạo mới một project kiểu Console Application với tên là pascalTriangle22. Sử dung các tinh chât C0

0 = Ckk = 1, Cn

k = Cn-1k-1 + Cn-1

k , ta sẽ xây dựng một jagged array tư nho đến lớn. Chi tiết như phân mã nguồn phia dưới:

Mở rộngCó thể dùng array nhiêu chiêu trong trương hợp này không? Nếu có thi có sự khác nhau nào so với dùng jagged array?

Bai tập thưc hanh Chuyên đề Visual Studio .NET 12

Page 13: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 1.6. MyTYPE

Tóm tắtViết chương trinh in nội dung văn ban ra màn hinh (như lệnh TYPE ở Ms DOS). Tên file được truyên theo tham số dòng lệnh.

Kỹ thuât được trinh bay

- Sử dung tham số dòng lệnh được truyên vào- Sử dung namespace System.IO để đọc nội dung tâp tin

Trinh tư thưc hiên

1. Tạo mới một projecet kiểu Console Application với tên myTYPE2. Khai báo sử dung thêm namespace System.IO rồi hoàn thiện phân mã nguồn

như minh họa dưới

Mở rộng

- Cách kiểm tra sự tồn tại của tâp tin trước khi đọc và hiển thị nó như trên đã an toàn chưa? Có trương hợp nào mà sự tồn tại của tâp tin lại chưa đam bao cho việc đọc và hiển thị nó? Giai quyết bằng cách nào?

- Thêm phân kiểm tra số lượng tham số truyên vào dòng lệnh để chương trinh có thể hoạt động chinh xác hơn (sử dung args.Length)

- Sử dung MSDN để tim hiểu thêm các lớp khác trong namespace System.IO

Bai tập thưc hanh Chuyên đề Visual Studio .NET 13

Page 14: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 1.7. Quan ly sinh viên

Tóm tắtViết chương trinh quan lý sinh viên của một trương. Sinh viên có thể học các chuyên ngành Công nghệ Thông tin, Vât lý, Ngư văn. Mỗi chuyên ngành tương ưng có các môn học khác nhau.

Sinh viên khoa Công nghệ Thông tin phai học 3 môn Pascal, C# và SQL. Sinh viên khoa Vât lý phai học 4 môn: Cơ học, Điện học, Quang học, Vât lý hạt

nhân. Sinh viên khoa Văn phai học 2 môn Văn học cổ điển và Văn học Hiện đại

Chương trinh cho phép nhâp danh sách sinh viên, sau đó in danh sách sinh viên cùng với điểm trung binh của họ ra màn hinh.

In ra danh sách nhưng sinh viên có điểm trung binh cao trên 5.0 ra màn hinh. Thông tin hiển thị có dạng Họ tên, Chuyên ngành đào tạo, Điểm trung binh.

Kỹ thuât được trinh bay

- Truy xuât tâp tin có định dạng cho trước- Sử dung một phương thưc của lớp String- Các kỹ thuât hướng đối tượng được sử dung trong bài toán thực tế

Trinh tư thưc hiên

1. Trước khi tiến hành cài đăt, ta khao sát qua sơ đồ lớp được sử dung. Với nhưng mô ta khá rõ ràng trong yêu câu bài toán, ta có được cái nhin tổng quan vê các lớp như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 14

Page 15: Giao trinh visual studio[bookbooming.com]

Lưu ý rằng, phương thưc dtb() được cài đăt là virtual để chúng ta có thể override một cách cu thể, chi tiết hơn trong các lớp kế thưa tư class SinhVien. Phương thưc ToString() được cài đăt override tư lớp object để sử dung trong việc in “nội dung” của đối tượng.

2. Tạo mới một project kiểu Console Application với tên là studentManager3. Tại cây phân câp Solution Explorer nhắp phai chuột và chọn Add New

Item… Trong hộp thoại hiện ra, chọn tạo mới class SinhVien.cs

Bai tập thưc hanh Chuyên đề Visual Studio .NET 15

Page 16: Giao trinh visual studio[bookbooming.com]

4. Cài đăt các thành phân cơ ban cho lớp SinhVien

5. Bổ sung thêm các class SinhVienCNTT, SinhVienVan, SinhVienVL theo phân tich thiết kế lớp tư trước. Dưới đây là phân mô ta cài đăt cho lớp SinhVienVan. Hai lớp còn lại SinhVienCNTT, SinhVienVL được cài đăt một cách tương tự.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 16

Page 17: Giao trinh visual studio[bookbooming.com]

6. Trong phân chương trinh (tâp tin Program.cs) chúng ta thực hiện yêu câu bài toán như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 17

Page 18: Giao trinh visual studio[bookbooming.com]

Yêu câu thêm

- In ra 3 sinh viên có điểm trung binh cao nhât trương.- Chỉnh sửa để ngươi sử dung có thể nhâp danh sách mà không biết trước số

lượng sinh viên (sử dung vòng lăp while, do, …)- Chỉnh sửa để có thể nhâp dư liệu các sinh viên tư file.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 18

Page 19: Giao trinh visual studio[bookbooming.com]

PPHÂHÂ NN 2 2LLÂÂ PP TRITRI NHNH ƯƯ NGNG DUDU NGNG VƠVƠ II WINFORMSWINFORMS

Phân này kéo dài trong 2 buổi. Các bài thực hành này sẽ được giới thiệu như là nội dung cơ ban nhât mà sinh viên cân nắm. Các kỹ thuât khác sinh viên tự tham khao và trao đổi với lớp.

Bai thưc hanh 2.1 helloWinForms

Tóm tắtChương trinh

Kỹ thuât được trinh bay

- Câu trúc của và cơ chế hoạt động của một project Windows Form Application.- Cơ chế xử lý sự kiện của các Control trong một Windows Form- Một số phương thưc, thuộc tinh, sự kiện quan trọng của các điêu khiển trong

một Windows Form.

Trinh tư thưc hiên

1. Tạo mới một ưng dung kiểu Windows Form Application với tên là 01-helloWindowsForm như hinh vẽ

Bai tập thưc hanh Chuyên đề Visual Studio .NET 19

Page 20: Giao trinh visual studio[bookbooming.com]

2. Theo măc định, một solution với một project được tạo ra. Project này có một lớp Form1. Khao sát nội dung của project trong Windows Explorer, chúng ta sẽ thây câu trúc của thư muc và các tâp tin tương tự như hinh dưới:

Có thể thây, mỗi Form được tạo ra tương ưng với 3 tâp tin có tiếp đàu ngư là giống nhau, lây vi du là Form1

Form1.Designer.cs: chưa các mã lệnh do Form Designer tự sinh ra tương ưng với các thao tác do ngươi sử dung kéo tha cac Control từ ToolBox vao bề mặt Form hay thưc hiện cac thiết lập đối với cac Control.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 20

Page 21: Giao trinh visual studio[bookbooming.com]

Form1.cs: chưa phân mã lệnh và khai báo thêm do ngươi sử dung cài đăt.

Form1.resx: chưa các mô ta, khai báo vê các tài nguyên được sử dung trong Form.

3. Chúng ta cũng có thể quan sát câu trúc của solution hay project bằng cách khao sát cửa sổ Solution Explorer:

4. Tư cửa sổ Solution Explorer, đổi tên tâp tin Form1.cs thành FormMain.cs. Để ý rằng, ca ba tâp tin liên quan đến Form1 đêu được thay đổi theo một cách đồng bộ.

5. Thiết kế giao diện cho FormMain như hinh vẽ

Bai tập thưc hanh Chuyên đề Visual Studio .NET 21

Page 22: Giao trinh visual studio[bookbooming.com]

6. Bước tiếp theo, chúng ta sẽ thực hiện cài đăt phương thưc xử lý sự kiện Click của nút bâm btnCurrentTime:

a. Chọn điêu khiển nút bâm btnCurrentTime trong cửa số thiết kế Form.b. Ở trang Event trong cửa sổ Properties Windows, nhắp đúp chuột vào sự

kiện Click (xem hinh vẽ dưới). Form Designer sẽ sinh ra phương thưc xử lý sự kiện có tên măc định là btnCurrentTime_Click(…). (Phương thưc xử lý sự kiện được măc định đăt tên là <tênĐiêuKhiển>_<TênSựKiện>)

Soạn thao phân mã lệnh cho phương thưc này như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 22

Page 23: Giao trinh visual studio[bookbooming.com]

7. Thực hiện chạy chương trinh, khi nhân vào nút bâm btnCurrentTime, một hộp thông báo được hiển thị ra như hinh vẽ

8. Thực ra chúng ta có thể tự đăt tên cho phương thưc xử lý sự kiện. Chẳng hạn, để cài đăt phương thưc xử lý sự kiện MouseEnter cho nút bâm btnCurrentTime, trong cửa sổ Properties ở trang Events, tim đến muc MouseEnter và:

a. Nhâp vào tên phương thưc xử lý sự kiện: btn_MouseEnterb. Nhân Enterc. FormDesigner sẽ tạo ra phương thưc với tên tương ưng

Bai tập thưc hanh Chuyên đề Visual Studio .NET 23

Page 24: Giao trinh visual studio[bookbooming.com]

d. Tiến hành cài đăt mã lệnh cho phương thưc xử lý sự kiện trên như sau:

private void btn_MouseEnter(object sender, EventArgs e) { btnCurrentTime.ForeColor = Color.Red; }

9. Tương tự, chúng ta cài đăt tiếp phương thưc xử lý sự kiện MouseLeave cho nút bâm btnCurrentTime như sau

private void btn_MouseLeave(object sender, EventArgs e) { btnCurrentTime.ForeColor = SystemColors.ControlText; }

10. Chạy chương trinh và quan sát kết qua: Điêu khiển nút bâm btnCurrentTime sẽ có hiệu ưng mouse hover khá ân tượng: khi rê con tro chuột vào nút bâm btnCurrentTime, màu chư của nó sẽ đổi sang màu đo; màu chư của nút bâm trở thành binh thương (màu ControlText) khi con tro chuột rê ra khoi nút bâm.

11. Để tim hiểu kỹ hơn ban chât của việc gắn kết phương thưc xử lý sự kiện, chúng ta nhắp đúp chuột vào FormMain.Designer.cs trong cửa sổ Solution Explorer để xem phân nội dung được sinh ra bởi Form Designer:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 24

Page 25: Giao trinh visual studio[bookbooming.com]

Chú ý nhưng phân được tô sáng trong hinh vẽ nói trên; tư đó suy ra được ban chât của việc gắn kết phương thưc xử lý sự kiện trong khi thiết kế.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 25

Page 26: Giao trinh visual studio[bookbooming.com]

12. Đóng file nội dung FormMain.Designer.cs lại. Các bước tiếp theo sẽ minh họa cách thưc dùng chung một phương thưc xử lý sự kiện cho nhiêu đối tượng khác nhau.

13. Trong cửa sổ thiết kế của FormMain, thực hiệna. Chọn ca hai đối tượng btnClose và btnAboutb. Trong trang Events của cửa sổ Properties, gõ tên phương thưc xử lý sự

kiện Click cho ca hai điêu khiển nút bâm này là btnTask_Click rồi nhân Enter (xem hinh vẽ)

14. Thực hiện cài đăt mã lệnh cho phương thưc này như sau:

private void btnTask_Click(object sender, EventArgs e) { if (sender == btnClose) this.Close(); else if (sender == btnAbout)1

MessageBox.Show("Day la chuong trinh minh hoa", "Thong bao"); }

Trong phương thưc trên, chúng ta sử dung đối số sender để nhân biết điêu khiển nào phát sinh sự kiện. Chúng ta cũng có thể thực hiện như thế này:

private void btnTask_Click(object sender, EventArgs e)

1 Thực ra không nhât thiết phai có nhánh else if, chỉ cân else là đủ, bởi vi ở đây chúng ta chỉ áp dung phương thưc này cho hai điêu khiển btnClose và btnAbout!.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 26

Page 27: Giao trinh visual studio[bookbooming.com]

{ string stTask = (sender as Button).Text; 2

if (stTask == "Close") this.Close(); else if (stTask == "About") MessageBox.Show("Day la chuong trinh minh hoa", "Thong bao"); }

15. Bây giơ, chúng ta tinh chỉnh thêm để chương trinh hỗ trợ hiệu ưng mouse hover cho tất ca cac điều khiển trong form:

a. Sửa lại phân mã nguồn cho 2 phương thưc xử lý sự kiện btn_MouseEnter và btn_MouseLeave như sau:

private void btn_MouseEnter(object sender, EventArgs e) { (sender as Control).ForeColor = Color.Red; }

private void btn_MouseLeave(object sender, EventArgs e) { (sender as Control).ForeColor = SystemColors.ControlText; }

b. Trong phân FormDesigner, chọn tât ca các đối tượng trên bê măt Form.c. Trong cửa sổ Properties, chọn phương thưc xử lý sự kiện MouseLeave

cho tất ca cac đối tượng đang chọn là btn_MouseLeave (xem hinh vẽ)

2 Phép chuyển kiểu (sender as Button) trong câu lệnh này là thành công vi ca btnClose và btnAbout đêu là các điêu khiển kiểu Button

Bai tập thưc hanh Chuyên đề Visual Studio .NET 27

Page 28: Giao trinh visual studio[bookbooming.com]

d. Làm tương tự để gán phương thưc xử lý sự kiện MouseEnter cho tât ca các điêu khiển nói trên là btn_Enter.

e. Chạy chương trinh để xem hiệu ưng: khi rê con tro chuột qua các điêu khiển, font chư của chúng sẽ được đổi thành màu đo.

16. Trong bước 11, chúng ta đã biết được cách thưc đưa một thành phân điêu khiển vào giao diện của một Windows Form thông qua mã lệnh (bằng cách tim hiểu phân mã sinh ra bởi Form Designer). Bây giơ, chúng ta sẽ áp dung để thực hiện thêm các điêu khiển vào Form và gán phương thưc xử lý sự kiện cho chúng trong thơi gian thực thi chương trinh

a. Bổ sung vào Form một nút bâm btnCreateButton

b. Cài đăt phương thưc xử lý sự kiện Click cho nút bâm này như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 28

Page 29: Giao trinh visual studio[bookbooming.com]

c. Chạy chương trinh và quan sát kết qua.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 29

Page 30: Giao trinh visual studio[bookbooming.com]

Mở rộng

- Hãy tim hiểu ý nghĩa của việc cài đăt mã lệnh ở bước 15.a: (sender as Control). Có thể sử dung phép ép kiểu nào khác không? Tại sao?

- Điêu chỉnh trong giao diện chương trinh, trong đó có một số điêu khiển (Label, TextBox, RadioButton, CheckBox hoăc Button) sử dung màu khác với màu măc định (là SystemColors.ControlText). Khi đó, hiệu ưng mouse hover hoạt động không đúng nưa. Hãy chỉnh sửa chương trinh để khắc phuc phát sinh này.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 30

Page 31: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 2.2 usingControls

Tóm tắtXây dựng chương trinh điên thông tin cá nhân như minh họa

Kỹ thuât được trinh bay

- Giới thiệu một ưng dung WinForms cơ ban- Cách thưc lưu file với nội dung tiếng Việt- Các thành phân điêu khiển cơ ban: Button, Label, TextBox, PictureBox, Timer,

…- Nạp một anh tư file

Trinh tư thưc hiên

1. Tạo mới một project loại Windows Application, đăt tên là usingControls2. Theo măc định, một lớp Form1 được sinh ra. Chỉnh sửa các thuộc tinh của Form1 với

các giá trị như bang dưới:

Thuộc tính Gia trị Ghi chú

Name FormMain

Text Hello WinForms Tiêu để của cửa sổ

FormBorderStyle FixedSingle Kich thước của cửa sỗ sẽ không được thay đổi khi chạy chương trinh

MaximizeBox False Vô hiệu hóa nút Maximize của cửa sổ

Bai tập thưc hanh Chuyên đề Visual Studio .NET 31

Page 32: Giao trinh visual studio[bookbooming.com]

Chú ý rằng, nhưng thuộc tinh có thay đổi giá trị so với măc định sẽ được hiển thị trong cửa sổ Properties dưới dạng chư in đâm

3. Thiết kế giao diện của form như minh họa. Lưu ý, với mỗi điêu khiển bạn đưa vào form, nếu dự định truy xuât nó trong phân mã nguồn khi lâp trinh thi hãy đăt tên nó thay vi để như tên măc định.

Chỉnh sửa thuộc tinh của một số đối tượng như sau:

Điều khiển Thuộc tính Gia trị

dtpDOB Format Custom

CustomFormat dd/MM/yyyy

txtOther Enable False

lblInfo Font Chọn font thich hợp, in đâm

picImage SizeMode StretchImage

lblName BackColor Transparent (Web)

tmrScroll Interval 120

4. Nhân Ctrl + S để lưu nội dung project. Do chúng ta có sử dung ký tự tiếng Việt trong Form nên Visual Studio có hiển thị hộp thoại để yêu câu chỉ định bang mã lưu ký tự:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 32

Page 33: Giao trinh visual studio[bookbooming.com]

Nhân nút “Save With Other Encoding” để chọn bang mã thich hợp – sau đó bạn có thể chọn cách lưu theo UTF8 như hinh dưới (cũng có thể chọn tùy chọn Unicode – Codepage 1200):

5. Cài đăt phân mã lệnh cho sự kiện Click của nút bâm btnSelectImage như sau:

Khi ngươi sử dung nhân vào nút này, một hộp thoại sẽ hiện ra cho phép chọn anh. Chỉ các tâp tin có phân mở rộng là BMP, JPG, GIF mới được hiển thị để lựa chọn. Điêu này được thiết lâp thông qua thuộc tinh Filter của đối tượng dlgOpen (thuộc lớp OpenFileDialog).

6. Khi ngươi sử dung gõ tên của họ vào txtName thi nội dung của lblName cũng thay đổi theo. Muốn vây, ta cài đăt mã lệnh cho sự kiện TextChanged của txtName như (1) – xem minh họa code ở dưới

Bai tập thưc hanh Chuyên đề Visual Studio .NET 33

Page 34: Giao trinh visual studio[bookbooming.com]

7. Đối tượng txtOther chỉ được sử dung (Enabled) khi mà chkOther được check vào, do đó ta cũng cài đăt mã lệnh cho sự kiện CheckChanged của chkOther như (2)

8. Khi nhân nút “Câp nhât” thi nội dung của lblInfo được câp nhât theo như phân mã lệnh cài đăt cho sự kiện Click của btnUpdate (3)

9. Ngươi sử dung có thể bât tắt chế độ cuộn nội dung dòng chư lblInfo bằng cách nhân chuột vào nó. Cài đăt mã lệnh cho sự kiện Click của lblInfo như (5)

10. Để cuộn nội dung dòng chư, cài đăt mã lệnh cho sự kiện Tick của tmrScroll như (4)

Bai tập thưc hanh Chuyên đề Visual Studio .NET 34

Page 35: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 2.3 textFormat

Tóm tắtXây dựng chương trinh thể hiện định dạng cho đoạn văn ban tĩnh (Label)

Kỹ thuât được trinh bay

- Cách sử dung Font, FontStyle trong ưng dung Windows Form- Truy xuât các thành phân dư liệu giưa các Form- Sử dung cửa sổ dạng Dialog trong chương trinh

Trinh tư thưc hiên

1. Tạo mới một ưng dung loại Windows Applications, đăt tên là textFormat2. Theo măc định, một lớp Form1 được sinh ra. Chỉnh sửa các thuộc tinh của

Form1 với các thuộc tinh giá trị như hinh dưới:

Thuộc tính Gia trị Ghi chú

Name FormMain

Text Text formartting Tiêu để của cửa sổ

FormBorderStyle FixedSingle Kich thước của cửa sỗ sẽ không được thay đổi khi chạy chương trinh

MaximizeBox False Vô hiệu hóa nút Maximize của cửa sổ

Chú ý rằng, nhưng thuộc tinh có thay đổi giá trị so với măc định sẽ được hiển thị trong cửa sổ Properties dưới dạng chư in đâm

3. Thiết kế giao diện cho FormMain như hinh dưới đây

STT Thuộc tính Gia trị Ghi chú

1 Name lblAdvert Label

2 Name pnlAdvert Panel

3 NameText

btnChangeTextChangeText…

Button

4 Name btnClose Button

Bai tập thưc hanh Chuyên đề Visual Studio .NET 35

Page 36: Giao trinh visual studio[bookbooming.com]

Text Close

4. Bổ sung vào Project thêm một WindowForm bằng cách chọn menu lệnh Project Add Windows Forms…

Chọn tên file của Windows Form cân tạo là FormSettings.cs như hinh rên.

5. Thiết kế giao diện cho FormSettings vưa được tạo ra như hinh dưới.

Trinh tự đăt các điêu khiển vào form có thể thực hiện như sau:- Điêu khiển TextBox đăt tên là txtAdvert.- Điêu khiển Frame với thuộc tinh Text là “Format”

Bai tập thưc hanh Chuyên đề Visual Studio .NET 36

Page 37: Giao trinh visual studio[bookbooming.com]

- 4 CheckBox có tên là chkB, chkI, chkU, chkS với thuộc tinh Text được thiết lâp tương ưng là “Bold”, “Italic”, “Underline” và “Strike out”

- 4 RadioButton có tên là rbRed, rbGreen, rbBlue, rbYellow với thuộc tinh Text được thiết lâp tương ưng với 4 tên màu “Red”, “Green”, “Blue” và “Yellow”

- 3 nút bâm btnOK, btnApply, btnCancel. Sau đó thiết lâp thuộc tinh DialogResult của các nút bâm btnOK, btnCancel lân lượt là OK và Cancel

6. Tiến hành cài đăt mã lệnh cho nút bâm btnChangeText ở FormMain như sau:

private void btnChangeText_Click(object sender, EventArgs e) { FormSettings frm = new FormSettings(); if (frm.ShowDialog() == DialogResult.OK) {

lblAdvert.Text = “You’ve clicked at OK button!”; } }

7. Thực hiện chạy chương trinh và quan sát kết qua. Để ý rằng, với việc thiết lâp thuộc tinh DialogResult cho 2 nút bâm btnOK và btnCancel như bước 5 ở trên, chúng ta không cân cài đăt mã lệnh cho 2 nút này mà vân có hiệu ưng frm (một thể hiện của FormSettings) bị đóng khi một trong 2 nút này được nhân. Hơn nưa, chúng ta sẽ biết được ngươi sử dung đã nhân vào nút nào bằng cách kiểm tra kết qua của hàm frm.ShowDialog() như trên.

Trong Bước tiếp theo, chúng ta sẽ làm cho hai form sẽ tương tác dư liệu được với nhau trong thơi gian thực thi.

8. Trong FormMain, tạo ra một thuộc tinh AdvertText kiểu string như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 37

Page 38: Giao trinh visual studio[bookbooming.com]

public string AdvertText { get { return lblAdvert.Text; }

set { lblAdvert.Text = value; } }

9. Trong FormSettings, chúng ta thêm khai báo biến thành phân và sửa lại phương thưc khởi dựng của lớp:

public partial class FormSettings: Form { FormMain formMain;

public FormSettings(FormMain frmMain) { InitializeComponent(); this.formMain = frmMain; }

private void FormSettings_Load(object sender, EventArgs e) {

this.txtAdvert.Text = formMain.AdvertText; } . . . . . . . . . .

}

10. Cài đăt phương thưc xử lý sự kiện Click của nút bâm btnApply như sau

public void btnApply_Click(object sender, EventArgs e) { formMain.AdvertText = this.txtAdvert.Text; }

Để ý rằng, bạn phai chỉnh sửa modifier của phương thưc bntApply_Click thành public thay vi private như FormDesigner sinh ra theo măc định. Điêu này cho phép phương thưc này có thể được triệu gọi tư ngoài lớp FormSettings như ở bước 11 dưới đây.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 38

Page 39: Giao trinh visual studio[bookbooming.com]

11. Chỉnh sửa lại phương thưc xử lý sự kiện Click của nút bâm btnChangeText ở FormMain như sau:

private void btnChangeText_Click(object sender, EventArgs e) { FormSettings frm = new FormSettings(this); if (frm.ShowDialog() == DialogResult.OK) { frm.btnApply_Click(null, null); } }12. Chạy thử chương trinh và quan sát kết qua. Tóm lại, chúng ta đã thực hiện

nhưng bước sau đây để có thể thay đổi dư liệu tư 2 form:a. Tạo property (AdvertText) có modifier kiểu public cho phân dư liệu

muốn truy xuât (lblAdvert.Text)b. Tim cách truyên tham chiếu của form chưa property nói trên

(FormMain) đến form muốn truy xuât (FormSettings)13. Tiếp theo, chúng ta sẽ tạo ra property tên AdvertForeColor có kiểu Color trong

lớp FormMain để thực hiện thay đổi màu sắc của lblAdvert:

public Color AdvertForeColor { get { return lblAdvert.ForeColor; } set { lblAdvert.ForeColor = value; } }

14. Câp nhât lại phương thưc xử lý sự kiện Click của nút bâm btnApply và sự kiện Load trong lớp FormSettings:

private void FormSettings_Load(object sender, EventArgs e) { this.txtAdvert.Text = formMain.AdvertText;

rbRed.Checked = formMain.AdvertForeColor == Color.Red; rbGreen.Checked = formMain.AdvertForeColor == Color.Green; rbBlue.Checked = formMain.AdvertForeColor == Color.Blue; rbYellow.Checked = formMain.AdvertForeColor == Color.Yellow; }

public void btnApply_Click(object sender, EventArgs e) {

Bai tập thưc hanh Chuyên đề Visual Studio .NET 39

Page 40: Giao trinh visual studio[bookbooming.com]

formMain.AdvertText = this.txtAdvert.Text; if (rbRed.Checked) formMain.AdvertForeColor = Color.Red; else if (rbGreen.Checked) formMain.AdvertForeColor = Color.Green; else if (rbBlue.Checked) formMain.AdvertForeColor = Color.Blue; else formMain.AdvertForeColor = Color.Yellow; }15. Như vây, trong các bước trên, chúng ta đã tạo ra một property kiểu Color và

đồng bộ hóa nó với 4 điêu khiển RadioButton. Nhưng bước tiếp theo chúng ta tạo ra thêm một property khác để thay đổi định dạng font chư cho lblAdvert. Trước hết, chúng ta cân biết

a. Các thuộc tinh như Bold, Italic, .. của lblAdvert.Font là chỉ đọc. Thế nên không thể thực hiện phép gán để thay đổi lblAdvert.Font.Bold được

b. Việc thay đổi tinh chât Bold, Italic, … của một đối tượng Font được thực hiện bằng cách tạo mới đối tượng Font (tham khao thêm MSDN để biết 13 hàm nạp chồng để khởi tạo một đối tượng Font)

c. Một trong các hàm nạp chồng khá đơn gian mà chúng ta có thể sử dung để tạo một đối tượng Font có cú pháp là:

Trong đó, family sẽ là tên font, emSize là kich cỡ font, style là kiểu font. Giá trị của style sẽ là sự tổng hợp theo phép toán or của các giá trị FontStyle.Bold, FontStyle.Italic, FontStyle.Underline và FontStyle.Strikeout.

16. Tạo property AdvertFontFormat trong lớp FormMain như sau:

public bool[] AdvertFontFormat { get { Font f = lblAdvert.Font; return (new bool[] {f.Bold, f.Italic, f.Underline, f.Strikeout}); } set { if (value.Length == 4) { FontStyle fs = FontStyle.Regular; if (value[0]) fs = fs | FontStyle.Bold; if (value[1]) fs = fs | FontStyle.Italic;

Bai tập thưc hanh Chuyên đề Visual Studio .NET 40

Page 41: Giao trinh visual studio[bookbooming.com]

if (value[2]) fs = fs | FontStyle.Underline; if (value[3]) fs = fs | FontStyle.Strikeout; lblAdvert.Font = new Font(lblAdvert.Font.Name, lblAdvert.Font.Size, fs); } } }

Property AdvertFontFormat có kiểu dư liệu là một mang bool gồm 4 phân tử mà thư tự của chúng sẽ tương ưng biểu diễn tinh chât Bold, Italic, Underline và Strikeout của một FontStyle.

17. Tiếp đến, chúng ta sẽ câp nhât các phương thưc cân thiết trong lớp FormSettings để sử dung thuộc tinh AdvertFontFormat vưa tạo như sau:

private void FormSettings_Load(object sender, EventArgs e) { this.txtAdvert.Text = formMain.AdvertText;

rbRed.Checked = formMain.AdvertForeColor == Color.Red; rbGreen.Checked = formMain.AdvertForeColor == Color.Green; rbBlue.Checked = formMain.AdvertForeColor == Color.Blue; rbYellow.Checked = formMain.AdvertForeColor == Color.Yellow;

this.chkB.Checked = formMain.AdvertFontFormat[0]; this.chkI.Checked = formMain.AdvertFontFormat[1]; this.chkU.Checked = formMain.AdvertFontFormat[2]; this.chkS.Checked = formMain.AdvertFontFormat[3]; }

public void btnApply_Click(object sender, EventArgs e) { formMain.AdvertText = this.txtAdvert.Text; if (rbRed.Checked) formMain.AdvertForeColor = Color.Red; else if (rbGreen.Checked) formMain.AdvertForeColor = Color.Green; else if (rbBlue.Checked) formMain.AdvertForeColor = Color.Blue; else formMain.AdvertForeColor = Color.Yellow;

formMain.AdvertFontFormat = new bool[] { chkB.Checked, chkI.Checked, chkU.Checked, chkS.Checked }; }

Bai tập thưc hanh Chuyên đề Visual Studio .NET 41

Page 42: Giao trinh visual studio[bookbooming.com]

18. Chạy chương trinh để xem kết qua.

Mở rộng

- Qua quá trinh cài đăt, có thể thây, Form Designer của Visual Studio .NET không hỗ trợ việc tạo mang điêu khiển giống như ở Visual Basic. Tuy nhiên, chúng ta có thể mô phong mang điêu khiển bằng cách tạo ra các Property hoăc là Indexer để ánh xạ đến các điêu khiển.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 42

Page 43: Giao trinh visual studio[bookbooming.com]

-

Bai thưc hanh 2.4 myCalculator

Tóm tắtXây dựng chương trinh mô phong một máy tinh điện tử đơn gian.

Kỹ thuât được trinh bay:- Xây dựng ưng dung GUI với WinForms- Cách thưc cài đăt, gắn kết, xử lý events với một thành phân giao diện- Tạo hiệu ưng transparent với Form

Trinh tư thưc hiên

1. Tạo mới một project loại Windows Application, đăt tên là myCalculator2. Theo măc định, một lớp Form1 được sinh ra. Chỉnh sửa các thuộc tinh của Form1 với

các giá trị như bên dưới:

Thuộc tính Gia trị Ghi chú

Name FormMain

Text my Calculator Tiêu để của cửa sổ

FormBorderStyle FixedSingle Kich thước của cửa sỗ sẽ không được thay đổi khi chạy chương trinh

MaximizeBox False Vô hiệu hóa nút Maximize của cửa sổ

3. Tạo giao diện cho chương trinh như hinh minh họa

Sau khi đã tạo ra được giao diện với các điêu khiển có vị tri, kich thước hợp lý, bạn nên cố định chúng. Thực hiện điêu này bằng cách nhắp phai chuột lên bê măt của FormMain, trong menu hiện ra, chọn Lock Controls. Điêu chỉnh các thuộc tinh của đối tượng “màn hinh hiển thị” như sau:

Đối tượng Thuộc tính Gia trị

Bai tập thưc hanh Chuyên đề Visual Studio .NET 43

Page 44: Giao trinh visual studio[bookbooming.com]

“Man hinh hiển thị” Name txtScreen

Text 0

Font Chọn font thich hợp

ReadOnly True

TextAlign Right

4. Trước khi bắt tay vào viết mã lệnh, bạn phai hinh dung cách thưc làm việc của chương trinh cũng như việc chuẩn bị các kiểu đối tượng, dư liệu.

Giao diện của chương trinh chỉ là các nút bâm và “màn hinh” hiển thị kết qua. Do chỉ là máy tinh đơn gian nên chương trinh chỉ hỗ trợ các phép tinh 2 ngôi cơ ban. Có thể phân biệt nút bâm thuộc các nhóm:

(1) Nút bâm chư số 0, 1, …, 9, ký hiệu dâu châm thâp phân, nút đao dâu, nút xóa trái xác định hai toán hạng tham gia vào phép tinh.

(2) Nút bâm phép tinh +, -, x, / xác định phép tinh(3) Nút Enter để kich hoạt việc thực hiện phép tinh và hiển thị kết qua(4) Nút C khởi tạo một phép toán mới

Trinh tự các bước sử dung của máy tinh thông thương như sau: Ngươi sử dung “nhâp vào” số thư nhât, xác định phép toán, sau đó “nhâp vào” số thư hai, cuối cùng nhân dâu =

Khái niệm “nhâp vào” ở đây có nghĩa là ngươi sử dung dùng liên tiếp các nút bâm thuộc nhóm (1). Chú ý rằng dâu châm thâp phân chỉ xuât hiện 1 lân trong 1 số hạng. Việc xác định phép toán có thể xác định nhiêu lân giữa hai lân nhập hai số hạng. Tóm lại, khi ngươi sử dung nhân một nút bâm trong nhóm (1), ta luôn biết được anh ta đang “nhâp số liệu” cho số hạng nào: nếu chưa xác định phép toán thi có nghĩa anh ta đang nhâp cho số thư nhât, ngược lại thi đang nhâp cho số thư hai.

Điêu khác nưa cân phai tinh đến, đó là lưu trư dư liệu như thế nào? Trong bài toán này, việc sử dung string để lưu trư các số hạng là hợp lý cho việc nhâp số. Phép tinh sẽ được lưu trư bằng một ký tự.

5. Ngay trong đâu phân mã nguồn partial class FormMain: Form, bổ sung khai báo các biến

a. stNum1, stNum2 kiểu string để đại diện cho hai chuỗi số hạng.b. op kiểu char để đại diện cho phép toán (op là viết tắt của operator)

6. Cài đăt phân mã lệnh cho sự kiện FormLoad và sự kiện click của nút C như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 44

Page 45: Giao trinh visual studio[bookbooming.com]

7. Các nút bâm trong nhóm (1) được cài đăt phân mã lệnh tương ưng với sự kiện click như sau:

8. Phương thưc xử lý sự kiện click của nút bâm thuộc nhóm (2) – xác định phép tinh

9. Cuối cùng, phương thưc xử lý sự kiện click của nút bâm ‘=’ được cài đăt như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 45

Page 46: Giao trinh visual studio[bookbooming.com]

10. Đến đây, các tinh năng cơ ban của máy tinh đã được cài đăt. Chúng ta khao sát thêm một số hiệu ưng đăc biệt của lớp đối tượng Form:

a. Thiết lâp thuộc tinh TopMost bằng True để trong thơi gian thực thi, cửa sổ chương trinh luôn luôn nổi.

b. Bổ sung phương thưc xử lý sự kiện Activated và Deactive cho FormMain. Hai sự kiện này được kich hoạt tương ưng khi ngươi dùng chuyển focus tư vào ưng dung (Activated) hay ra khoi ưng dung (Deactive)

c. Minh họa khi chạy chương trinh: khi ngươi sử dung chuyển focus ra khoi cửa sổ ưng dung, cửa sổ này sẽ bị mơ đi 50%.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 46

Page 47: Giao trinh visual studio[bookbooming.com]

Mở rộng

- Cài đăt thêm các tinh năng khác cho máy tinh, chẳng hạn hỗ trợ phép tinh 1 ngôi như căn bâc 2, nghịch đao, phân trăm,… Chú ý phân xử lý lỗi (vi du như chia cho 0, căn bâc hai với số âm…)

- Hỗ trợ để ngươi sử dung có thể nhâp dư liệu bằng bàn phim.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 47

Page 48: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 2.5 myNotePAD

Tóm tắtChương trinh có các chưc năng cơ ban của một chương trinh soạn thao văn ban đơn gian (như Ms Windows NotePAD): Tạo mới, Soạn thao, Lưu lên đĩa, Mở tư đĩa. Chương trinh cũng cho phép ngươi sử dung thiết lâp các câu hinh phu như: font chư thể hiện (loại font, kich thước, màu sắc, ...).

Kỹ thuât được trinh bay

- Sử dung menu- Xây dựng ưng dung với nhiêu form- Lây danh sách font hệ thống- Cách liên hệ giưa các đối tượng thành phân thuộc các form, module khác nhau

Trinh tư thưc hiên

1. Tạo mới một project kiểu Windows Application, đăt tên là myNotePAD2. Đổi thuộc tinh Name của form thành FormMain3. Bổ sung các thành phân StatusBarStrip, MenuStrip với các menu lệnh như

minh họa.

4. Bổ sung thêm thành phân TextBox với tên gọi là txtDoc. Thiết lâp các thuộc tinh của txtDoc như sau:

Thuộc tính Gia trị

Multiline True

Dock Fill

Bai tập thưc hanh Chuyên đề Visual Studio .NET 48

Page 49: Giao trinh visual studio[bookbooming.com]

5. Khai báo một biến fileName kiểu string ở đâu phân mô ta lớp. Biến này sẽ lưu tên file đang được soạn thao. Sau đó cài đăt phương thưc xử lý sự kiện cho tât ca các ToolStripMenuItem như sau:

Phân xử lý cho “else if (stTask == “Configuration…”)…” sẽ được cài đăt sau.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 49

Page 50: Giao trinh visual studio[bookbooming.com]

Chú ý rằng thuộc tinh Text của các ToolStripMenuItem được sử dung để viết các câu lệnh if ở trên. Vây nên, bạn phai nhớ chinh xác các thuộc tinh Text của chúng để viết mã lệnh đúng.Thực ra, bạn có thể viết riêng rẽ cho tưng phương thưc xử lý sự kiện Click của tưng ToolStripMenuItem, tuy nhiên theo ý kiến của riêng ngươi viết giáo trinh này, cách gộp chung như ở trên giúp bạn tâp trung mã lệnh hơn.

6. Bước tiếp theo chúng ta cài đăt phân mã lệnh cho phép ngươi sử dung thay đổi font hiển thị tài liệu:Bổ sung một Form vào project bằng cách nhân tổ hợp phim Ctrl + Shift + A. Một hộp thoại như sau hiện ra:

Chọn loại đối tượng cân thêm là Windows Form, gõ tên file là “FormConfig.cs” rồi nhân Add.Sau thao tác này, Visual Studio sẽ tạo ra một file trong đó có khai báo lớp FormConfig (trùng tên với tên file mà bạn cung câp). Nếu muốn, chúng ta có thể đổi tên lớp của form này.

7. FormConfig sẽ làm nhiệm vu hiển thị danh sách các fonts hiện có trong hệ thống để ngươi sử dung chọn. Thiết kế giao diện của FormConfig như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 50

Page 51: Giao trinh visual studio[bookbooming.com]

Dự kiến, khi form này bắt đâu nạp nó sẽ hiển thị danh sách tât ca các fonts đang được cài đăt trong hệ thống vào lstFonts. Font đang được sử dung ở txtDoc (ở FormMain) sẽ được tô sáng trong lstFonts. Cuối cùng, khi ngươi sử dung nhân nút OK, font được chọn trong lstFonts sẽ được sử dung cho txtDoc. Như vây, đã có sự sử dung biến thành phân giưa hai forms: FormMain và FormConfig.

8. Trước hết, thiết lâp thuộc tinh DialogResult của hai nút OK và Cancel là OK và Cancel. Có thể thiết lâp thêm các thuộc tinh Anchor của các đối tượng để có giao diện hợp lý.

9. Thiết lâp thuộc tinh Modifiers của lstFonts là Public. Bằng cách này, chúng ta có thể truy xuât đến thành phân lstFonts tư bên ngoài.

10. Bổ sung biến thành phân stFontName kiểu string vào khai báo FormConfig, xem (1).

11. Sửa phương thưc khởi dựng của lớp FormConfig như (2).12. Viết mã cho phương thưc xử lý sự kiện Load của form như (3).

13. Hoàn thiện phân gọi FormConfig ở FormMain như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 51

Page 52: Giao trinh visual studio[bookbooming.com]

Mở rộng

- Cài đăt thêm các chưc năng thương dùng khác đối với ưng dung soạn thao văn ban

- Sửa lại ưng dung theo giao diện MDI

Bai tập thưc hanh Chuyên đề Visual Studio .NET 52

Page 53: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 2.6 Quan ly sinh viên - WinForms version

Tóm tắtThực hiện lại chương trinh quan lý sinh viên như bài thực hành 1.7 nhưng giao tiếp với ngươi sử dung thông qua giao diện Windows.

Chương trinh có thể tạo mới, mở và lưu tâp tin chưa dư liệu vê các sinh viên có định dạng như vi du sau:

Nguyễn Văn Trung|True|1981/10/25 00:00:00|9|10|10Trịnh Phương|False|1984/11/20 00:00:00|4|9Trân Văn Phúc|True|1999/10/01 00:00:00|6|6.5|6.5|8Đăng Phương Nam|True|1991/10/25 00:00:00|2|10Trịnh Phương Lan|False|1994/11/20 00:00:00|2|9

Theo định dạng lưu này, mỗi dòng thông tin sẽ chưa các thông tin Họ tên, Giới tinh, Ngày sinh, sau đó là các cột điểm. Nếu có 3 (tương ưng 2, 4) cột điểm thi sinh viên đó thuộc chuyên ngành CNTT (tương ưng Văn, Vât lý). (Xem lại Bài thực hành 1.7 để biết thêm vê mô ta thông tin sinh viên).

Khi ngươi sử dung chọn một sinh viên trong danh sách (danh sách này chỉ hiển thị tên sinh viên) thi các thông tin chi tiết vê sinh viên này sẽ được hiển thị và cho phép chỉnh sửa tương ưng (xem hinh vẽ). Chú ý rằng, tùy theo chuyên ngành của sinh viên, tên các môn học sẽ được hiển thị một cách hợp lý.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 53

Page 54: Giao trinh visual studio[bookbooming.com]

Kỹ thuât được trinh bay

- Sử dung kỹ thuât hướng đối tượng trên ưng dung GUI- Truy xuât file có định dạng quy ước sẵn

Trinh tư thưc hiên

1. Tạo form có giao diện như minh họa. Đăt tên các thành phân cho hợp lý

2. Thiết kế các lớp đối tượng sinh viên như sơ đồ lớp được mô ta ở dưới. Các phương thưc, thuộc tinh của các lớp này đã được xây dựng trong các bài thực hành trước, ở đây ta chỉ thao luân thêm vê hàm ToFormatText() ở các lớp:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 54

Page 55: Giao trinh visual studio[bookbooming.com]

Trong lớp SinhVien, đăc ta hàm này như là một hàm ao và không cho sử dung trực tiếp tư thể hiện thuộc lớp SinhVien như sau:

Đối với lớp SinhVienCNTT, hàm này được override lại thành:

Tương tự, đối với lớp SinhVienVan và SinhVienVL, hàm này lân lượt được cài đăt như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 55

Page 56: Giao trinh visual studio[bookbooming.com]

3. Xử lý sự kiện mở file dư liệu, nạp vào listBox:o Bổ sung biến thành phân fileName để chưa tên file dư liệu

o Bổ sung thêm phương thưc void updateFormTitle()

o Thêm sự kiện Click cho nút Open như sau:

Chú ý rằng, các lớp SinhVienVan, SinhVienCNTT, SinhVienVL đêu phai override hàm ToString() để được hiển thị ngắn gọn trong hộp danh sách.

4. Xử lý sự kiện tạo mới file dư liệua. Thêm phương thưc xử lý sự kiện Click của nút New

Bai tập thưc hanh Chuyên đề Visual Studio .NET 56

Page 57: Giao trinh visual studio[bookbooming.com]

b. Gán phương thưc xử lý sự kiện này cho sự kiện Load của Form5. Khi ngươi sử dung chọn 1 sinh viên trong lstSinhVien, thông tin chi tiết vê sinh

viên này sẽ được hiển thị. Viết phương thưc xử lý sự kiện SelectedIndexChanged của lstSinhVien như sau:

6. Viết phương thưc xử lý sự kiện Click của nút “Câp nhât”, “Xóa” và “Bo câp nhât” như (1), (2), (3):

Bai tập thưc hanh Chuyên đề Visual Studio .NET 57

Page 58: Giao trinh visual studio[bookbooming.com]

7. Cài đăt phương thưc xử lý sự kiện Click cho 4 nút “|<”, “<”, “>”, “>|” như sau:

8. Tiếp đến, cài đăt phương thưc xử lý sự kiện Click của nút bâm Save và Save as…

Bai tập thưc hanh Chuyên đề Visual Studio .NET 58

Page 59: Giao trinh visual studio[bookbooming.com]

Mở rộng

- Thêm phân xử lý lỗi cho chương trinh- Bổ sung chưc năng Tạo mới Sinh viên

Bai tập thưc hanh Chuyên đề Visual Studio .NET 59

Page 60: Giao trinh visual studio[bookbooming.com]

Bai thưc hanh 2.7 myFileViewer

Tóm tắtTrong bài thực hành này, bạn sẽ được tiếp cân một số kỹ thuât nâng cao như: kế thưa form, thành phân điêu khiển TreeView, ListView, ... Ứng dung cuối cùng được tạo ra sẽ là ưng dung quan lý tâp tin kiểu ACDSee.

Kỹ thuât được trinh bay

- Thưa kế form- Làm quen với các component, các thư viện nâng cao

Trinh tư thưc hiên

1. Tạo mới một ưng dung kiểu Windows Application với tên là fileViewer. Đăt tên cho form chinh là FormMain.

2. Thiết kế giao diện ban đâu cho FormMain như hinh vẽ. Khi chạy chương trinh, vùng bên tay trái sẽ hiển thị cây thư muc (đối tượng tvwDirs). Mỗi khi chọn 1 thư muc ở cây, nội dung của nó được hiển thị ở lvwItems bên phai. Ngay phia dưới tvwDirs là vùng “preview” nội dung của file được chọn trong lvwItems.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 60

Page 61: Giao trinh visual studio[bookbooming.com]

3. Thêm vào Form một đối tượng ImageList có tên là imageList1 với các anh như hinh dưới:

4. Gán imageList1 cho thuộc tinh ImageList của tvwDirs và lvItems.5. Viết mã lệnh cho sự kiện Load của FormMain như (1)

Bai tập thưc hanh Chuyên đề Visual Studio .NET 61

Page 62: Giao trinh visual studio[bookbooming.com]

Trước hết, lây danh sách các ổ đĩa của hệ thống. Ứng với mỗi đĩa như vây, ta sẽ thêm tât ca các thư muc con câp 1 của ổ đĩa (hãy giai thich?) bằng cách gọi phương thưc (2). Để ý rằng (2) sẽ được gọi đệ quy.

6. Khi ngươi dùng nhân vào dâu “+” của một node trên treeview để mở nhánh này ra, ta phai hiển thị được tât ca các thư muc con của nó. Việc này được chuẩn bị qua phương thưc xử lý sự kiện BeforeExpand của treeview tvwDirs:

7. Khi ngươi sử dung chọn một node trên cây thi nội dung của thư muc tương ưng (bao gồm tât ca thư muc và files chưa trong nó) sẽ được hiển thị trong listview lvItems. Để thuân tiện cho nhưng thao tác khác sau này của ưng dung, chúng ta quy ước, trong lvItems, phân tử đại diện cho file sẽ có ImageIndex là 2, còn phân tử đại diện cho thư muc sẽ có ImageIndex là 0.Chúng ta xử lý sự kiện AfterSelect của tvwDirs như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 62

Page 63: Giao trinh visual studio[bookbooming.com]

Chú ý rằng, ngoài các thư muc và tâp tin, ta thêm vào một “thư muc” đăc biệt, thư muc “..” đại diện cho thư muc cha của thư muc hiện tại.

8. Tiếp đến, chúng ta viết mã cho sự kiện nhân đúp chuột vào một phân tử trong listview. Có 3 kha năng xay ra:(1) ngươi sử dung nhân đúp vào phân tử là thư muc “..” chuyển đến thư muc

trên câp của thư muc hiện tại(2) ngươi sử dung nhân đúp vào phân tử thư muc binh thương chọn thư muc

đó làm thư muc hiện tại(3) ngươi sử dung nhân đúp vào phân tử là một file hiển thị nội dung của file

này ra một cửa sổ riêng một cách thich hợp theo nội dung của nó.

Trong phân code dưới đây, ta chỉ quan tâm đến 2 kha năng đâu. Kha năng còn lại sẽ được hoàn thiện ở các bước sau.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 63

Page 64: Giao trinh visual studio[bookbooming.com]

9. Tiếp theo, ta sẽ cài đăt thêm chưc năng Preview nội dung của phân tử file anh đang được chọn trong listview lvItems. Sự kiện SelectedIndexChanged của lvItems được xử lý như sau:

10. Phân còn lại của bài thực hành sẽ hướng dân bạn cài đăt phân xử lý kha năng (3) trong bước 8. Gia sử rằng, ưng dung của chúng ta chỉ hỗ trợ hiển thị ra cửa sổ 2 loại nội dung: anh và văn ban. Như thế, để hiển thị mỗi loại nội dung, chúng ta cân 1 loại form khác nhau. Tuy thế, ca hai loại form này cũng có một số thuộc tinh và hành vi chung. Ta xác định mối quan hệ của chúng qua sơ đồ lớp như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 64

Page 65: Giao trinh visual studio[bookbooming.com]

Tạo mới một Form để hiển thị nội dung file như sau:

11. Thiết kế giao diện cho FormFile như sau:o Đăt một Panel tên pnlButtons neo phia dưới Form (Dock = Bottom).

o Trên pnlButtons, đăt nút btnClose vào vị tri thich hợp.

o Có thể trang tri thêm cho pnlButtons, vi du đăt một Label trong nó như

hinh minh họa.o Phân trống còn lại của form dự kiến sẽ dùng để hiển thị nội dung của

file.

12. Cài đăt mã lệnh cho form như sauo Cài đăt phương thưc xử lý sự kiện Click của nút btnClose (1)

Bai tập thưc hanh Chuyên đề Visual Studio .NET 65

Page 66: Giao trinh visual studio[bookbooming.com]

o Bổ sung thêm hàm virtual showContent() vào lớp (2). Dự kiến hàm này

sẽ làm nhiệm vu hiển thị nội dung của file: tùy theo file anh hay file văn ban mà có cách hiển thị khác nhau, nhưng thao tác chung nhât là hiển thị đương dân của file lên tiêu đê cửa sổ.

13. Lưu và Build ưng dung. (rât quan trọng cho các bước sau!)14. Bây giơ, ta bổ sung thêm một Windows Form vào project. Tuy nhiên khác với

các lớp cửa sổ ta đã bổ sung trước đó, lân này ta sẽ bổ sung một Windows Form kế thưa tư một lớp ta đã thiết kế. Cu thể là FormFileImage kế thưa tư FormFile.

15. Visual Studio sẽ hiển thị hộp thoại hoi lớp mà FormFileImage được kế thưa:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 66

Page 67: Giao trinh visual studio[bookbooming.com]

Chọn FormFile làm Form để kế thưa rồi nhân OK16. FormFileImage được tạo ra với giao diện như dưới đây:

Để ý, các thành phân được kế thưa sẽ tư lớp cha có mũi tên nho bên góc trái. Hơn nưa, nhưng thành phân thuộc loại Private thi sẽ có thêm biểu tượng ổ khóa, bạn không thể thay đổi thuộc tinh của nó trong lớp kế thưa. Vi du, nếu muốn chỉnh sửa thuộc tinh Text của nút btnClose trong FormFileImage, bạn phai thiết lâp btnClose ở FormFile thuộc loại Protected hoăc Public.

17. Bây giơ, bổ sung thêm một PictureBox có tên là pic vào FormFileImage. Thiết lâp thuộc tinh Dock của nó là Fill. Xem hinh minh họa

Bai tập thưc hanh Chuyên đề Visual Studio .NET 67

Page 68: Giao trinh visual studio[bookbooming.com]

18. Trong phân mã lệnh cho FormFileImage, ta override hàm showContent như sau:

19. Tương tự như các bước tạo FormFileImage, ta tạo thêm một Windows Form có tên là FormFileText kế thưa tư FormFile có giao diện và phân cài đăt mã lệnh như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 68

Page 69: Giao trinh visual studio[bookbooming.com]

20. Cuối cùng, ta hoàn chỉnh chưc năng (3) đã mô ta ở Bước 8 bẳng cách sửa lại phương thưc xử lý sự kiện DoubleClick của lvItems như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 69

Page 70: Giao trinh visual studio[bookbooming.com]

Mở rộng

- Bổ sung thêm chưc năng preview cho file văn ban- Cài đăt chưc năng cho các menu

Bai tập thưc hanh Chuyên đề Visual Studio .NET 70

Page 71: Giao trinh visual studio[bookbooming.com]

PPHHÂÂ NN 3 3XXƯƯ LYLY DƯDƯ LIÊLIÊ UU VƠVƠ II ADO.NET ADO.NET

Xử lý dư liệu là nhiệm vu phổ biến và quan trọng của nhiêu chương trinh ưng dung. Dư liệu được truy xuât, xử lý của một chương trinh ưng dung có thể là một tâp tin văn ban, tâp tin các ban ghi, hay là một nguồn dư liệu tư CSDL nào đó. .NET Framework cung câp một lượng lớn các thành phân giao diện (Win Forms, Web Forms) hỗ trợ cho việc trinh bày, kết buộc (bind) dư liệu. Cùng với đó là nên tang xử lý dư liệu ADO.NET cung câp cách thưc làm việc với nhiêu loại nguồn dư liệu khác nhau một cách linh động. Do tinh chât quan trọng của việc xử lý dư liệu trong một ưng dung cùng với sự phưc tạp của ADO.NET, trước khi bắt tay vào thực hiện các bài tâp thực hành, chúng ta khao sát qua một số điểm lý thuyết cơ ban.

Kiến thưc cơ ban về ADO.NET 2.0

3.1 Kiến trúc tổng quan của ADO.NETKiến trúc của ADO.NET được mô ta như hinh dưới, bao gồm hai thành phân chinh: Thanh phân truy cập nguồn dữ liệu và thanh phân lưu trữ xử ly dữ liệu.

Thanh phân thứ nhất:.NET Framework Data Provider được thiết kế để thực hiện các thao tác kết nối, gửi các lệnh xử lý đến CSDL (thành phân này còn được gọi với một tên khác là lớp kết nối – Connectectivity Layer). Trong ADO.NET, có 4 đối tượng chinh với các chưc năng cơ ban như sau:

Connection: giúp thực hiện kết nối đến các CSDL

Bai tập thưc hanh Chuyên đề Visual Studio .NET 71

Page 72: Giao trinh visual studio[bookbooming.com]

Command: giúp truy câp đến CSDL và thực hiện các phát biểu SQL hay thủ tuc lưu trư sẵn (stored procedure) của CSDL

DataReader: dùng để đọc nhanh nguồn dư liệu, chỉ được duyệt tuân tự theo chiêu tiến của các record

DataAdapter: dùng để chuyển dư liệu truy vân được cho các đối tượng lưu trư và xử lý (DataSet, DataTable). DataAdapter chủ yếu thực hiện các thao tác như SELECT, INSERT, UPDATE, DELETE

Vê măt thực chât, thành phân .NET Framework Data Provider cung câp giao diện lâp trinh chung để làm việc với các nguồn dư liệu. Mỗi nha cung cấp 3 đăc thù sẽ đưa ra một loại data provider riêng. Dưới đây là bang mô ta giao diện lâp trinh cùng với các lớp cơ ban của các data provider mà ADO.NET cung câp sẵn:

Interface SQL Server Provider

Oracle Provider OLEDB Provider ODBC Provider

IDbConnection SqlConnection OracleConnection OledbConnection OdbcConnectionIDbDataAdapter SqlDataAdapter OracleDataAdapter OledbDataAdapter OdbcDataAdapterIDbCommand SqlCommand OracleCommand OledbCommand OdbcCommandIDbDataReader SqlDataReader OracleDataReader OledbDataReader OdbcDataReader

Để sử dung data provider nào, chúng ta phai tiến hành khái báo using namspace tương ưng. Chẳng hạn, using System.Data.SqlClient;

Ngoài nhưng data provider mô ta ở bang trên, chúng ta có thể reference đến các data provider khác không được tich hợp sẵn bởi ADO.NET trong Visual Studio .NET, chẳng hạn như data provider dùng cho MySQL, Postgre, …

Thanh phân thứ hai trong kiến trúc ADO.NET – DataSet – được xem như là container dùng để lưu trư đối tượng liên quan đến dư liệu như DataTable, DataRelation, DataView. Thành phân này còn được gọi là lớp không kết nối (disconected layer). DataSet như là một CSDL thu nho tại máy client, có thể chưa các đối tượng table, view, constaint, ralationship giưa các table, … Tât ca dư liệu tư nguồn dư liệu thực sẽ được nạp vào DataSet dưới dạng các DataTable, đó là một snapshot của nguồn dư liệu thực. Khối dư liệu này sẽ được chỉnh sửa độc lâp, sau đó nếu cân sẽ được câp nhât trở lại nguồn dư liệu thực. Theo nguyên tắc này, chúng ta không cân duy tri kết nối liên tuc một cách không cân thiết với nguồn dư liệu thực trong suốt quá trinh thao tác với nó.

3 Nhà cung câp ở đây được hiểu theo nghĩa ca vê loại nguồn dư liệu lân cách thưc truy xuât nguồn dư liệu. Vi du, ngoài data provider SqlClient do Microsoft cung câp, cũng có thể có một tổ chưc khác phát triển một provider khác để truy xuât loại nguồn dư liệu này.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 72

Page 73: Giao trinh visual studio[bookbooming.com]

3.2 Tổng quan về cac mô hinh xư ly dư liêu trong ADO.NET: Mô hinh Kết nối (Connected Model) va Mô hinh Ngắt Kết nối (Disconnected Model)

3.2.1 Mô hinh Kết nốiTrong mô hinh kết nối của ADO.NET, có một connection hoạt động được duy

tri giưa đối tượng DataReader của ưng dung và một data source (nguồn dư liệu). Một dòng dư liệu (data row) được tra vê tư data source mỗi khi phương thưc Read của đối tượng DataReader được thực thi. Điểm quan trọng nhât của mô hinh kết nối đó là dư liệu được lây tư tâp dư liệu (các record được tra vê bởi một lệnh SQL nào đó) theo kiểu tưng record một cho một lân đọc, chỉ đọc (read-only), và chỉ theo một hướng tiến (forward-only). Hinh dưới đây mô ta cách sử dung DataReader trong chế độ kết nối.

Các bước điển hinh để làm việc với đối tượng DataReader là như sau:

1. Tạo đối tượng Connection bằng cách truyên một chuỗi Connection string cho hàm khởi dựng của nó.

2. Khởi tạo một biến chuỗi và gán cho câu lệnh SQL dựa theo dư liệu muốn nạp vê.

3. Khởi tạo một đối tượng Command tư với nội dung câu lệnh SQL đã xác định ở trên.

4. Tạo đối tượng DataReader bằng cách thực thi phương thưc Command.ExecuteReader(). Đối tượng này sau đó sẽ được dùng để đọc kết qua của câu truy vân mỗi dòng một lân.

Đoạn code sau minh họa các bước trên với Data Provider SqlClient. Đoạn code sẽ đọc danh sách họ tên các sinh viên trong một bang SinhVien của cơ sở dư liệu và hiển thị lên một điêu khiển ListBox. Chi tiết vê các đối tượng DataReader, Command, Connection sẽ được đê câp chi tiết sau.

using System.Data.SqlClient;

...

// (1) Tao ConnectionSqlConnection cn = new SqlConnection(chuoiKetNoi);

cn.Open();

Bai tập thưc hanh Chuyên đề Visual Studio .NET 73

Page 74: Giao trinh visual studio[bookbooming.com]

// (2) Chuoi SQL thuc hien lay danh sach ten cac sinh vien xep tang dan theo NgaySinhstring sql = "SELECT HoTen FROM SinhVien ORDER BY NgaySinh";

// (3) Tao doi tuong CommandSqlCommand cmd = new SqlCommand(sql, conn);

DbDataReader rdr;

// (4) Tao doi tuong DataReaderrdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);

while (rdr.Read())

listBox1.Items.Add(rdr["HoTen"]); // Fill ListBox

rdr.Close(); // Dong datareader sau khi da su dung xong

Tham số được sử dung trong phương thưc ExecuteReader xác định đối tượng Connection sẽ được đóng sau khi DataReader được đóng.

3.2.2 Mô hinh Ngắt Kết nốiTriết lý của mô hinh Ngắt kết nối đó là: Dư liệu được nạp – sử dung một lệnh SQL – tư nguồn dư liệu bên ngoài vào bộ nhớ đệm tại máy client; tâp kết qua được xử lý tại máy cuc bộ; mọi câp nhât sau đó sẽ được truyên tư dư liệu trong bộ nhớ ngược trở lại nguồn dư liệu.

Mô hinh được gọi là “ngắt kết nối” bởi vi đối tượng kết nối chỉ được mở đủ lâu để đọc dư liệu tư nguồn dư liệu và tiến hành các thao tác câp nhât. Bằng cách đưa dư liệu vê phia máy client, tài nguyên của server – chẳng hạn như thông tin dư liệu Connection, bộ nhớ, thơi gian xử lý – sẽ được giai phóng bớt. Tuy vây, mô hinh này cũng có nhược điểm vê thơi gian cân để nạp tâp dư liệu và bộ nhớ dùng để chưa dư liệu tại máy client.

Như hinh dưới đây minh họa, các thành phân chinh của mô hinh ngắt kết nối đó là DataApdapter và DataSet. DataAdapter làm nhiệm vu như là câu nối giưa nguồn dư liệu và DataSet, nạp dư liệu vào các bang của DataSet và đẩy các thay đối ngược trở lại nguồn dư liệu. Một DataSet đóng vai trò như là một cơ sở dư liệu quan hệ nằm trong bộ nhớ, chưa một hay nhiêu DataTables, giưa các DataTable này cũng có thể có các mối quan hệ với nhau như trong một cơ sở dư liệu quan hệ thực. Một DataTable chưa các dòng và các cột dư liệu thương được lây tư cơ sở dư liệu nguồn.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 74

Page 75: Giao trinh visual studio[bookbooming.com]

Trong số các phương thưc và thuộc tinh của DataAdapter thi Fill() và Update() là hai phương thưc quan trọng nhât. Fill() chuyển một query đến cơ sở dư liệu và lưu tâp kết qua tra vê trong một DataTable nào đó; phương thưc Update() thực hiện một thao tác thêm, xóa, câp nhât dựa trên nhưng thay đối của đối tượng DataSet. Các lệnh câp nhât thực sự được chưa trong các thuộc tinh của DataAdapter. Chi tiết vê DataAdapter sẽ được đê câp ở phân sau.

Để minh họa cách thưc làm việc với DataAdapter và DataSet, đoạn code dưới đây giới thiệu cách tạo ra một đối tượng DataTable, nạp dư liệu tư một cơ sở dư liệu, và đưa nó vào một DataSet.

string sql = "SELECT MaSinhVien, HoTen, NgaySinh FROM SinhVien";

string connStr = "Data Source=MYSERVER;Initial Catalog=qlsinhvien; User Id=k28;Password=k28;";

// (1) Tao doi tuong data adapterSqlDataAdapter da = new SqlDataAdapter(sql, connStr);

// (2) Tao doi tuong datasetDataSet ds = new DataSet();

// (3) Tao mot Table co ten “SinhVien” trong dataset va nap du lieu cho noda.Fill(ds, "SinhVien");

// (4) Hien thi danh sach ten sinh vien ra list boxDataTable dt = ds.Tables["SinhVien"];

for (int i=0; i< dt.Rows.Count;i++){ DataRow row = dt.Rows[i]; listBox1.Items.Add(row["HoTen"]);}

Bước đâu tiên là tạo ra một thể hiện của SqlDataAdapter bằng cách truyên một câu lệnh SELECT và chuỗi kết nối cho phương thưc khởi dựng của lớp này. DataAdapter sẽ lo đến việc tạo ra đối tượng Connection cũng như việc mở, đóng Connection khi cân thiết. Sau khi một DataSet rỗng sẽ được tạo ra, phương thưc Fill()

Bai tập thưc hanh Chuyên đề Visual Studio .NET 75

Page 76: Giao trinh visual studio[bookbooming.com]

của DataAdapter sẽ tạo ra một DataTable có tên là “SinhVien” trong DataSet và nạp các dòng dư liệu vào DataTable này (bằng câu lện SQL dạng SELECT của DataAdapter). Mỗi column của DataTable sẽ tương ưng với một column trong bang của cơ sở dư liệu nguồn. Dư liệu trong bang dư liệu sau đó được đưa vào một ListBox bằng cách duyệt qua danh sách các dòng của DataTable.

3.3 Lam viêc vơi mô hinh Kết nối trong ADO.NETNhư đã mô ta tổng quan trong phân trước, mô hinh Kết nối được dựa trên việc

thiết lâp một Connection đến CSDL và sau đó sử dung các Command để thực hiện việc thêm, xóa, sửa, hay đọc dư liệu tư data source (nguồn dư liệu) được kết nối. Đăc điểm phân biệt của mô hinh này đó là các Command được phát sinh, làm việc với data source thông qua một Connection đang hoạt động – Connection này sẽ mở cho đến khi các thao tác được hoàn tât. Cho dù là làm việc với mô hinh Kết nối hay Ngắt kết nối, bước đâu tiên trong quá trinh truy xuât một data source đó là tạo ra một đối tượng Connection để làm đương truyên giưa ưng dung với data source.

3.3.1 Lơp ConnectionCó nhiêu lớp Connection trong ADO.NET – mỗi lớp tương ưng với một Data Provider – bao gồm SqlConnection, OracleConnection, OleDbConnection, OdbcConnection. Măc dù mỗi lớp có thể gồm nhưng đăc tinh riêng, nhưng các lớp này đêu phai implement interface IDbConnection. Bang dưới đây tóm tắt các thành phân được định nghĩa bởi interface này.

Loại Tên Mô taProperty ConnectionString Get/Sets chuỗi kết nối đến data source.Property ConnectionTimeout Khoang thơi gian tối đa tinh bằng giây để chơ thực

hiện việc kết nối đến data sourceProperty Database Tên CSDL ưng với Connection hiện tạiProperty State Trạng thái hiện tại của Connection. Tra vê một giá

trị kiểu liệt kê (enumeration): Broken, Closed, Connecting, Executing, Fetching, hoăc Open

Method OpenClose

Mở một Connection. Roll back mọi thao tác đang làm dở.Đóng Connection – tra Connection cho Connection Pool nếu như có sử dung Connection Pool

Method BeginTransaction Khởi tạo một database transactionMethod ChangeDatabase Thay đối CSDL hiện tại cho Connection đang mở.

Chuỗi mô ta tên CSDL mới được truyên cho phương thưc này

Method CreateCommand Tạo ra một đối tượng Command ưng với Connection

Bai tập thưc hanh Chuyên đề Visual Studio .NET 76

Page 77: Giao trinh visual studio[bookbooming.com]

3.3.1.1 Connection stringThuộc tinh ConnectionString xác định data source và các thông tin cân thiết để

truy xuât data source, chẳng hạn như User ID và Password, … Ngoài nhưng thông tin cơ ban này, Connection string còn có thể chưa các giá trị cho các trương dư liệu đăc trưng cho data provider. Vi du, Connection string cho Ms Sql Server có thể chưa các giá trị để quy định Connection Timeout và Packet Size.

Dưới đây là các vi du vê cách thành lâp chuỗi kết nối cho các data provider thương găp. Danh sách đây đủ vê cách thành lâp các chuỗi kết nối được cho ở Phu lucA .

SqlConnection sử dung cơ chế xác thực kiểu SQL Server:

“server=;database=;uid=;pwd=” hoăc

“Data Source=;Initial Catalog=;User ID=;Password=”

SqlConnection sử dung cơ chế xác thực kiểu Windows:

“Server=;Database=;Trusted_Connection=yes”

Ở đây, là tên/máy chủ chưa CSDL, là tên CSDL, là tên đăng nhâp, là mât khẩu tương ưng.

Vi du: “server=192.168.0.1;database=qlnhanvien;uid=k28;pwd=spider” hoăc “Server=192.168.0.1;Database=qlnhanvien;Trusted_Connection=yes”

OleDbConnection sử dung để kết nối CSDL Access phiên ban trước 2003:

“Provider=Microsoft.Jet.OLEDB.4.0;DataSource=”

Vi du:

o string stConnection =

string.Format(“Provider=Microsoft.Jet.OLEDB.4.0;DataSource={0}”, @”c:\program files\qlnhanvien.mdb”);

o Sử dung trong ưng dung Internet: string stConnection =

string.Format(“Provider=Microsoft.Jet.OLEDB.4.0;DataSource={0}”,Server.MapPath(“/data/qlnhanvien.mdb”);

ODBC: “DSN=” với là Data Source Name (DSN), vi du “DSN=qlnhanvien”

Các Connection string được dùng để tạo ra đối tượng Connection. Cách thực hiện thông thương là truyên chuỗi này cho hàm khởi dựng như vi du dưới đây:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 77

Page 78: Giao trinh visual studio[bookbooming.com]

string stConnection = "Data Source=192.168.0.1;” +“Initial Catalog=films;” +“User Id=k28;”+“Password=spider";

SqlConnection cn = new SqlConnection(stConnection);cn.Open(); //Open connection

3.3.1.2 Connection PoolingTạo một Connection là một quá trinh tốn nhiêu thơi gian – trong một số trương

hợp, việc này thâm chi còn tốn thơi gian hơn việc thực thi các Command. Để loại bo điêu này, ADO.NET cung câp một khái niệm gọi là connection pool. Connection pool quan lý các Connection có trùng Connection string để tối ưu hóa số lân thiết lâp, hợp lệ hóa thông tin kết nối.

Các quy tắc quy định connection pool cân biết:

- Cơ chế Connection pooling được kich hoạt theo măc định. Cơ chế này được tắt bằng cách thêm vào Connection string “Pooling=false” đối với SqlConnection hoăc “OLE DB Services=-4” đối với OleDbConnection.

- Mỗi connection pool được ưng với một connection string duy nhât. Khi có một Connection được yêu câu, pool handler (bộ quan lý pool) sẽ so sánh connection string với nhưng connection string trong các pools đang tồn tại. Nếu có một Connection trùng khớp thi Connection tương ưng sẽ được xác định trong pool.

- Nếu tât ca các connection trong pool đang được sử dung khi lại có yêu câu vê connection thi yêu câu đó sẽ được xếp vào hàng đợi cho đến khi có một connection ranh. Các connection sẽ được giai phóng khi phương thưc Close hay Dispose của đối tượng connection được gọi.

- Connection pool được đóng khi tât ca các connection trong nó được giai phóng và hết thơi gian (time out).

Đối với SQL Server, bạn có thể điêu khiển hành vi của conneciton pooling bằng cách gộp các căp key-value vào connection string. Các key này có thể được sử dung để thiết lâp số lượng nho nhât và lớn nhât các connection trong pool cũng như xác định xem một connection có cân phai reset khi nó được lây tư pool ra hay không. Một key đăc biệt chú ý đó là key có tên Lifetime, xác định thơi gian mà connection có thể tồn tại trước khi nó bị hủy bo. Giá trị này được kiểm tra khi một connection được tra vê cho pool. Nếu connection đã được mở trước đó, và lâu hơn giá trị Lifetime thi nó sẽ bị hủy.

Đoạn code dưới đây minh họa các dùng các key này cho SqlClient:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 78

Page 79: Giao trinh visual studio[bookbooming.com]

string stConnection = "Server=192.168.0.1;” + “Trusted_Connection=yes;” + “database=qlnhanvien;" + "connection reset=false;" + "connection Lifetime=60;" + // Seconds "min pool size=1;" + "max pool size=50"; // Default=100

SqlConnection cn = new SqlConnection(cnString);

3.3.2 Đối tượng CommandSau khi một đối tượng connection được tạo ra, bước tiếp theo trong quá trinh truy xuât CSDL – đối với mô hinh Kết nối – đó là tạo ra một đối tượng Command để gửi một query (select) hay một action command (thêm, xóa, sửa) đến data source. Có nhiêu loại lớp Command ưng với các data provider; các lớp này đêu implement interface IDbCommand.

3.3.2.1 Tạo đối tượng CommandBạn có thể dùng một trong nhiêu hàm khởi dựng để tạo đối tượng Command một cách trực tiếp hoăc sử dung cách tiếp cân ProviderFactory.

Đoạn code dưới đây minh họa các tạo ra một đối tượng Command và thiết lâp các thuộc tinh của nó.

SqlConnection conn = new SqlConnection(connstr);

conn.open();

string sql = "INSERT INTO SinhVien (MaSinhVien, HoTen) VALUES (@pMaSinhVien,

@pHoTen)";

SqlCommand cmd = new SqlCommand();cmd.Connection = conn;cmd.commandText = sql;cmd.Parameters.AddWithValue ("@pMaSinhVien", 12);cmd.Parameters.AddWithValue ("@pHoTen", "tnv spider");

Trong trương hợp ưng dung có thể phai sử dung nhiêu data provider, bạn nên sử dung cách tiếp cân provider factory. Factory được tạo ra bằng cách truyên chuỗi data provider cho hàm khởi dựng của nó. Tiếp đến, phương thưc CreateCommand được gọi để tra vê một đối tượng command.

string provider = "System.Data.SqlClient";

Bai tập thưc hanh Chuyên đề Visual Studio .NET 79

Page 80: Giao trinh visual studio[bookbooming.com]

DBProviderFactory factory = DbProviderFactories.GetFactory(provider);

DbCommand cmd = factory.CreateCommand(); // DbCommand là một lớp trưu tượng

cmd.CommandText = sql; // sql là một chuỗi query hay command

cmd.Connection = conn; // conn là một Connection

3.3.2.2 Thưc thi một CommandLệnh SQL được gán trong thuộc tinh CommandText của đối tượng Command sẽ được thực thi bằng một trong các phương thưc được chỉ ra ở bang dưới đây

Phương thưc Mô taExecuteNonQuery Thực thi truy vân hành động (action query) và tra vê số lượng

dòng dư liệu bị anh hưởng bởi truy vân đó:

cmd.CommandText = "DELETE SinhVien WHERE MaSinhVien=12";

int soLuong = cmd.ExecuteNonQuery();

ExecuteReader Thực thi một query và tra vê đối tượng DataReader để có thể truy câp tâp kết qua của query đó. Phương thưc này nhân một tham số tùy chọn kiểu CommandBehavior để có thể tăng hiệu năng thực thi query.

cmd.CommandText = "SELECT * FROM SinhVien” + “WHERE YEAR(NgaySinh) > 1981”;

SqlDataReader rdr= cmd.ExecuteReader();

ExecuteScalar Thực thi một query và tra vê giá trị của cột đâu tiên trong dòng đâu tiên của tâp kết qua.

cmd.CommandText="SELECT COUNT(MaSinhVien) FROM SinhVien";

int soSinhVien = (int)cmd.ExecuteScalar();

ExecuteXmlReader Chỉ có cho data provider SQL Server. Tra vê một đối tượng XmlReader dùng để truy xuât tâp dư liệu. Tham khao thông tin vê XmlReader trong MSDN

Bai tập thưc hanh Chuyên đề Visual Studio .NET 80

Page 81: Giao trinh visual studio[bookbooming.com]

ExecuteReader là phương thưc quan trọng nhât trong các phương thưc kể trên. Phương thưc này tra vê một đối tượng DataReader giúp truy xuât đến các dòng dư liệu tra vê bởi query. Xem vi du dưới đây:

dr = cmd.ExecuteReader(sql, );

Ở đây, là một giá trị kiểu CommandBehavior để chỉ định behavior (hành vi) thực thi của query. Một số data providers sử dung để tối ưu quá trinh thực thi query. Danh sách các giá trị và tác dung của tham số được mô ta chi tiết như dưới đây:

SingleRow. Chỉ định rằng query chỉ tra vê 1 dòng dư liệu. Behavior măc định là tra vê nhiêu tâp kết qua.

SingleResult. Query tra vê một giá trị tuyến tinh đơn nhât (single scalar value).

KeyInfo. Tra vê thông tin vê column và primary key. Behavior này được sử dung với phương thưc GetSchema của DataReader để lây thông tin vê các column trong lược đồ (schema).

SchemaOnly. Dùng để lây vê tên của các cột trong tâp dư liệu tra vê:

Vi du

dr = cmd.ExecuteReader(CommandBehavior.SchemaOnly);

string col1 = dr.GetName(0); // tên cột đâu tiên

SequentialAccess. Cho phép dư liệu trong dòng tra vê có thể được truy xuât tuân tự theo column. Behavior này được dùng cho các trương dư liệu BLOB hay TEXT.

CloseConnection. Đóng connection khi DataReader được đóng.

3.3.2.3 Thưc thi Stored Procedure (thủ tục lưu trữ sẵn) với đối tượng CommandMột stored procedure là một đoạn code SQL được lưu sẵn trong CSDL và có thể được thực thi như là một script. ADO.NET hỗ trợ việc thực thi các stored procedure cho các data provider OleDb , SqlClient, ODBC, và OracleClient.

Các bước để thực thi một stored procedure:

- Thiết lâp thuộc tinh SqlCommand.CommandText thành tên của procedure;

- Thiết lâp thuộc tinh CommandType là CommandType.StoredProcedure;

- Thiết lâp các Parameter (nếu có) cho procedure

- Thực thi phương thưc ExecuteNonQuery.

Thủ tuc dưới đây cho phép các mâu tin lây vê tư bang SinhVien được phân thành tưng nhóm các trang, mỗi trang 10 record. Đâu vào của của procedure là @pTrang (số hiệu

Bai tập thưc hanh Chuyên đề Visual Studio .NET 81

Page 82: Giao trinh visual studio[bookbooming.com]

trang cân lây); đâu ra của procedure là số trang tổng cộng của tâp dư liệu. Đoạn code minh họa phia dưới thực hiện việc thiết lâp để lây vê trang dư liệu đâu tiên.

SqlCommand cmd = new SqlCommand();

cmd.CommandText = "spListSinhVien"; // tên procedure

cmd.CommandType = CommandType.StoredProcedure;

cmd.Parameters.Add(“@pTrang", SqlDbType.Int);

cmd.Parameters.Add(“@pTongSoTrang", SqlDbType.Int);

cmd.Parameters[0].Direction= ParameterDirection.Input;cmd.Parameters[0].Value= 1; // thiết lâp để lây vê trang đâu tiên

cmd.Parameters[1].Direction=ParameterDirection.Output;

cmd.CommandTimeout=10; // Cho command tối đa 10s để thực thi

SqlDataReader dr = cmd.ExecuteReader();

while (dr.Read()){ // xử lý tâp dư liệu ở đây}

dr.Close(); // DataReader phai được đóng trước khi đọc tham số đâu ra

int tongSoTrang = cmd.Parameters[1].Value;

Vi du này sử dung data provider SqlClient. Có thể chỉnh sửa một phân nho thi nó cũng có thể hoạt động với OleDb. Điểm khác biệt mâu chốt giưa SqlClient và OleDb đó là cách quan lý các parameter. SqlClient yêu câu tên parameter phai đúng với tên parameter của stored procedure; trong khi đó OleDb lại truyên các parameter cho stored procedure dựa vào vị tri, vi vây tên parameter là không quan trọng. Nếu procedure tra vê giá trị kết qua, OleDb phai thiết kế để parameter đâu tiên trong danh sách làm nhiệm vu này. Với SqlClient, chúng ta chỉ cân thêm một parameter với một tên nào đó và xác định hướng tra vê (direction) của parameter này là Return Value.

Phân code của stored procedure là như sau:

CREATE PROCEDURE spListSinhVien @pTrang int, @pTongSoTrang int output

Bai tập thưc hanh Chuyên đề Visual Studio .NET 82

Page 83: Giao trinh visual studio[bookbooming.com]

AS

/*Thủ tuc tra vê một tâp kết qua gồm các SinhVien xếp theo HoTen.Tâp kết qua được phân thành các trang, mỗi trang 10 SinhVien.

*/

SET NOCOUNT ON

SELECT @pSoTrang = CEILING(COUNT(*)/10) FROM SinhVien

if @pTrang = 1 or @pTrang <1 begin SELECT TOP MaSinhVien, HoTen FROM SinhVien ORDER BY HoTen set @pTrang = 1 return 0 end

if @pTrang > @pTongSoTrang begin SET @pTrang = @pTongSoTrang declare @RowCount int

set @RowCount = (@pTrang * 10)

exec ('SELECT * FROM (

SELECT TOP 10 a.* FROM (

SELECT TOP ' + @RowCount + ' * FROM SinhVien ORDER BY HoTen

) a ORDER BY HoTen desc

) b ORDER BY HoTen'

)

return 0 end

Bai tập thưc hanh Chuyên đề Visual Studio .NET 83

Page 84: Giao trinh visual studio[bookbooming.com]

3.3.2.4 Sử dụng Parameter trong cac Command không phai la Stored ProceduresTrong các query được thành lâp trực tiếp (chư không phai là stored procedure như ở trên), chúng ta cũng có thể sử dung các Parameter. Vi du dưới đây minh họa cách thưc bổ sung một record vào bang SinhVien:

string sql = "INSERT INTO SinhVien (MaSinhVien, HoTen) VALUES (@pMaSinhVien,

@pHoTen)";

SqlCommand cmd = new SqlCommand();cmd.Connection = conn;cmd.commandText = sql;cmd.Parameters.AddWithValue("@pMaSinhVien", 12);cmd.Parameters.AddWithValue("@pHoTen", "tnv spider");

Một cách khác để thực hiện việc bổ sung record như trên là sử dung phép nối chuỗi4

như thế này:

int iMaSinhVien = 12;string stHoTen = "tnv spider";

sql = string.Format(“INSERT INTO SinhVien (MaSinhVien, HoTen) VALUES ({0}, ‘{1}’)”,

iMaSinhVien, stHoTen);

SqlCommand cmd = new SqlCommand(sql, conn);

3.3.3 Đối tượng DataReaderNhư đã thây trong các vi du trước, một DataReader cho phép lây các dòng và cột dư liệu của dư liệu tra vê khi thực thi một query. Việc truy xuât dòng được định nghĩa bởi interface IDataRecord. Dưới đây là các member quan trọng của interface này.

3.3.3.1 Truy xuất cac dòng dữ liệu với DataReaderDataReader lây vê tưng dòng đơn (single row) tư một tâp dư liệu tra vê mỗi khi phương thưc Read của nó được thực thi. Nếu không có dòng dư liệu nào thi phương thưc này tra vê giá trị false. DataReader phai được đóng sau khi các thao tác xử lý các dòng được hoàn tât để giai phóng tài nguyên hệ thống. Bạn có thể sử dung thuộc tinh DataReader.IsClosed để biết được DataReader đã được đóng hay chưa.

4 Trong thực tế, giai pháp nối chuỗi it khi được sử dung vi lý do an toàn dư liệu. Hãy hinh dung trong đoạn code này, nếu stHoTen được gán giá trị là “tnv spider’); DELETE * FROM SinhVien;--”. Khi đó query được thực thi sẽ là “INSERT INTO SinhVien (MaSinhVien, HoTen) VALUES (12, ‘tnv spider’); DELETE * FROM SinhVien;--)” Lỗ hổng kiểu này thương được gọi với tên SQL Injection.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 84

Page 85: Giao trinh visual studio[bookbooming.com]

Măc dù DataReader là ưng với một Command đơn, nhưng Command này lại có thể chưa nhiêu query trong đó, do đó có thể tra vê nhiêu tâp dư liệu kết qua. Đoạn code dưới đây minh họa cách xử lý các dòng dư liệu tra vê bởi 2 query trong một Command.

string q1 = "SELECT * FROM SinhVien WHERE YEAR(NgaySinh) < 1981";

string q2 = "SELECT * FROM SinhVien WHERE YEAR(NgaySinh) > 1990";

cmd.CommandText = q1 + ";" + q2; // hai query được ngăn cách nhau bởi dâu ;

DbDataReader rdr = cmd.ExecuteReader();

bool readNext = true;

while (readNext){ while (rdr.Read()) MessageBox.Show(rdr.GetString(1));

readNext = rdr.NextResult(); // kiem tra xem con tap du lieu nao nua khong}

rdr.Close();

conn.Close();

DataReader không có thuộc tinh hay phương thưc nào cho biết số lượng dòng dư liệu tra vê trong tâp dư liệu của nó (do đăc tinh forward-only của DataReader), tuy nhiên, chúng ta có thể sử dung thuộc tinh HasRows (kiểu Boolean) của DataReader để xác định xem nó có 1 hay nhiêu dòng để đọc hay không.

3.3.3.2 Truy xuất gia trị của columnCó nhiêu cách để truy xuât dư liệu chưa trong các columns của dòng hiện tại của DataReader:

- Truy xuât như là một array dùng số thư tự column (bắt đâu tư 0) hoăc dùng tên column

- Sử dung phương thưc GetValue bằng cách truyên cho phương thưc này số thư tự của column

- Sử dung một trong các phương thưc định kiểu GetXXX, bao gồm GetString, GetInt32, GetDateTime, GetDouble, …

Đoạn code dưới đây minh họa các thưc truy xuât giá trị dư liệu của các column.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 85

Page 86: Giao trinh visual studio[bookbooming.com]

cmd.CommandText = "SELECT MaSinhVien, Hoten, GioiTinh, NgaySinh FROM SinhVien ” +“WHERE YEAR(NgaySinh) = 1981";

dr = cmd.ExecuteReader();

dr.Read();

// Các cách để lây dư liệu kiểu string ở cột thư 2 (HoTen) string stHoTen;

stHoTen = dr.GetString(1);

stHoTen = (string)dr.GetSqlString(1); // SqlClient provider

stHoTen = (string)dr.GetValue(1);

stHoTen = (string)dr["HoTen"];

stHoTen = (string)dr[1];

// Lây dư liệu kiểu DateTime ở cột thư 4 (NgaySinh) có kiểm tra giá trị NULLif (!dr.IsDbNull(3))

DateTime dtNgaySinh = dr.GetDateTime(3);

Phương thưc GetString có điểm thuân lợi trong việc ánh xạ nội dung dư liệu tư CSDL sang kiểu dư liệu của .NET. Các cách tiếp cân khác đêu tra vê các kiểu đối tượng có yêu câu phép chuyển kiểu. Vi lý do này, bạn nên sử dung các phương thưc GetXXX cho các kiểu dư liệu xác định. Cũng lưu ý rằng, phương thưc GetString không yêu câu phép chuyển kiểu, nhưng ban thân nó không thực hiện bât cư phép chuyển đổi nào; chinh vi thế, nếu dư liệu là không đúng như kiểu dư liệu trông đợi sẽ có Exception được tra ra.

Nhiêu ưng dung phu thuộc vào tâng xử lý dư liệu để cung câp DataReader. Với nhưng trương hợp như thế, ưng dung có thể sử dung metadata (siêu dư liệu) để xác định tên column, kiểu dư liệu của column, và các thông tin khác vê column. Đoạn code sau đây minh họa việc in ra danh sách các tên và kiểu dư liệu của các column mà đối tượng DataReader đang quan lý:

// In ra danh sách các tên column của một đối tượng DataReader có tên dr

for (int i = 0; i < dr.FieldCount; i++) Console.WriteLine(“Column {0} co kieu du lieu {1}”,

dr.GetName(i), dr.GetDataTypeName(i)); // Column name

Bai tập thưc hanh Chuyên đề Visual Studio .NET 86

Page 87: Giao trinh visual studio[bookbooming.com]

Có một cách khác toàn diện hơn để quan lý toàn bộ thông tin vê lược đồ (schema) của tâp dư liệu kết qua tra vê, đó là sử dung phương thưc GetSchemaTable. Phương thưc này tra vê một đối tượng DataTable mà mỗi dòng trong DataTable này sẽ biểu diễn một column trong tâp dư liệu kết qua. Đoạn code dưới đây minh họa cách truy xuât tât ca các thông tin vê các column của một tâp dư liệu tra vê.

DataTable schemaTable = dr.GetSchemaTable();

int stt = 0;

foreach (DataRow r in schemaTable.Rows){ foreach (DataColumn c in schemaTable.Columns) { Console.WriteLine(stt.ToString() + " " + c.ColumnName + ": " + r[c]); stt++; }}

Kết qua hiển thị: 0 ColumnName: movie_ID 1 ColumnOrdinal: 0 … //không liệt kê 12 DataType: System.Int32 … //không liệt kê

3.3.4 Ví duGia sử ta đã có cơ sở dư liệu quanlythuvien trong SQL Server có quan hệ như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 87

Page 88: Giao trinh visual studio[bookbooming.com]

Ví dụ về đối tượng Connection, Command và DataReader

Thiết kế Form để tạo mới 1 tài khoan như sau (làm việc trên bang nhanvien):

Frmtaomoitk sử dung các trương, phương thưc và sự kiện sau:

Các điêu khiển

Tên điều khiển Thuộc tính

Bai tập thưc hanh Chuyên đề Visual Studio .NET 88

ListView1

Page 89: Giao trinh visual studio[bookbooming.com]

Form Name: FrmtaomoitkText:Tạo mới một tài khoan sử dung chương trinh

listView Name:listView1Columns: Add thêm 4 cột: Họ tên, Địa chỉ, Tên đăng nhâp và Quyên hạnView: DetailsGridLines:True

groupBox Name:groupBox1Text: Thông tin cơ ban

Label Tạo ra 5 label để hiển thị: Mã nhân viên, Họ tên, Địa chỉ, Tên đăng nhâp và quyên hạn.

TextBox Tạo ra 4 TextBox lân lượt với các tên: txtmanv, txthoten, txtdiachi, txttendangnhap

Button Tạo 8 button lân lượt với các tên butdau, butlui, buttien, butcuoi, buttaomoi, buttimkiem, butxoabo,butthoat

Cac trường:

Tên trường Ý nghĩa

Cn Dùng để kết nối đến cơ sở dư liệu quanlythuvien

cmdSelect sqlCommand sử dung câu lệnh select để hiển thị và tim kiếm

cmdInsert sqlCommand sử dung câu lệnh Insert để tạo thêm 1 tài khoan

cmdXoa sqlCommand sử dung câu lệnh Delete để xóa 1 tài khoan

I Tài khoan thư i

Cac phương thưc+ Hàm dựng Frmtaomoitk để tạo giao diệnpublic Frmtaomoitk() { InitializeComponent(); }+ Phương thưc Moketnoi(): Kiểm tra đương kết nối, nếu đang mở thi đóng lại, sau đó mở lại đương kết nối

private void Moketnoi() { if (cn.State == ConnectionState.Open) cn.Close(); cn.Open(); }

+ Phương thưc LoadListView: Lây dư liệu của bang nhanvien nạp dư liệu lên listView1. Phương thưc này được gọi khi thay đổi dư liệu trong bang nhân viên như nhâp thêm hoăc xóa đi 1 nhân viên. Sử dung 2 đối tượng SqlCommand, SqlDataReader

Bai tập thưc hanh Chuyên đề Visual Studio .NET 89

Page 90: Giao trinh visual studio[bookbooming.com]

private void LoadListView() { Moketnoi(); cmdSelect = new SqlCommand("select * from nhanvien", cn); SqlDataReader r = cmdSelect.ExecuteReader(); listView1.Items.Clear(); // Xóa tât ca dư liệu trong listView1 while (r.Read()) { string[] st = new string[5]; st[0] = r[0].ToString(); st[1] = r[1].ToString(); st[2] = r[2].ToString();// Không hiển thị mât khẩu, nên không có r[3] st[3] = r[4].ToString(); st[4] = r[5].ToString(); ListViewItem lv = new ListViewItem(st); listView1.Items.Add(lv); } cmdSelect.Dispose(); }+ Phương thưc LoadItem: Lây dư liệu tư dòng thư i của listView1 đưa vào txtmanv, txthoten, txtdiachi, txttendangnhap và comboBox1. Phương thưc này được gọi khi di chuyển qua lại thông tin của các nhân viên.

private void LoadItem(int i) { txtmanv.Text = listView1.Items[i].Text; txthoten.Text = listView1.Items[i].SubItems[1].Text; txtdiachi.Text = listView1.Items[i].SubItems[2].Text; txttendangnhap.Text = listView1.Items[i].SubItems[3].Text; comboBox1.Text = listView1.Items[i].SubItems[4].Text; }+ Phương thưc LoadCombox: Đưa dư liệu vào cho comboBox1. Gia sử chỉ có 3 quyên hạn: admin, sinhvien và Thuthu. Phương thưc này được gọi khi vưa nạp Form lên

private void LoadCombox() { comboBox1.Items.Add("Admin"); comboBox1.Items.Add("Sinhvien"); comboBox1.Items.Add("ThuThu"); comboBox1.Text = "Admin"; }

Bai tập thưc hanh Chuyên đề Visual Studio .NET 90

Page 91: Giao trinh visual studio[bookbooming.com]

+ Phương thưc XoaTextBox: Xóa hết dư liệu trong các textBox, phương thưc này được goi khi nhâp thêm 1 tài khoan.

private void XoaTextBox() { txtmanv.Clear(); txthoten.Clear(); txtdiachi.Clear(); txttendangnhap.Clear(); txtmanv.Focus(); }+ Phương thưc KiemTraMa: Kiểm tra xem có mã nhân viên nào bằng với ma hay không. Phương thưc này được gọi khi nhâp thêm 1 tài khoan

private int KiemTraMa(string ma) { Moketnoi(); cmdSelect = new SqlCommand("select count(*) from nhanvien where manhanvien='"+ma.Trim()+"'"); cmdSelect.Connection = cn; return (int)cmdSelect.ExecuteScalar(); }+ Sự kiện Frmtaomoitk_Load: Tạo và mở ra đương kết nối đến cơ sở dư liệu quanlythuvien, tên máy chủ nhha, sử dung cơ chế xác thực kiểu Windows, nạo dư liệu vào cho các điêu khiển.

private void Frmtaomoitk_Load(object sender, EventArgs e) { try { cn = new SqlConnection("Data Source=nhha;Initial Catalog=quanlythuvien; Trusted_Connection=yes"); cn.Open(); } catch (Exception loi) { MessageBox.Show("Không thể kết nối được"); } LoadListView(); //Nạp dư liệu vào cho listView1 i = 0; LoadItem(i);// Nạp dư liệu vào cho các textBox và comboBox1 LoadCombox(); }+ Sự kiện butdau_Click: Nạp dư liệu của dòng đâu tiên tư listView1 vào cho các textBox và comboBox

Bai tập thưc hanh Chuyên đề Visual Studio .NET 91

Page 92: Giao trinh visual studio[bookbooming.com]

private void butdau_Click(object sender, EventArgs e) { i = 0; LoadItem(i); }+ Sự kiện buttien_Click: Nạp dư liệu của dòng tiếp theo tư listView1 vào cho các textBox và comboBox

private void buttien_Click(object sender, EventArgs e) { i++; if (i == listView1.Items.Count) i = listView1.Items.Count - 1; LoadItem(i); }+ Sự kiện butlui_Click:

private void butlui_Click(object sender, EventArgs e) { i--; if (i < 0) i = 0; LoadItem(i); }+ Sự kiện butcuoi_Click:

private void butcuoi_Click(object sender, EventArgs e) { i = listView1.Items.Count - 1; LoadItem(i); }+ Sự kiện butTaomoi_Click: Được sử dung để thêm 1 tài khoan (1 nhân viên), nút butTaomoi có 2 trạng thái tạo mới và lưu. Nếu ngươi sử dung kich vào nút Tạo mới sẽ chuyển sang trạng thái là lưu và ngược lại.

private void butTaomoi_Click(object sender, EventArgs e) { if (butTaomoi.Text.Equals("Tạo mới")) { XoaTextBox(); butTaomoi.Text = "Luu"; } else

// Kiểm tra xem mã nhân viên nay co hay chưa ? if (KiemTraMa(txtmanv.Text)==1) {

Bai tập thưc hanh Chuyên đề Visual Studio .NET 92

Page 93: Giao trinh visual studio[bookbooming.com]

MessageBox.Show("Mã này đã có"); txtmanv.Clear(); txtmanv.Focus(); } else { string ma = txtmanv.Text; string hoten = txthoten.Text; string diachi = txtdiachi.Text; string tendangnhap = txttendangnhap.Text; string matkhau = "";// Khi tạo 1 tài khoan thi mât khẩu ban đâu là rỗng string quyenhan = comboBox1.Text; Moketnoi(); string sql="insert into nhanvien values("+"'"+ma+"','"+hoten+"','"+diachi +"','" +tendangnhap+"','"+matkhau+"','"+quyenhan +"')"; cmdInsert = new SqlCommand(sql,cn); cmdInsert.ExecuteNonQuery(); MessageBox.Show("Đã lưu thành công"); LoadListView(); //Nạp lại dư liệu mới vào listView1 butTaomoi.Text = "Tạo mới"; cmdInsert.Dispose(); } }+ Sự kiện buttimkiem_Click: Khi ngươi sử dung gõ 1 mã nhân viên vào txtmanv và kich vào nút buttimkiem, nếu tim thây mã nhân viên này sẽ hiển thị kết qua lên các textBox và comboBox

private void buttimkiem_Click(object sender, EventArgs e) { Moketnoi(); string sql = "select * from nhanvien where manhanvien='" + txtmanv.Text + "'"; cmdSelect = new SqlCommand(sql,cn); SqlDataReader dr = cmdSelect.ExecuteReader(); if (dr.Read())// Đã tim thây { txtmanv.Text = dr[0].ToString(); txthoten.Text = dr[1].ToString(); txtdiachi.Text = dr[2].ToString(); txttendangnhap.Text = dr[4].ToString(); comboBox1.Text = dr[5].ToString(); } else

Bai tập thưc hanh Chuyên đề Visual Studio .NET 93

Page 94: Giao trinh visual studio[bookbooming.com]

MessageBox.Show("Không tim thây"); }+ Sự kiện butXoabo_Click: Xóa nhân viên có mã nhân viên ở txtmanv

private void butXoabo_Click(object sender, EventArgs e) { DialogResult dr = MessageBox.Show("Chắc chắn xóa hay không ?", "Thông báo", MessageBoxButtons.YesNo); if (dr == DialogResult.Yes) // Nếu ngươi sử dung chọn nút yes { Moketnoi(); string Sql = "delete from nhanvien where manhanvien='" + txtmanv.Text + "'"; cmdXoa = new SqlCommand(Sql,cn); if (cmdXoa.ExecuteNonQuery() == 1) { MessageBox.Show("Xóa thành công"); LoadListView(); LoadItem(0); } else MessageBox.Show("Không tồn tại mã nhân viên " + txtmanv.Text); cmdXoa.Dispose(); } }

3.5 Lam viêc vơi mô hinh Ngắt kết nối: DataSet va DataTableMô hinh Ngắt Kết nối của ADO.NET dựa trên cơ sở sử dung đối tượng DataSet như là một vùng nhớ đệm. Một đối tượng DataAdapter làm nhiệm vu trung gian giưa DataSet và data source (nguồn dư liệu) để nạp dư liệu vào vùng nhớ đệm. Sau khi DataAdapter hoàn thành nhiệm vu nạp dư liệu, nó sẽ tra đối tượng Connection vê pool, vi thế nó ngắt kết nối khoi nguồn dư liệu.

3.4.1 Lơp DataSetDataSet đóng vai trò của một CSDL in-memory (CSDL nằm trong bộ nhớ). Thuộc tinh Tables của DataSet là một tâp hợp các DataTable chưa dư liệu và lược đồ dư liệu (data schema) mô ta dư liệu trong DataTable. Thuộc tinh Relations chưa tâp hợp các đối tượng DataRelation xác định cách thưc liên kết các đối tượng DataTable của DataSet. Lớp DataSet cũng hỗ trợ việc sao chép, trộn, và xóa DataSet thông qua các phương thưc tương ưng là Copy, Merge, và Clear.

DataSet và DataTable là phân lõi của ADO.NET và chúng không là đăc trưng của một data provider nào (giống như ở các lớp Connection, DataReader,

Bai tập thưc hanh Chuyên đề Visual Studio .NET 94

Page 95: Giao trinh visual studio[bookbooming.com]

DataAdapter). Một ưng dung có thể định nghĩa và nạp dư liệu tư nguồn bât kỳ (chư không nhât thiết là tư một CSDL) vào DataSet.

Bên cạnh các DataTable và các DataRelation, một DataSet còn có thể chưa các thông tin tùy biến khác được định nghĩa bởi ưng dung. Hinh dưới đây mô ta ca lớp chinh trong DataSet. Trong số các thuộc tinh này, chú ý thuộc tinh PropertyCollection; đó là các thuộc tinh được lưu trư dưới dạng một hash table (bang băm), thương chưa một giá trị time stamp hay các thông tin đăc ta như các yêu câu hợp lệ hóa (validation requirements) cho column trong các DataTable trong DataSet.

3.4.1.1 DataTableThuộc tinh DataSet.Tables chưa các đối tượng DataTable. Mỗi đối tượng trong tâp hợp này có thể được truy xuât bằng chỉ số hoăc bằng tên.

Các DataTable trong tâp hợp DataSet.DataTables mô phong các Table trong CSDL quan hệ (các row, column, …). Các thuộc tinh quan trọng nhât của lớp DataTable là Columns và Rows định nghĩa câu trúc và nội dung bang dư liệu.

3.4.1.2 DataColumnThuộc tinh DataTable.Columns chưa một tâp các đối tượng DataColumn biểu diễn các trương dư liệu trong DataTable. Bang dưới đây tóm tắt các thuộc tinh quan trọng của lớp DataColumn.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 95

Page 96: Giao trinh visual studio[bookbooming.com]

Phương thưc Mô ta

ColumnName Tên column

DataType Kiểu của dư liệu chưa trong column nàyVi du: col1.DataType = System.Type.GetType("System.String")

MaxLength Độ dài tối đa của một text column. -1 nếu không xác định độ dài tối đa

ReadOnly Cho biết giá trị của column có được chỉnh sửa hay không

AllowDBNull Giá trị Boolean cho biết column này có được chưa giá trị NULL hay không

Unique Giá trị Boolean cho biết column này có được chưa các giá trị trùng nhau hay không

Expression Biểu thưc định nghĩa cách tinh giá trị của một columnVi du: colTax.Expression = "colSales * .085";

Caption Tiêu đê hiển thị trong thành phân điêu khiển giao diện đồ họa

DataTable Tên của đối tượng DataTable chưa column này

Các column của DataTable được tạo ra một cách tự động khi table được nạp dư liệu tư kết qua của một database query hoăc tư kết qua đọc được ở một file XML. Tuy nhiên, chúng ta cũng có thể viết code để tạo động các column. Đoạn code dưới đây sẽ tạo ra một đối tượng DataTable, sau đó tạo thêm các đối tượng DataColumn, gán giá trị cho các thuộc tinh của column, và bổ sung các DataColumn này vào DataTable.

DataTable tb = new DataTable("DonHang");

DataColumn dCol = new DataColumn("MaSo", Type.GetType("System.Int16"));dCol.Unique = true; // Dư liệu của các dòng ở column này không được trùng nhaudCol.AllowDBNull = false;tb.Columns.Add(dCol);

dCol = new DataColumn("DonGia", Type.GetType("System.Decimal"));tb.Columns.Add(dCol);

dCol = new DataColumn("SoLuong",Type.GetType("System.Int16"));tb.Columns.Add(dCol);

Bai tập thưc hanh Chuyên đề Visual Studio .NET 96

Page 97: Giao trinh visual studio[bookbooming.com]

dCol= new DataColumn("ThanhTien",Type.GetType("System.Decimal"));dCol.Expression= "SoLuong*DonGia";tb.Columns.Add(dCol);

// Liệt kê danh sách các Column trong DataTableforeach (DataColumn dc in tb.Columns){ Console.WriteLine(dc.ColumnName); Console.WriteLine(dc.DataType.ToString());}

Để ý rằng column MaSo được định nghĩa để chưa các giá trị duy nhât. Ràng buộc này giúp cho column này có thể được dùng như là trương khóa để thiết lâp relationship kiểu parent-child với một bang khác trong DataSet. Để mô ta, khóa phai là duy nhât – như trong trương hợp này – hoăc được định nghĩa như là một primary key của bang. Vi du dưới đây mô ta cách xác định primary key của bang:

DataColumn[] col = {tb.Columns["MaSo"]};tb.PrimaryKey = col;

Nếu một primary key chưa nhiêu hơn 1 column – chẳng hạn như HoDem và Ten – bạn có thể tạo ra một ràng buộc unique constraint trên các như vi du dưới đây:

DataColumn[] cols = {tb.Columns["HoDem"], tb.Columns["Ten"]};

tb.Constraints.Add(new UniqueConstraint("keyHoVaTen", cols));

Chúng ta sẽ xem xét cách thưc tạo relationship cho các bang và trộn dư liệu ở phân tiếp theo.

3.4.1.3 DataRowsDư liệu được đưa vào table bằng cách tạo mới một đối tượng DataRow, gán giá trị cho các column của nó, sau đó bổ sung đối tượng DataRow này vào tâp hợp Rows gồm các DataRow của table.

DataRow row;row = tb.NewRow(); // Tạo mới DataRowrow["DonGia"] = 22.95;row["SoLuong"] = 2;row["MaSo"] = 12001;

tb.Rows.Add(row); // Bổ sung row vào tâp Rows

Console.WriteLine(tb.Rows[0]["ThanhTien"].ToString()); // 45.90

Bai tập thưc hanh Chuyên đề Visual Studio .NET 97

Page 98: Giao trinh visual studio[bookbooming.com]

Một DataTable có các phương thưc cho phép nó có thể commit hay roll back các thay đổi được tạo ra đối với table tương ưng. Để thực hiện được điêu này, nó phai nắm giư trạng thái của mỗi dòng dư liệu bằng thuộc tinh DataRow.RowState. Thuộc tinh này được thiết lâp bằng một trong 5 giá trị kiểu enumeration DataRowState sau: Added, Deleted, Detached, Modifed, hoăc Unchanged. Xem xét vi du sau:

tb.Rows.Add(row); // Added

tb.AcceptChanges(); // ...Commit changes

Console.Write(row.RowState); // Unchanged

tb.Rows[0].Delete(); // Deleted

// Undo deletiontb.RejectChanges(); // ...Roll back

Console.Write(tb.Rows[0].RowState); // Unchanged

DataRow myRow;

MyRow = tb.NewRow(); // Detached

Hai phương thưc AcceptChanges và RejectChanges của DataTable là tương đương với các thao tác commit và rollback trong một CSDL. Các phương thưc này sẽ câp nhât mọi thay đổi xay ra kể tư khi table được nạp, hoăc tư khi phương thưc AcceptChanges được triệu gọi trước đó. Ở vi du trên, chúng ta có thể khôi phuc lại dòng bị xóa do thao tác xóa là chưa được commit trước khi phương thưc RejectChanges được gọi. Điêu đáng lưu ý nhât đó là, nhưng thay đổi được thực hiện là ở trên table chư không phai là ở data source.

ADO.NET quan lý 2 giá trị - ưng với 2 phiên ban hiện tại và nguyên gốc - cho mỗi column trong một dòng dư liệu. Khi phương thưc RejectChanges được gọi, các giá trị hiện tại sẽ được đăt khôi phuc lại tư giá trị nguyên gốc. Điêu ngược lại được thực hiện khi gọi phương thưc AcceptChanges. Hai tâp giá trị này có thể được truy xuât đồng thơi thông qua các giá trị liệt kê DataRowVersion là: Current và Original:

DataRow r = tb.Rows[0];

r["DonGia"]= 14.95;r.AcceptChanges();

r["DonGia"]= 16.95;

Bai tập thưc hanh Chuyên đề Visual Studio .NET 98

Page 99: Giao trinh visual studio[bookbooming.com]

Console.WriteLine("Current: {0} Original: {1} ", r["Price", DataRowVersion.Current], r["Price", DataRowVersion.Original]);

Kết qua in ra:

Current: 16.95 Original: 14.95

3.4.1.4 DataView.DataView đóng vai trò như tâng hiển thị dư liệu lưu trư trong DataTable. Nó cho phép ngươi sử dung sắp xếp, lọc và tim kiếm dư liệu.

//Gia sử đã có 1 dataset có tên là ds chưa dư liệu của bang DonHang

DataView dv = new DataView(ds.Tables["DonHang”];

// Lọc ra tât ca các hàng có giá tư 10 đến 100

dv.RowFilter = "soluong>=10 and soluong<=100";

//Sắp xếp tăng dân theo số lượng nếu số lượng bằng nhau thi sắp xếp giam dân thêm đơn giá

dv.Sort = "soluong, dongia DESC";

3.4.2 Nạp dư liêu vao DataSetChúng ta đã biết cách thành lâp một DataTable và xử lý dư liệu theo kiểu tưng dòng một. Phân này sẽ trinh bày phương pháp để dư liệu và lược đồ dư liệu được nạp tự động tư CSDL quan hệ vào các table trong DataSet.

3.4.2.1 Dùng DataReader để nạp dữ liệu vao DataSetĐối tượng DataReader có thể được sử dung để liên hợp đối tượng DataSet hay DataTable trong việc nạp các dòng dư liệu kết qua (của query trong DataReader).

cmd.CommandText = "SELECT * FROM nhanvien";

DBDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);

DataTable dt = new DataTable("nhanvien");

dt.Load(rdr); // Nạp dư liệu và lược đồ vào table

Console.WriteLine(rdr.IsClosed); // True

Bai tập thưc hanh Chuyên đề Visual Studio .NET 99

Page 100: Giao trinh visual studio[bookbooming.com]

Đối tượng DataReader được tự động đóng sau khi tât ca các dòng dư liệu được nạp vào table. Do đã sử dung tham số CommandBehavior.CloseConnection trong phương thưc ExecuteReader nên connection được đóng sau khi DataReader được đóng.

Nếu table đã có dư liệu, phương thưc Load sẽ trộn dư liệu mới với các dòng dư liệu đang có trong nó. Việc trộn này xay ra chỉ khi các dòng dư liệu có chung primary key. Nếu không có primary key được định nghĩa, các dòng dư liệu sẽ được nối vào sau tâp dư liệu hiện tại. Chúng ta có thể sử dung phương thưc nạp chồng khác của phương thưc Load để quy định cách thưc làm việc. Phương thưc Load với tham số kiểu enumeration LoadOption gồm 1 trong 3 giá trị OverwriteRow, PreserveCurrentValues, hoăc UpdateCurrentValues tương ưng với tùy chọn ghi đè nguyên dòng, giư lại các giá trị hiện tại, hoăc câp nhât các giá trị hiện tại. Đoạn code dưới đây minh họa cách trộn dư liệu vào các dòng hiện tại theo kiểu ghi đè các giá trị hiện tại:

cmd.CommandText = "SELECT * FROM nhanvien WHERE diachi=’a’";

DBDataReader rdr = cmd.ExecuteReader();DataTable dt = new DataTable("nhanvien");

dt.Load(rdr);

Console.Write(dt.Rows[0]["HoTen"]); // gia sử giá trị nhân được là “tnv spider”

// Gán khóa chinh

DataColumn[] col = new DataColumn[1];col[0] = dt.Columns["Manv"];

dt.PrimaryKey = col;

DataRow r = dt.Rows[0]; // lây dòng đâu tiên

r["HoTen"] = "ten moi"; // thay đổi giá trị của cột HoTen

// Do reader đã bị đóng sau khi nạp vào data table nên phai giơ phai fill lạirdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);

// Trộn dư liệu với các dòng hiện tại. Ghi đè các giá trị hiện tạidt.Load(rdr, LoadOption.UpdateCurrentValues);

// Giá trị câp nhât đã bị ghi đè!!! Console.Write(dt.Rows[0]["HoTen"]); // “tnv spider”

3.4.2.2 Nạp dữ liệu vao DataSet bằng DataAdapterĐối tượng DataAdapter có thể được dùng để nạp một table hiện có vào một table khác, hoăc tạo mới và nạp dư liệu cho table tư kết qua của một query. Bước đâu tiên là tạo ra

Bai tập thưc hanh Chuyên đề Visual Studio .NET 100

Page 101: Giao trinh visual studio[bookbooming.com]

một đối tượng DataAdapter tương ưng với data provider cu thể. Dưới đây là các vi du để tạo ra đối tượng DataAdapter:

(1) Tạo tư Connection string và câu truy vân SELECT:

String sql = "SELECT * FROM nhanvien";SqlDataAdapter da = new SqlDataAdapter(sql, connStr);

(2) Tạo tư đối tượng Connection và câu truy vân SELECT:

SqlConnection conn = new SqlConnection(connStr);SqlDataAdapter da = new SqlDataAdapter(sql, conn);

(3) Gán đối tượng Command cho thuộc tinh SelectCommand

SqlDataAdapter da = new SqlDataAdapter();SqlConnection conn = new SqlConnection(connStr);da.SelectCommand = new SqlCommand(sql, conn);

Sau khi đối tượng DataAdapter đã được tạo ra, phương thưc Fill của nó được thực thi để nạp dư liệu vào table (đang tồn tại hoăc tạo mới). Ở vi du dưới đây, một table mới được tạo ra với tên măc định là “Table”:

DataSet ds = new DataSet();

// Tạo ra một DataTable, nạp dư liệu vào DataTable, và đưa DataTable vào DataSetint nRecs = da.Fill(ds); // tra vê số lượng record được nạp vào DataTable

// Nếu muốn đăt tên cho DataTable trong DataSet thay vi lây tên măc định// thi sử dung code như thế nàyint nRecs = da.Fill(ds, "nhanvien ")

Với một table đang tồn tại, tác dung của lệnh Fill tùy thuộc vào table có primary hay không. Nếu có, nhưng dòng dư liệu có khóa trùng với dòng dư liệu mới sẽ được thay thế. Các dòng dư liệu mới không trùng với dư liệu hiện có sẽ được nối vào sau DataTable.

3.4.3 Ví duVí dụ về DataAdapter và DataSet

Vi du này sử dung cơ sở dư liệu quanlythuvien như trong vi du 3.3.4

Thiết kế form frmtimkiemsach để tim theo tên sách hoăc tên tác gia như sau:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 101

Page 102: Giao trinh visual studio[bookbooming.com]

frmtimkiemsach sử dung các trương, phương thưc và sự kiện sau:

Các điêu khiển

Tên điều khiển Thuộc tínhForm Name: frmtimkiemsach

Text:Tim kiếm theo nhan đê hoăc tên tác giaLabel Text: Nhâp tên sách hoăc tên tác gia cân timTextBox Name: txttimkiemdataGridView Name: dataGridView1statusStrip Name: thanhtrangthai

Items: Add thêm 2 statusLabel: với tên ketquatim và tóngoluongCác trương:

Tên trường Ý nghĩa

Cn Dùng để kết nối đến cơ sở dư liệu quanlythuvien

cmd sqlCommand sử dung câu lệnh select để hiển thị và tim kiếm sách

da SqlDataAdapter chưa cmd và cn

Bai tập thưc hanh Chuyên đề Visual Studio .NET 102

Page 103: Giao trinh visual studio[bookbooming.com]

ds DataSet chưa dư liệu của bang sách hoăc chưa kết qua tim kiếm

Cac phương thưc+ Hàm dựng frmtimkiemsach để tạo giao diệnpublic frmtimkiemsach() { InitializeComponent(); }

+ Phương thưc Tongsoluong: được sử dung để tinh tổng số lượng sách của các sách lưu trong Dataset ds. private int Tongsoluong() { int s=0; foreach (DataRow r in ds.Tables["sach"].Rows) { s += (int)r["soluong"]; } return s; }+ Phương thưc Tongsoluongtk tinh tổng số lượng sách trong DataView dv, dv chưa thông tin các sách tim kiếm được. private int Tongsoluongtk(DataView dv) { int s = 0; foreach (DataRow r in dv.ToTable("sach").Rows ) { s += (int)r["soluong"]; } return s; }+ Sự kiện frmtimkiemsach_Load:Nạp thông tin của 4 quyển sách đâu tiên theo thư tự giam dân của ngaynhap vào DataSet ds với tên bang trong DataSet là sach, sau đó hiển thị thông tin của bang sach trong DataSet vào dataGridView1, đưa tổng số sách và tổng số lượng sách trong DataSet vào thanh trạng thái private void frmtimkiemsach_Load(object sender, EventArgs e) { cn.Open(); // Mở kết nối cmd.CommandText = "select top 4 * from sach order by ngaynhap desc" ; cmd.Connection = cn; da.SelectCommand = cmd; da.Fill(ds, "sach"); // Nạp dư liệu vào DataSet dataGridView1.DataSource = ds.Tables["sach"]; // Nạp dư liệu vào dataGridView1

// Nạp dư liệu vào thanh trạng thái

Bai tập thưc hanh Chuyên đề Visual Studio .NET 103

Page 104: Giao trinh visual studio[bookbooming.com]

thanhtrangthai.Items[0].Text = "Tổng số sách:" + ds.Tables["sach"].Rows.Count.ToString(); thanhtrangthai.Items[1].Text = "Tổng số lượng:" + Tongsoluong().ToString(); }+ Sự kiện txttimkiem_KeyPress: Khi ngươi sử dung nhân Enter trên txttimkiem thi việc tim kiếm tương đối bắt đâu: Tạo ra 1 DataView dv chưa dư liệu của bang sách trong DataSet ds, lọc trong DataView dv ra thông tin của các quyển sách gân giống với dư liệu nhâp trên txttimkiem, sau đó đưa kết qua lọc ra trên dataGridView1 và thanh trạng thái.

private void txttimkiem_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == 13) { DataView dv = new DataView(ds.Tables["sach"]); //Nạp dư liệu vào DataView

//bắt đâu lọc dư liệu dv.RowFilter = "nhande like '%" + txttimkiem.Text + "%' or tacgia like '%" + txttimkiem.Text + "%'"; dataGridView1.DataSource = dv; //Nạp kết qua lọc trong dv vào dataGridView1

// Đưa số quyển sách và tổng số lượng sách lọc được vào thanh trang thái

thanhtrangthai.Items[0].Text = "Số kết qua tim thây được: " + dv.Count.ToString() + "/" + ds.Tables["sach"].Rows.Count.ToString(); thanhtrangthai.Items[1].Text = "Tổng số lượng tim thây được:" +

Tongsoluongtk(dv).ToString() + "/" + Tongsoluong().ToString(); } }

3.4.4 Câp nhât CSDL bằng DataAdapterSau khi DataAdapter đã nạp dư liệu vào table, connection sẽ được đóng, và các thay đổi sau đó đối sau đó tạo ra cho dư liệu sẽ chỉ có anh hưởng trong DataSet chư không phai là ở dư liệu nguồn! Để thực sự câp nhât các thay đổi này lên nguồn dư liệu, DataAdapter phai được sử dung để khôi phuc connection và gửi các dòng dư liệu đã được thay đổi lên CSDL.

Ngoài SelectCommand, DataAdapter có thêm 3 thuộc tinh Command nưa, gồm InsertCommand, DeleteCommand và UpdateCommand, làm nhiệm vu thực hiện các thao tác tương ưng với tên thuộc tinh của chúng (chèn, xóa, câp nhât). Các Command này được thực thi khi phương thưc Update của DataAdapter được triệu gọi. Khó khăn nằm ở chỗ tạo ra các query command phưc tạp này (cú pháp của câu lệnh SQL tương ưng càng dài dòng và phưc tạp khi số lượng column nhiêu lên). Rât may là các data provider đêu có cài đăt một lớp gọi là CommandBuilder dùng để quan lý việc tạo các Command nói trên một cách tự động.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 104

Page 105: Giao trinh visual studio[bookbooming.com]

3.4.4.1 CommandBuilderMột đối tượng CommandBuilder sẽ sinh ra các Command cân thiết để thực hiện việc câp nhât nguồn dư liệu tạo ra bởi DataSet. Cách tạo đối tượng CommandBuilder là truyên đối tượng DataAdapter cho phương thưc khởi dựng của nó; sau đó, khi phương thưc DataAdapter.Update được gọi, các lệnh SQL sẽ được sinh ra và thực thi. Đoạn code dưới đây minh họa cách thưc thay đổi dư liệu ở một DataTable và câp nhât lên CSDL tương ưng bằng DataAdapter:

//Gia sử đã có 1 DataSet ds chưa dư liệu của bang khoa

DataTable dt= ds.Tables["khoa"]; // (1) Dùng commandBuilder để sinh ra các Command cân thiết để updateSqlCommandBuilder sb = new SqlCommandBuilder(da);

// (2) Thực hiện thay đổi dư liệu: thêm 1 khoa mớiDataRow drow = dt.NewRow();drow["Makhoa"] = 12;drow["tenkhoa"] = "abc";dt.Rows.Add(drow);

// (3) Thực hiện thay đổi dư liệu: xóa 1 khoadt.Rows[4].Delete();

// (4) Thực hiện thay đổi dư liệu: thay đổi giá trị 1 dòng dư liệudt.Rows[5]["tenkhoa"] = "this must be changed";

// (5) Tiến hành câp nhât lên CSDLint nUpdate = da.Update(ds, "khoa");

MessageBox.Show("Số dòng được thay đổi: " + nUpdate.ToString()); // 3

Có một số hạn chế khi sử dung CommandBuilder: Command Select ưng với DataAdapter chỉ được tham chiếu đến 1 table, và table nguồn trong CSDL phai bao gồm một primary key hoăc một column chưa các giá trị duy nhât. Column này (hay tổ hợp các columns) phai được bao gồm trong command Select ban đâu.

3.4.4.2 Đồng bộ hoa dữ liệu giữa DataSet va CSDLNhư đã minh họa trong vi du này, việc sử dung DataAdapter làm đơn gian hóa và tự động hóa quá trinh câp nhât CSDL hoăc bât kỳ data source nào. Tuy nhiên, có một vân đê ở đây: multi-user (nhiêu ngươi sử dung). Mô hinh Ngắt kết nối được dựa trên cơ chế Optimistic Concurrency, một cách tiếp cân mà trong đó các dòng dư liệu ở data source không bị khóa (lock) giưa thơi gian mà chúng được đọc và thơi gian mà các câp nhât được áp dung cho data source. Trong khoang thơi gian này, user khác có thể cũng

Bai tập thưc hanh Chuyên đề Visual Studio .NET 105

Page 106: Giao trinh visual studio[bookbooming.com]

câp nhât data source. Nếu có thay đổi xay ra kể tư lân đọc trước đó thi phương thưc Update sẽ nhân biết được và không cho áp dung thay đổi đối với các dòng dư liệu đó.

Có hai phương án cơ ban để giai quyết lỗi concurrency (tương tranh) khi có nhiêu câp nhât được áp dung: roll back tât ca các thay đổi nếu như xuât hiện xung đột (violation), hoăc áp dung các câp nhât không gây ra lỗi và xác định nhưng câp nhât có gây ra lỗi để có thể xử lý lại.

3.4.4.3 Sử dụng Transactions để Roll Back nhiều cập nhậtKhi thuộc tinh DataAdapter.ContinueUpdateOnErrors được thiết lâp là false, một ngoại lệ sẽ được ném ra khi một thay đổi dòng dư liệu không thể thực hiện được. Điêu này sẽ ngăn các câp nhât tiếp theo được thực thi, nhưng lại không anh hưởng đến các câp nhât đã xuât hiện trước ngoại lệ đó. Do nhưng câp nhât có thể có liên quan với nhau, ưng dung thương là cân chiến lược hoặc la tất ca, hoặc la không (all-or-none). Cách dễ nhât để thực thi chiến lược này là tạo ra một transaction trong đó tât ca các command update sẽ được thực thi. Để thực hiện điêu này, tạo ra một đối tượng SqlTransaction và gắn nó với SqlDataAdapter.SelectCommand bằng cách truyên nó cho hàm khởi dựng của nó. Nếu có ngoại lệ xay ra, phương thưc Rollback sẽ được thực thi để undo mọi thay đổi trước đó; nếu không có ngoại lệ nào xuât hiện, phương thưc Commit được thực thi để áp dung tât ca các command update. Dưới đây là một vi du:

SqlDataAdapter da = new SqlDataAdapter();

SqlCommandBuilder sb = new SqlCommandBuilder(da);

SqlTransaction tran;

SqlConnection conn = new SqlConnection(connStr);

conn.Open(); // Connection phai được dùng với Transaction

// (1) Tạo ra một transactionSqlTransaction tran = conn.BeginTransaction();

// (2) Gắn SelectCommand với transactionda.SelectCommand = new SqlCommand(sql, conn, tran);

DataSet ds = new DataSet();

da.Fill(ds, "docgia");

//// Code ở phân này thực hiện các câp nhât lên các dòng dư liệu ở DataSet try

Bai tập thưc hanh Chuyên đề Visual Studio .NET 106

Page 107: Giao trinh visual studio[bookbooming.com]

{ int updates = da.Update(ds, "docgia"); MessageBox.Show("Câp nhât: " + updates.ToString());}// (3) Nếu có ngoại lệ xuât hiện, roll back mọi câp nhât trong transactioncatch (Exception ex){ MessageBox.Show(ex.Message); // Lỗi khi câp nhât if (tran != null) { tran.Rollback(); // Roll back mọi câp nhât tran = null;

MessageBox.Show("Tât ca các câp nhât đã bị roll back."); }}finally{ // (4) Nếu không có lỗi, commit tât ca các câp nhât if (tran != null) { tran.Commit(); MessageBox.Show("Tât ca đã được câp nhât thành công. "); tran = null; }}

conn.Close();

3.4.4.4 Xac định cac dòng gây ra lỗi cập nhậtKhi thuộc tinh DataAdapter.ContinueUpdateOnErrors được thiết lâp là True, các xử lý sẽ không ngưng nếu có một dòng dư liệu không thể câp nhât được. Thay vào đó, DataAdapter sẽ câp nhât tât ca các dòng dư liệu không gây ra lỗi. Sau đó, lâp trinh viên có thể xác định các dòng dư liệu không câp nhât được và quyết định cách xử lý chúng.

Các dòng dư liệu không câp nhât được có thể dễ dàng được xác định qua thuộc tinh DataRowState của chúng (đã được trinh bày trong phân mô ta DataRow). Các dòng dư liệu đã được câp nhât thành công sẽ có trạng thái Unchanged; trong khi đó các dòng dư liệu không câp nhât thành công sẽ mang trạng thái Added, Deleted hoăc

Bai tập thưc hanh Chuyên đề Visual Studio .NET 107

Page 108: Giao trinh visual studio[bookbooming.com]

Modified. Đoạn code dưới đây minh họa cách lăp qua các dòng dư liệu và xác định các dòng chưa được câp nhât.

// SqlDataAdapter da nạp dư liệu của bang docgia da.ContinueUpdateOnError = true;

DataSet ds = new DataSet();try{ da.Fill(ds, "docgia"); DataTable dt = ds.Tables["docgia"];

SqlCommandBuilder sb = new SqlCommandBuilder(da);

// ... Các thao tác câp nhât

dt.Rows[29].Delete(); // Delete

dt.Rows[30]["HoTen"] = "try to change"; // Update

dt.Rows[30][Madocgia] = 1234; // Update

dt.Rows[31]["HoTen"] = "XYZ"; // Update

DataRow drow = dt.NewRow(); drow["HoTen"] = "tnv spider"; drow["Madocgia"] = 25; dt.Rows.Add(drow); // insert

// Submit updates int updates = da.Update(ds, "docgia");

if (ds.HasChanges()) { // Load rows that failed into a DataSet DataSet failures = ds.GetChanges();

int rowsFailed = failures.Rows.Count;

Console.WriteLine("Số dòng không thể câp nhât: " + rowsFailed);

foreach (DataRow r in failures.Tables[0].Rows ) { string state = r.RowState.ToString());

Bai tập thưc hanh Chuyên đề Visual Studio .NET 108

Page 109: Giao trinh visual studio[bookbooming.com]

// Phai hủy bo thay đổi để hiển thị dòng đã bị xóa if (r.RowState == DataRowState.Deleted) r.RejectChanges();

string iMadocgia= ((int)r["Madocgia"]).ToString();

string msg = state + " Madocgia: " + iMadocgia;

Console.WriteLine(msg); } }

Lưu ý rằng ngay ca khi thao tác xóa xuât hiện trước, nó cũng không có tác dung đối với các thao tác khác. Câu lệnh SQL xóa hay câp nhât một dòng dư liệu được dựa theo giá trị của primary key chư không liên quan đến vị tri của nó. Ngoài ra các câp nhât trên cùng một dòng được kết hợp và đếm như là 1 câp nhât cho dòng đó bởi phương thưc Update. Ở vi du trên, các câp nhât cho dòng 30 được tinh như là 1 câp nhât.

3.4.5 Định nghĩa Relationships giưa cac Table trong DataSetMột DataRelation là một mối quan hệ parent-child giưa hai đối tượng DataTables. Nó được định nghĩa dựa trên việc so khớp các columns trong 2 DataTable. Cú pháp hàm khởi dựng là như sau:

public DataRelation( string relationName, DataColumn parentColumn, DataColumn childColumn)

Một DataSet có một thuộc tinh Relations giúp quan lý tâp hợp các DataRelation đã được định nghĩa trong DataSet. Sử dung phương thưc Relations.Add để thêm các DataRelation vào tâp hợp Relations. Vi du dưới đây thiết lâp mối quan hệ giưa hai bang khoa và docgia để có thể liệt kê danh sách các docgia của mỗi khoa.

string connStr="Data Source=tên máy chủ;Initial Catalog=quanlythuvien; Trusted_Connection=yes";

DataSet ds = new DataSet();// (1) Fill bang docgiastring sql = "SELECT * FROM docgia”;SqlConnection conn = new SqlConnection(connStr);SqlCommand cmd = new SqlCommand();SqlDataAdapter da = new SqlDataAdapter(sql, conn);da.Fill(ds, "docgia");// (2) Fill bang khoasql = "SELECT * FROM khoa”;

Bai tập thưc hanh Chuyên đề Visual Studio .NET 109

Page 110: Giao trinh visual studio[bookbooming.com]

da.SelectCommand.CommandText = sql;da.Fill(ds, "khoa");// (3) Định nghĩa relationship giưa 2 bang khoa và docgiaDataTable parent = ds.Tables["khoa"];DataTable child = ds.Tables["docgia"];DataRelation relation = new DataRelation("khoa_docgia", parent.Columns["makhoa"],

child.Columns["makhoa"]);// (4) Đưa relationship vào DataSetds.Relations.Add(relation);// (5) Liệt kê danh sách các đọc gia của tưng khoa foreach (DataRow r in parent.Rows){ Console.WriteLine(r["tenkhoa"]); // Tên khoa foreach (DataRow rc in r.GetChildRows("khoa_docgia")) { Console.WriteLine(" " + rc["HoTen"]); }}/* Vi du kết qua: Khoa Tin Nguyễn Văn Trung Ngô Anh Tuân Lê Thanh Hoa Khoa Toán Nguyễn Thị Hoa Trân Văn Phúc*/Khi một relationship được định nghĩa giưa 2 tables, nó cũng sẽ thêm một ForeignKeyConstraint vào tâp hợp Constraints của DataTable con. Constraint này quyết định cách mà DataTable con bị anh hưởng khi các dòng dư liệu ở phia DataTable cha bị thay đổi hay bị xóa. Trong thực tế, điêu này có nghĩa là khi bạn xóa 1 dòng trong DataTable cha, các dòng con có liên quan cũng bị xóa – hoăc cũng có thể là các key bị đăt lại giá trị thành NULL. Tương tự như thế, nếu một giá trị key bị thay đổi trong DataTable cha, các dòng dư liệu có liên quan trong DataTable con cũng có thể bị thay đổi theo hoăc bị đổi giá trị thành NULL.

Các luât như trên được xác định bởi các thuộc tinh DeleteRule và UpdateRule của constraint. Các luât này được nhân các giá trị liệt kê sau đây:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 110

Page 111: Giao trinh visual studio[bookbooming.com]

- Cascade. Xóa/Câp nhât các dòng dư liệu có liên quan trong DataTable con. Đây là giá trị măc định.

- None. Không làm gi.- SetDefault. Thiết lâp các giá trị khóa trong các dòng dư liệu có liên quan của

DataTable con thành giá trị măc định của column tương ưng.- SetNull. Thiết lâp các giá trị khóa trong các dòng dư liệu có liên quan của

DataTable con thành null.

Xem xét vi du dưới đây:

// (1) Thêm một dòng với khóa mới vào DataTable con DataRow row = child.NewRow();

row["Makhoa"] = 999; // gia sử trong bang khoa không có record nào có Makhoa = 999

child.Rows.Add(row); // Không được do 999 không tồn tại trong DataTable cha

// (2) Xóa một dòng trong DataTable cha row = parent.Rows[0];row.Delete(); // Xóa các dòng trong DataTable con có khóa này

// (3) Tạm thơi vô hiệu hóa constraints và thử thêm dòng mới ds.EnforceConstraints = false;

row["Makhoa"] = 999;child.Rows.Add(row); // Được châp nhân!!!ds.EnforceConstraints = true; // Kich hoạt constraint trở lại

// (4) Thay đổi constraint để đăt các dòng dư liệu thành null nếu DataTable thay đổi ((ForeignKeyConstraint)child.Constraints[0]).DeleteRule = Rule.SetNull;

Lưu ý rằng thuộc tinh EnforeceConstraint được đăt thành false sẽ làm vô hiệu hóa tât ca các constraint – điêu này trong thuât ngư CSDL gọi là bo qua tinh toàn vẹn tham chiếu. Điêu này cho phép một khoa được bổ sung vào thâm chi khi ca column Makhoa không tương ưng với dòng nào trong bang khoa. Nó cũng cho phép một dòng khoa được xóa ngay ca khi có nhiêu dòng tương ưng với nó trong bang docgia.

3.5 Sư dung Data Binding

3.6 Lưa chọn giưa mô hinh Kết nối va mô hinh Ngắt kết nốiDataReader và DataSet đưa ra hai cách tiếp cân khác nhau để xử lý dư liệu. DataReader cho phép truy xuât kiểu forward-only, read-only. Bằng cách xử lý tưng dòng một, cách tiếp cân này giúp tiết kiệm bộ nhớ. DataSet, ngược lại, cho phép truy

Bai tập thưc hanh Chuyên đề Visual Studio .NET 111

Page 112: Giao trinh visual studio[bookbooming.com]

xuât theo kiểu read/write, nhưng lại yêu câu phai có đủ bộ nhớ để quan lý ban sao dư liệu nạp vê tư data source. Như vây, bạn có thể suy ra một số quy tắc chung: Nếu ưng dung không cân tinh năng câp nhât dư liệu và hâu như chỉ hiển thị và chọn lọc dư liệu, DataReader là lựa chọn thich hợp; nếu ưng dung cân câp nhât dư liệu, giai pháp sử dung DataSet nên được xem xét.

Tât nhiên, cũng có một số tinh huống đi ngược lại với các quy tắc chung nói trên. Chẳng hạn, nếu data source chưa một số lượng lớn các record, khi đó DataSet phai yêu câu quá nhiêu tài nguyên bộ nhớ; hoăc nếu dư liệu chỉ yêu câu một vài thao tác câp nhât, thi sự kết hợp giưa DataReader và Command để thực thi câp nhât sẽ có thể có ý nghĩa hơn.

Tóm lại, một DataSet là một lựa chọn tốt khi:

- Dư liệu cân được serialize (tuân tự hóa) và/hoăc gửi đi bằng HTTP.- Các điêu khiển read-only trên Form Win Form được kết buộc (bind) với data

source. - Một điêu khiển Win Form như GridView hay DataView được kết buộc với

một data source có kha năng câp nhât được.- Một ưng dung desktop cân thêm, xóa, sửa các dòng dư liệu.

Trong khi đó, DataReader là lựa chọn cho nhưng trương hợp:

- Cân quan lý một số lượng lớn các record, lớn đến mưc mà bộ nhớ và thơi gian để nạp dư liệu cho DataSet là phi thực tế.

- Dư liệu là read-only và được kết buộc với một điêu khiển loại danh sách (list control) của Win Form hoăc Web Form.

- CSDL là không ổn định và thay đổi thương xuyên.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 112

Page 113: Giao trinh visual studio[bookbooming.com]

3.6 Tạo đối tượng DataSet

Trong vi du trước, tạo ra đối tượng SqlDataAdapter bằng cách gắn trực tiếp chuỗi kết nối và chuỗi truy vân vào nó. Đối tượng Connection và Command sẽ được tạo và tich hợp vào trong đối tượng DataAdapter này. Với cách này, ta sẽ bị hạn chế trong các thao tác liên quan đến cơ sở dư liệu.

SqlDataAdapter DataAdapter = new SqlDataAdapter(commandString, connectionString);

Vi du sau đây sẽ minh họa việc lây vê đối tượng DataSet bằng cách tạo ra các đối tượng Connection và Command một cách riêng biệt, khi ta cân dùng lại chúng hay muốn thực hiện hoàn chỉnh một thao tác thi sẽ thuân lợi hơn.

Đâu tiên ta sẽ khai báo bốn biến thành viên thuộc lớp, như sau:

private System.Data.SqlClient.SqlConnection myConnection;

private System.Data.DataSet myDataSet;

private System.Data.SqlClient.SqlCommand myCommand;

private System.Data.SqlClient.SqlDataAdapter DataAdapter;

Đối tượng Connection sẽ được tạo riêng với chuỗi kết nối:

string connectionString = "server=localhost; uid=sa; pwd=; database=northwind";

myConnection = new System.Data.Sql.SqlConnection(connectionString);

Sau đó ta sẽ mở kết nối: myConnection.Open( );

Ta có thể thực hiện nhiêu giao tác trên cơ sở dư liệu khi kết nối được mở và sau khi dùng xong ta chỉ đơn gian đóng kết nối lại. Tiếp theo ta sẽ tạo ra đối tượng DataSet:

myDataSet = new System.Data.DataSet( );

Và tiếp tuc tạo đối tượng Command, gắn cho nó đối tượng Connection đã mở và chuỗi truy vân dư liệu:

myCommand = new System.Data.SqlClient.SqlCommand( )

myCommand.Connection=myConnection;

myCommand.CommandText = "Select * from Customers";

Cuối cùng ta cân tạo ra đối tượng SqlDataAdapter, gắn đối tượng SqlCommand vưa tạo ở trên cho nó, đồng thơi phai tiến hành ánh xạ bang dư liệu nó nhân được tư câu truy vân của đối tượng Command để tạo sự đồng nhât vê tên các cột khi đẩy bang dư liệu này vào DataSet.

DataAdapter = new System.Data.SqlClient.SqlDataAdapter( );

Bai tập thưc hanh Chuyên đề Visual Studio .NET 113

Page 114: Giao trinh visual studio[bookbooming.com]

DataAdapter.SelectCommand= myCommand;

DataAdapter.TableMappings.Add("Table","Customers");

DataAdapter.Fill(myDataSet);

Bây giơ ta chỉ việc gắn DataSet vào thuộc tinh DataSoucre của điêu khiển lưới:

dataGrid1.DataSource=myDataSet.Tables["Customers"].DefaultView;

Dưới đây là mã hoàn chỉnh của ưng dung này:

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Data.SqlClient;

namespace ProgrammingCSharpWindows.Form

{

public class ADOForm1: System.Windows.Forms.Form

{

private System.ComponentModel.Container components;

private System.Windows.Forms.DataGrid dataGrid1;

private System.Data.SqlClient.SqlConnection myConnection;

private System.Data.DataSet myDataSet;

private System.Data.SqlClient.SqlCommand myCommand;

private System.Data.SqlClient.SqlDataAdapter DataAdapter;

public ADOForm1( )

{

InitializeComponent( );

// tạo đối tượng connection và mở nó

string connectionString =

"server=Neptune; uid=sa; pwd=oWenmEany;" +

"database=northwind";

Bai tập thưc hanh Chuyên đề Visual Studio .NET 114

Page 115: Giao trinh visual studio[bookbooming.com]

myConnection = new SqlConnection(connectionString);

myConnection.Open();

// tạo đối tượng DataSet mới

myDataSet = new DataSet( );

// tạo đối tượng command mới và gắn cho đối tượng

// connectio và chuỗi truy vân cho nó

myCommand = new System.Data.SqlClient.SqlCommand( );

myCommand.Connection=myConnection;

myCommand.CommandText = "Select * from Customers";

// tạo đối tượng DataAdapter với đối tượng Command vưa

// tạo ở trên, đồng thơi thực hiện ánh xạ bang dư liệu

DataAdapter = new SqlDataAdapter( );

DataAdapter.SelectCommand= myCommand;

DataAdapter.TableMappings.Add("Table","Customers");

// đẩy dư liệu vào DataSet

DataAdapter.Fill(myDataSet);

// gắn dư liệu vào lưới

dataGrid1.DataSource =

myDataSet.Tables["Customers"].DefaultView;

}

public override void Dispose()

{

base.Dispose();

components.Dispose();

}

private void InitializeComponent( )

{

this.components = new System.ComponentModel.Container();

this.dataGrid1 = new System.Windows.Forms.DataGrid();

dataGrid1.BeginInit();

Bai tập thưc hanh Chuyên đề Visual Studio .NET 115

Page 116: Giao trinh visual studio[bookbooming.com]

dataGrid1.Location = new System.Drawing.Point(24, 32);

dataGrid1.Size = new System.Drawing.Size(480, 408);

dataGrid1.DataMember = "";

dataGrid1.TabIndex = 0;

this.Text = "ADOFrm1";

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.ClientSize = new System.Drawing.Size(536, 501);

this.Controls.Add(this.dataGrid1);

dataGrid1.EndInit( );

}

public static void Main(string[] args)

{

Application.Run(new ADOForm1());

}

}

}

Giao diện của vi du này cũng tương tự như các vi du trên.

3.7 Kết hợp giưa nhiều bang

Các vi du ở trên chỉ đơn thuân lây dư liệu tư trong một bang. Ở vi du này ta sẽ tim hiểu vê cách lây dư liệu trên hai bang. Trong cơ sở dư liệu của ta, một khách hàng có thể có nhiêu hóa đơn khác nhau, vi thế ta sẽ có quan hệ một nhiêu giưa bang khách hàng (Customers)và bang hóa đơn (Orders). Bang Orders sẽ chưa thuộc tinh CustomersId của bang Customers, thuộc tinh này đóng vai trò là khóa chinh đối bang Customers và khóa ngoại đối với bang Orders.

Ứng dung của ta sẽ hiển thị dư liệu của hai bang Customers và Orders trên cùng một lưới và thể hiện quan hệ một nhiêu của hai bang ngay trên lưới. Để làm được điêu này ta chỉ cân dùng chung một đối tượng Connetion, hai đối tượng tượng SqlDataAdapter và hai đối tượng SqlCommand.

Sau khi tạo đối tượng SqlDataAdapter cho bang Customers tương tự như vi du trên, ta tiến tạo tiếp đối tượng SqlDataAdapter cho bang Orders:

myCommand2 = new System.Data.SqlClient.SqlCommand();

DataAdapter2 = new System.Data.SqlClient.SqlDataAdapter();

myCommand2.Connection = myConnection;

Bai tập thưc hanh Chuyên đề Visual Studio .NET 116

Page 117: Giao trinh visual studio[bookbooming.com]

myCommand2.CommandText = "SELECT * FROM Orders";

Lưu ý là ở đây đối tượng DataAdapter2 có thể dùng chung đối tượng Connection ở trên, nhưng đối tượng Command thi khác. Sau đó gắn đối tượng Command2 cho DataAdapter2, ánh xạ bang dư liệu và đẩy dư liệu vào DataSet ở trên.

DataAdapter2.SelectCommand = myCommand2;

DataAdapter2.TableMappings.Add ("Table", "Orders");

DataAdapter2.Fill(myDataSet);

Tại thơi điểm này, ta có một đối tượng DataSet nhưng chưa hai bang dư liệu: Customers và Orders. Do ta cân thể hiện ca quan hệ của hai bang ngay trên điêu khiển lưới, cho nên ta cân phai định nghĩa quan hệ này cho đối tượng DataSet của chúng ta. Nếu không làm điêu này thi đối tượng DataSet sẽ bo qua quan hệ giưa 2 bang này.

Do đó ta cân khai báo thêm đối tương DataRelation:

System.Data.DataRelation dataRelation;

Do mỗi bang Customers và Orders đêu có chưa một thuộc tinh CustomersId, nên ta cũng cân khái báo thêm hai đối tượng DataColumn tương ưng với hai thuộc tinh này.

System.Data.DataColumn dataColumn1;

System.Data.DataColumn dataColumn2;

Mỗi một DataColumn sẽ giư giá trị của một cột trong bang của đối tượng DataSet:

dataColumn1 = myDataSet.Tables["Customers"].Columns["CustomerID"];

dataColumn2 = myDataSet.Tables["Orders"].Columns["CustomerID"];

Ta tiến hành tạo quan hệ cho hai bang bằng cách gọi hàm khởi tạo của đối tượng DataRelation, truyên vào cho nó tên quan hệ và hai cột cân tạo quan hệ:

dataRelation = new System.Data.DataRelation("CustomersToOrders",

dataColumn1, dataColumn2);

Sau khi tạo được đối tượng DataRelation, ta thêm vào DataSet của ta. Sau đó ta cân tạo một đối tượng quan lý khung nhin DataViewManager cho DataSet, đối tượng khung nhin này sẽ được gán cho lưới điêu khiển để hiển thị:

myDataSet.Relations.Add(dataRelation);

DataViewManager DataSetView = myDataSet.DefaultViewManager;

dataGrid1.DataSource = DataSetView;

Do điêu khiển lưới phai hiển thị quan hệ của hai bang dư liệu, nên ta phai chỉ cho nó biết là bang nào sẽ là bang cha. Ở đây bang cha là bang Customers:

dataGrid1.DataMember= "Customers";

Bai tập thưc hanh Chuyên đề Visual Studio .NET 117

Page 118: Giao trinh visual studio[bookbooming.com]

Sau đây là mã hoàn chỉnh của toàn bộ ưng dung:

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Data.SqlClient;

namespace ProgrammingCSharpWindows.Form

{

public class ADOForm1: System.Windows.Forms.Form

{

private System.ComponentModel.Container components;

private System.Windows.Forms.DataGrid dataGrid1;

private System.Data.SqlClient.SqlConnection myConnection;

private System.Data.DataSet myDataSet;

private System.Data.SqlClient.SqlCommand myCommand;

private System.Data.SqlClient.SqlCommand myCommand2;

private System.Data.SqlClient.SqlDataAdapter DataAdapter;

private System.Data.SqlClient.SqlDataAdapter DataAdapter2;

public ADOForm1( )

{

InitializeComponent( );

// tạo kết nối

string connectionString = "server=Neptune; uid=sa;" +

" pwd=oWenmEany; database=northwind";

myConnection = new SqlConnection(connectionString);

myConnection.Open( );

// tạo DataSet

myDataSet = new System.Data.DataSet( );

Bai tập thưc hanh Chuyên đề Visual Studio .NET 118

Page 119: Giao trinh visual studio[bookbooming.com]

// tạo đối tượng Command và DataSet cho bang Customers

myCommand = new System.Data.SqlClient.SqlCommand( );

myCommand.Connection=myConnection;

myCommand.CommandText = "Select * from Customers";

DataAdapter =new System.Data.SqlClient.SqlDataAdapter();

DataAdapter.SelectCommand= myCommand;

DataAdapter.TableMappings.Add("Table","Customers");

DataAdapter.Fill(myDataSet);

// tạo đối tượng Command và DataSet cho bang Orders

myCommand2 = new System.Data.SqlClient.SqlCommand( );

DataAdapter2=new System.Data.SqlClient.SqlDataAdapter();

myCommand2.Connection = myConnection;

myCommand2.CommandText = "SELECT * FROM Orders";

DataAdapter2.SelectCommand = myCommand2;

DataAdapter2.TableMappings.Add ("Table", "Orders");

DataAdapter2.Fill(myDataSet);

// thiết lâp quan hệ giưa 2 bang

System.Data.DataRelation dataRelation;

System.Data.DataColumn dataColumn1;

System.Data.DataColumn dataColumn2;

dataColumn1 =

myDataSet.Tables["Customers"].Columns["CustomerID"];

dataColumn2 =

myDataSet.Tables["Orders"].Columns["CustomerID"];

dataRelation = new System.Data.DataRelation(

"CustomersToOrders", dataColumn1, dataColumn2);

// thêm quan hệ trên vào DataSet

myDataSet.Relations.Add(dataRelation);

// Đăt khung nhin và bang hiển thị trước cho lưới

DataViewManager DataSetView =

Bai tập thưc hanh Chuyên đề Visual Studio .NET 119

Page 120: Giao trinh visual studio[bookbooming.com]

myDataSet.DefaultViewManager;

dataGrid1.DataSource = DataSetView;

dataGrid1.DataMember= "Customers";

}

public override void Dispose( )

{

base.Dispose( );

components.Dispose( );

}

private void InitializeComponent( )

{

this.components = new System.ComponentModel.Container();

this.dataGrid1 = new System.Windows.Forms.DataGrid();

dataGrid1.BeginInit( );

dataGrid1.Location = new System.Drawing.Point(24, 32);

dataGrid1.Size = new System.Drawing.Size(480, 408);

dataGrid1.DataMember = "";

dataGrid1.TabIndex = 0;

this.Text = "ADOFrm1";

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.ClientSize = new System.Drawing.Size (536, 501);

this.Controls.Add (this.dataGrid1);

dataGrid1.EndInit ( );

}

public static void Main(string[] args)

{

Application.Run(new ADOForm1( ));

}

}

}

Bai tập thưc hanh Chuyên đề Visual Studio .NET 120

Page 121: Giao trinh visual studio[bookbooming.com]

3.8 Thay đổi cac ban ghi của cơ sở dư liêu

Tới lúc này, chúng ta đã học cách lây dư liệu tư cơ sở dư liệu sau đó hiển thị chúng ra màn hinh dựa vào các điêu khiển có hay không kết buộc dư liệu. Phân này chúng ta sẽ tim hiểu cách câp nhât vào cơ sở dư liệu. Các thao tác trên cơ sở dư liệu như: Thêm, xóa và sửa một dòng trong các bang dư liệu. Sau đây là luồng công việc hoàn chỉnh khi ta có một thao tác câp nhât cơ sở dư liệu:

1. Đẩy dư liệu của bang vào DataSet bằng câu truy vân SQL hay gọi thủ tuc tư cơ sở dư liệu

2. Hiển thị dư liệu trong các bang có trong DataSet bằng cách kết buộc hay duyệt qua các dòng dư liệu.

3. Hiệu chỉnh dư liệu trong các bang DataTable với các thao tác thêm, xóa hay sửa trên dòng DataRow.

4. Gọi phương thúc GetChanges() để lây vê một DataSet khác chưa tât ca các thay đổi trên dư liệu.

5. Kiểm tra lỗi trên DataSet mới được tạo này bằng thuộc tinh HasErrors. Nếu có lỗi thi ta sẽ tiến hành kiểm tra trên tưng bang DataTable của DataSet, khi găp một bang có lỗi thi ta tiếp tuc dùng hàm GetErrors()để lây vê các dòng DataRow có lỗi, ưng với tưng dòng ta sẽ dùng thuộc tinh RowError trên dòng để xác định xem dòng đó có lỗi hay không để có thể đưa ra xử lý thich hợp.

6. Trộn hai DataSet lại thành một.

7. Gọi phương thưc Update() của đối tượng DataAdapter với đối số truyên vào là DataSet vưa có trong thao tác trộn ở trên để câp nhât các thay đổi vào cơ sở dư liệu.

8. Gọi phương thưc AcceptChanges() của DataSet để câp nhât các thay đổi vào DataSet này hay phương thưc RejectChanges() nếu tư chối câp nhât thay đổi cho DataSet hiện hành.

Với luồng công việc trên, cho phép ta có thể kiểm soát tốt được việc thay đổi trên cơ sở dư liệu hay việc gỡ lỗi cũng thuân tiện hơn. Trong vi du dưới đây , ta sẽ cho hiện thị dư liệu trong bang Customers lên một ListBox, sau đó ta tiến hành các thao tác thêm, xóa hay sửa trên cơ sở dư liệu. Để dễ hiểu, ta giam bớt một số thao tác quan lý ngoại lệ hay lỗi, chỉ tâp trung vào muc đich chinh của ta. Giao diện chinh của ưng dung sau khi hoàn chỉnh:

Trong Form này, ta có một ListBox lbCustomers liệt kê các khách hàng, một Button btnUpdate cho việc câp nhât dư liệu, một Button Xóa, ưng với nút thêm mới ta có tám hộp thoại TextBox để nhân dư liệu gõ vào tư ngươi dùng. Đồng thơi ta có thêm một lblMessage để hiển thị các thông báo ưng với các thao tác trên.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 121

Page 122: Giao trinh visual studio[bookbooming.com]

3.9 Truy câp va hiển thị dư liêu

Ta sẽ tạo ra ba biến thành viên: DataAdapter, DataSet và Command:

private SqlDataAdapter DataAdapter;

private DataSet DataSet;

private DataTable dataTable;

Việc khai báo các biến thành viên như vây sẽ giúp ta có thể dùng lại cho các phương thưc khác nhau. Ta khai báo chuỗi kết nối và truy vân:

string connectionString =

"server=localhost; uid=sa; pwd=; database=northwind";

string commandString = "Select * from Customers";

Các chuỗi được dùng làm đối số để tạo đối tượng DataAdapter:

DataAdapter=new SqlDataAdapter(commandString,ConnectionString);

Tạo ra đối tượng DataSet mới, sau đó đẩy dư liệu tư DataAdapter vào cho nó:

DataSet = new DataSet();

DataAdapter.Fill(DataSet,"Customers");

Để hiển thị dư liệu, ta sẽ gọi hàm PopulateDB()để đẩy dư liệu vào ListBox:

dataTable = DataSet.Tables[0];

lbCustomers.Items.Clear( );

foreach (DataRow dataRow in dataTable.Rows)

{

lbCustomers.Items.Add(dataRow["CompanyName"] + " (" + dataRow["ContactName"] + ")" );

}

3.10 Câp nhât một dòng dư liêu

Khi ngươi dùng nhân Button Update (câp nhât), ta sẽ lây chỉ muc được chọn trên ListBox, và lây ra dòng dư liệu DataRow trong bang ưng với chỉ muc trên. Sau đó câp nhât DataSet với dòng dư liệu mới này nếu sau khi kiểm tra thây chúng không có lỗi nào ca. Chi tiết vê quá trinh thực hiện câp nhât:

Đâu tiên ta sẽ lây vê dòng dư liệu ngươi dùng muốn thay đổi tư đối tượng dataTable mà ta đã khai báo làm biến thành viên ngay tư đâu:

DataRow targetRow = dataTable.Rows[lbCustomers.SelectedIndex];

Bai tập thưc hanh Chuyên đề Visual Studio .NET 122

Page 123: Giao trinh visual studio[bookbooming.com]

Hiển thị chuỗi thông báo câp nhât dòng dư liệu đó cho ngươi dùng biết. Để làm điêu này ta sẽ gọi phương thưc tinh DoEvents() của đối tượng Application, hàm này sẽ giúp sơn mới lại màn hinh với thông điệp hay các thay đổi khác.

lblMessage.Text = "Updating " + targetRow["CompanyName"];

Application.DoEvents();

Gọi hàm BeginEdit() của đối tượng DataRow, để chuyển dòng dư liệu sang chế độ hiệu chỉnh ( Edit ) và EndEdit()để kết thúc chế độ hiệu chỉnh dòng.

targetRow.BeginEdit();

targetRow["CompanyName"] = txtCustomerName.Text;

targetRow.EndEdit();

Lây vê các thay đổi trên đối tượng DataSet để kiểm tra xem các thay đổi có xay ra bât kỳ lỗi nào không. Ở đây ta sẽ dùng một biến cơ có kiểu true/false để xác định là có lỗi là true, không có lỗi là false.Kiểm tra lỗi bằng cách dùng hai vòng lăp tuân tự trên bang và dòng của DataSet mới lây vê ở trên, ta dùng thuộc tinh

HasErrors để kiểm tra lỗi trên bang, phương thưc GetErrors()để lây vê các dòng có lỗi trong bang.

DataSet DataSetChanged;

DataSetChanged = DataSet.GetChanges(DataRowState.Modified);

bool okayFlag = true;

if (DataSetChanged.HasErrors)

{

okayFlag = false;

string msg = "Error in row with customer ID ";

foreach (DataTable theTable in DataSetChanged.Tables)

{

if (theTable.HasErrors)

{

DataRow[] errorRows = theTable.GetErrors( );

foreach (DataRow theRow in errorRows)

msg = msg + theRow["CustomerID"];

}

}

Bai tập thưc hanh Chuyên đề Visual Studio .NET 123

Page 124: Giao trinh visual studio[bookbooming.com]

lblMessage.Text = msg;

}

Nếu biến cơ okagFlag là true,thi ta sẽ trộn DataSet ban đâu với DataSet thay đổi thành một, sau đó câp nhât DataSet sau khi trộn này vào cơ sở dư liệu.

if (okayFlag)

{

DataSet.Merge(DataSetChanged);

DataAdapter.Update(DataSet,"Customers");

Tiếp theo hiển thị câu lệnh truy vân cho ngươi dùng biết, và câp nhât nhưng thay đổi cho DataSet đâu tiên, rồi hiển thị dư liệu mới lên đối tượng ListBox.

lblMessage.Text = DataAdapter.UpdateCommand.CommandText;

Application.DoEvents( );

DataSet.AcceptChanges( );

PopulateLB( );

Nếu cơ okayFlag là false, có nghĩa là có lỗi trong quá trinh hiệu chỉnh dư liệu, ta sẽ tư chối các thay đổi trên DataSet.

else

DataSet.RejectChanges( );

3.11 Xóa một dòng dư liêu

Mã thực thi của sự kiện xóa thi đơn gian hơn một chút, ta nhân vê dòng cân xóa:

DataRow targetRow = dataTable.Rows[lbCustomers.SelectedIndex];

Giư lại dòng cân xóa để dùng làm thông điệp hiển thị cho ngươi dùng biết trước khi xóa dòng này khoi cơ sở dư liệu.

string msg = targetRow["CompanyName"] + " deleted. ";,

Bắt đâu thực hiện xóa trên bang dư liệu, câp nhât thay đổi vào DataSet và câp nhât luôn vào cơ sở dư liệu:

dataTable.Rows[lbCustomers.SelectedIndex].Delete( );

DataSet.AcceptChanges( );

DataAdapter.Update(DataSet,"Customers");

Khi gọi hàm AccceptChanges()để câp nhât thay đổi cho DataSet thi nó sẽ lân lượt gọi hàm này cho các DataTable, sau đó cho các DataRow để câp nhât chúng. Ta cũng cân

Bai tập thưc hanh Chuyên đề Visual Studio .NET 124

Page 125: Giao trinh visual studio[bookbooming.com]

chú ý khi gọi hàm xóa trên bang Customers, dòng dư liệu DataRow của khách hàng này chỉ được xóa nếu nó không vi phạm ràng buộc trên các bang khác,

ở đây khách hàng chỉ được xóa nếu nếu khách hàng không có một hóa đơn nào trên bang Orders. Nếu có ta phai tiến hành xóa trên bang hóa đơn trước, sau đó mới xóa trên bang Customers.

3.12 Tạo một dòng dư liêu mơi

Sau khi ngươi dùng cung câp các thông tin vê khách hàng cân tạo mới và nhân Button tạo mới ( New ), ta sẽ viết mã thực thi trong hàm bắt sự kiện nhân nút tạo mới này. Đâu tiên ta sẽ tạo ra một dòng mới trên đối tượng DataTable, sau đó gán dư liệu trên các TextBox cho các cột của dòng mới này:

DataRow newRow = dataTable.NewRow( );

newRow["CustomerID"] = txtCompanyID.Text;

newRow["CompanyName"] = txtCompanyName.Text;

newRow["ContactName"] = txtContactName.Text;

newRow["ContactTitle"] = txtContactTitle.Text;

newRow["Address"] = txtAddress.Text;

newRow["City"] = txtCity.Text;

newRow["PostalCode"] = txtZip.Text;

newRow["Phone"] = txtPhone.Text;

Thêm dòng mới với dư liệu vào bang DataTable, câp nhât vào cơ sở dư liệu, hiển thị câu truy vân, câp nhât DataSet, hiển thị dư liệu mới lên hộp ListBox. Làm trắng các điêu khiển TextBox bằng hàm thành viên ClearFields().

dataTable.Rows.Add(newRow);

DataAdapter.Update(DataSet,"Customers");

lblMessage.Text = DataAdapter.UpdateCommand.CommandText;

Application.DoEvents( );

DataSet.AcceptChanges( );

PopulateLB( );

ClearFields( );

Để hiểu rõ hoàn chỉnh ưng, ta sẽ xem mã hoàn chỉnh của toàn ưng dung:

using System;

using System.Drawing;

Bai tập thưc hanh Chuyên đề Visual Studio .NET 125

Page 126: Giao trinh visual studio[bookbooming.com]

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Data.SqlClient;

namespace ProgrammingCSharpWindows.Form

{

public class ADOForm1: System.Windows.Forms.Form

{

private System.ComponentModel.Container components;

private System.Windows.Forms.Label label9;

private System.Windows.Forms.TextBox txtPhone;

private System.Windows.Forms.Label label8;

private System.Windows.Forms.TextBox txtContactTitle;

private System.Windows.Forms.Label label7;

private System.Windows.Forms.TextBox txtZip;

private System.Windows.Forms.Label label6;

private System.Windows.Forms.TextBox txtCity;

private System.Windows.Forms.Label label5;

private System.Windows.Forms.TextBox txtAddress;

private System.Windows.Forms.Label label4;

private System.Windows.Forms.TextBox txtContactName;

private System.Windows.Forms.Label label3;

private System.Windows.Forms.TextBox txtCompanyName;

private System.Windows.Forms.Label label2;

private System.Windows.Forms.TextBox txtCompanyID;

private System.Windows.Forms.Label label1;

private System.Windows.Forms.Button btnNew;

private System.Windows.Forms.TextBox txtCustomerName;

private System.Windows.Forms.Button btnUpdate;

Bai tập thưc hanh Chuyên đề Visual Studio .NET 126

Page 127: Giao trinh visual studio[bookbooming.com]

private System.Windows.Forms.Label lblMessage;

private System.Windows.Forms.Button btnDelete;

private System.Windows.Forms.ListBox lbCustomers;

private SqlDataAdapter DataAdapter;

// biết thành viên DataSet và dataTable cho phép ta sử

// dung trên nhiêu hàm khác nhau

private DataSet DataSet;

private DataTable dataTable;

public ADOForm1( )

{

InitializeComponent( );

string connectionString = "server=Neptune; uid=sa;" +

" pwd=oWenmEany; database=northwind";

string commandString = "Select * from Customers";

DataAdapter =

new SqlDataAdapter(commandString, connectionString);

DataSet = new DataSet( );

DataAdapter.Fill(DataSet,"Customers");

PopulateLB( );

}

// Đẩy dư liệu vào điêu khiển ListBox

private void PopulateLB( )

{

dataTable = DataSet.Tables[0];

lbCustomers.Items.Clear( );

foreach (DataRow dataRow in dataTable.Rows)

{

lbCustomers.Items.Add( dataRow["CompanyName"] + " (" +

dataRow["ContactName"] + ")" );

}

Bai tập thưc hanh Chuyên đề Visual Studio .NET 127

Page 128: Giao trinh visual studio[bookbooming.com]

}

public override void Dispose( )

{

base.Dispose( );

components.Dispose( );

}

private void InitializeComponent( )

{

this.components = new System.ComponentModel.Container();

this.txtCustomerName=new System.Windows.Forms.TextBox();

this.txtCity = new System.Windows.Forms.TextBox();

this.txtCompanyID = new System.Windows.Forms.TextBox();

this.lblMessage = new System.Windows.Forms.Label();

this.btnUpdate = new System.Windows.Forms.Button();

this.txtContactName= new System.Windows.Forms.TextBox();

this.txtZip = new System.Windows.Forms.TextBox();

this.btnDelete = new System.Windows.Forms.Button();

this.txtContactTitle=new System.Windows.Forms.TextBox();

this.txtAddress = new System.Windows.Forms.TextBox();

this.txtCompanyName=new System.Windows.Forms.TextBox( );

this.label5 = new System.Windows.Forms.Label( );

this.label6 = new System.Windows.Forms.Label( );

this.label7 = new System.Windows.Forms.Label( );

this.label8 = new System.Windows.Forms.Label( );

this.label9 = new System.Windows.Forms.Label( );

this.label4 = new System.Windows.Forms.Label( );

this.lbCustomers = new System.Windows.Forms.ListBox( );

this.txtPhone = new System.Windows.Forms.TextBox( );

this.btnNew = new System.Windows.Forms.Button( );

this.label1 = new System.Windows.Forms.Label( );

Bai tập thưc hanh Chuyên đề Visual Studio .NET 128

Page 129: Giao trinh visual studio[bookbooming.com]

this.label2 = new System.Windows.Forms.Label( );

this.label3 = new System.Windows.Forms.Label( );

txtCustomerName.Location =

new System.Drawing.Point(256, 120);

txtCustomerName.TabIndex = 4;

txtCustomerName.Size = new System.Drawing.Size(160, 20);

txtCity.Location = new System.Drawing.Point(384, 245);

txtCity.TabIndex = 15;

txtCity.Size = new System.Drawing.Size (160, 20);

txtCompanyID.Location =

new System.Drawing.Point (136, 216);

txtCompanyID.TabIndex = 7;

txtCompanyID.Size = new System.Drawing.Size (160, 20);

lblMessage.Location = new System.Drawing.Point(32, 368);

lblMessage.Text = "Press New, Update or Delete";

lblMessage.Size = new System.Drawing.Size (416, 48);

lblMessage.TabIndex = 1;

btnUpdate.Location = new System.Drawing.Point (32, 120);

btnUpdate.Size = new System.Drawing.Size (75, 23);

btnUpdate.TabIndex = 0;

btnUpdate.Text = "Update";

btnUpdate.Click +=

new System.EventHandler (this.btnUpdate_Click);

txtContactName.Location =

new System.Drawing.Point(136, 274);

txtContactName.TabIndex = 11;

txtContactName.Size = new System.Drawing.Size (160, 20);

txtZip.Location = new System.Drawing.Point (384, 274);

txtZip.TabIndex = 17;

txtZip.Size = new System.Drawing.Size (160, 20);

Bai tập thưc hanh Chuyên đề Visual Studio .NET 129

Page 130: Giao trinh visual studio[bookbooming.com]

btnDelete.Location = new System.Drawing.Point(472, 120);

btnDelete.Size = new System.Drawing.Size(75, 23);

btnDelete.TabIndex = 2;

btnDelete.Text = "Delete";

btnDelete.Click +=

new System.EventHandler (this.btnDelete_Click);

txtContactTitle.Location =

new System.Drawing.Point(136, 303);

txtContactTitle.TabIndex = 19;

txtContactTitle.Size = new System.Drawing.Size(160, 20);

txtAddress.Location = new System.Drawing.Point(384, 216);

txtAddress.TabIndex = 13;

txtAddress.Size = new System.Drawing.Size (160, 20);

txtCompanyName.Location= new System.Drawing.Point (136, 245);

txtCompanyName.TabIndex = 9;

txtCompanyName.Size = new System.Drawing.Size (160, 20);

label5.Location = new System.Drawing.Point (320, 252);

label5.Text = "City";

label5.Size = new System.Drawing.Size (48, 16);

label5.TabIndex = 14;

label6.Location = new System.Drawing.Point (320, 284);

label6.Text = "Zip";

label6.Size = new System.Drawing.Size (40, 16);

label6.TabIndex = 16;

label7.Location = new System.Drawing.Point (40, 312);

label7.Text = "Contact Title";

label7.Size = new System.Drawing.Size (88, 16);

label7.TabIndex = 18;

label8.Location = new System.Drawing.Point (320, 312);

label8.Text = "Phone";

Bai tập thưc hanh Chuyên đề Visual Studio .NET 130

Page 131: Giao trinh visual studio[bookbooming.com]

label8.Size = new System.Drawing.Size (56, 16);

label8.TabIndex = 20;

label9.Location = new System.Drawing.Point (120, 120);

label9.Text = "New Customer Name:";

label9.Size = new System.Drawing.Size (120, 24);

label9.TabIndex = 22;

label4.Location = new System.Drawing.Point (320, 224);

label4.Text = "Address";

label4.Size = new System.Drawing.Size (56, 16);

label4.TabIndex = 12;

lbCustomers.Location = new System.Drawing.Point(32, 16);

lbCustomers.Size = new System.Drawing.Size (512, 95);

lbCustomers.TabIndex = 3;

txtPhone.Location = new System.Drawing.Point (384, 303);

txtPhone.TabIndex = 21;

txtPhone.Size = new System.Drawing.Size (160, 20);

btnNew.Location = new System.Drawing.Point (472, 336);

btnNew.Size = new System.Drawing.Size (75, 23);

btnNew.TabIndex = 5;

btnNew.Text = "New";

btnNew.Click += new System.EventHandler(this.btnNew_Click);

label1.Location = new System.Drawing.Point (40, 224);

label1.Text = "Company ID";

label1.Size = new System.Drawing.Size (88, 16);

label1.TabIndex = 6;

label2.Location = new System.Drawing.Point (40, 252);

label2.Text = "Company Name";

label2.Size = new System.Drawing.Size (88, 16);

label2.TabIndex = 8;

label3.Location = new System.Drawing.Point (40, 284);

Bai tập thưc hanh Chuyên đề Visual Studio .NET 131

Page 132: Giao trinh visual studio[bookbooming.com]

label3.Text = "Contact Name";

label3.Size = new System.Drawing.Size (88, 16);

label3.TabIndex = 10;

this.Text = "Customers Update Form";

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.ClientSize = new System.Drawing.Size (584, 421);

this.Controls.Add (this.label9);

this.Controls.Add (this.txtPhone);

this.Controls.Add (this.label8);

this.Controls.Add (this.txtContactTitle);

this.Controls.Add (this.label7);

this.Controls.Add (this.txtZip);

this.Controls.Add (this.label6);

this.Controls.Add (this.txtCity);

this.Controls.Add (this.label5);

this.Controls.Add (this.txtAddress);

this.Controls.Add (this.label4);

this.Controls.Add (this.txtContactName);

this.Controls.Add (this.label3);

this.Controls.Add (this.txtCompanyName);

this.Controls.Add (this.label2);

this.Controls.Add (this.txtCompanyID);

this.Controls.Add (this.label1);

this.Controls.Add (this.btnNew);

this.Controls.Add (this.txtCustomerName);

this.Controls.Add (this.btnUpdate);

this.Controls.Add (this.lblMessage);

this.Controls.Add (this.btnDelete);

this.Controls.Add (this.lbCustomers);

}

Bai tập thưc hanh Chuyên đề Visual Studio .NET 132

Page 133: Giao trinh visual studio[bookbooming.com]

// Quan lý sự kiện nhân nút tạo mới (New)

protected void btnNew_Click( object sender, System.EventArgs e)

{

// tạo một dòng mới

DataRow newRow = dataTable.NewRow( );

newRow["CustomerID"] = txtCompanyID.Text;

newRow["CompanyName"] = txtCompanyName.Text;

newRow["ContactName"] = txtContactName.Text;

newRow["ContactTitle"] = txtContactTitle.Text;

newRow["Address"] = txtAddress.Text;

newRow["City"] = txtCity.Text;

newRow["PostalCode"] = txtZip.Text;

newRow["Phone"] = txtPhone.Text;

// thêm một dòng mới vào bang

dataTable.Rows.Add(newRow);

// câp nhât vào cơ sở dư liệu

DataAdapter.Update(DataSet,"Customers");

// thông báo cho ngươi dùng biết câu truy vân thay đổi

lblMessage.Text = DataAdapter.UpdateCommand.CommandText;

Application.DoEvents( );

DataSet.AcceptChanges( );

// hiển thị lại dư liệu cho điêu khiển ListBox

PopulateLB( );

// Xoá trằng các TextBox

ClearFields( );

}

// Xóa trắng các TextBox

private void ClearFields( )

{

txtCompanyID.Text = "";

Bai tập thưc hanh Chuyên đề Visual Studio .NET 133

Page 134: Giao trinh visual studio[bookbooming.com]

txtCompanyName.Text = "";

txtContactName.Text = "";

txtContactTitle.Text = "";

txtAddress.Text = "";

txtCity.Text = "";

txtZip.Text = "";

txtPhone.Text = "";

}

// quan lý sự kiện nhât nút chọn câp nhât (Update)

protected void btnUpdate_Click( object sender, EventArgs e)

{

// lây vể dòng được chọn trên ListBox

DataRow targetRow =

dataTable.Rows[lbCustomers.SelectedIndex];

// thông báo cho ngươi biết dòng câp nhât

lblMessage.Text = "Updating " + targetRow["CompanyName"];

Application.DoEvents( );

// hiệu chỉnh dòng

targetRow.BeginEdit( );

targetRow["CompanyName"] = txtCustomerName.Text;

targetRow.EndEdit( );

// lây vê___ các dòng thay đổi

DataSet DataSetChanged =

DataSet.GetChanges(DataRowState.Modified);

// đam bao không có dòng nào có lỗi

bool okayFlag = true;

if (DataSetChanged.HasErrors)

{

okayFlag = false;

string msg = "Error in row with customer ID ";

Bai tập thưc hanh Chuyên đề Visual Studio .NET 134

Page 135: Giao trinh visual studio[bookbooming.com]

// kiểm tra lỗi trên tưng bang

foreach (DataTable theTable in DataSetChanged.Tables)

{

// nếu bang có lỗi thi tim lỗi trên dòng cu thể

if (theTable.HasErrors)

{

// lây các dòng có lỗi

DataRow[] errorRows = theTable.GetErrors( );

// duyệt qua tưng dòng có lỗi để thống báo.

foreach (DataRow theRow in errorRows)

{

msg = msg + theRow["CustomerID"];

}

}

}

lblMessage.Text = msg;

}

// nếu không có lỗi

if (okayFlag)

{

// trộn các thay đổi trong 2 DataSet thành một

DataSet.Merge(DataSetChanged);

// câp nhât cơ sở dư liệu

DataAdapter.Update(DataSet,"Customers");

// thông báo câu truy vân cho ngươi dùng

lblMessage.Text = DataAdapter.UpdateCommand.CommandText;

Application.DoEvents( );

// câp nhât DataSet và

// hiển thị dư liệu mới cho ListBox

DataSet.AcceptChanges( );

Bai tập thưc hanh Chuyên đề Visual Studio .NET 135

Page 136: Giao trinh visual studio[bookbooming.com]

PopulateLB( );

}

else // nếu có lỗi

DataSet.RejectChanges( );

}

// quan lý sự kiện xóa

protected void btnDelete_Click( object sender, EventArgs e)

{

// lây vê___ dòng được chọn trên ListBox

DataRow targetRow =

dataTable.Rows[lbCustomers.SelectedIndex];

// chuẩn bị thông báo cho ngươi dùng

string msg = targetRow["CompanyName"] + " deleted. ";

// xóa dòng được chọn

dataTable.Rows[lbCustomers.SelectedIndex].Delete( );

// câp nhât thay đổi cho DataSet

DataSet.AcceptChanges( );

// câp nhât cơ sở dư liệu

DataAdapter.Update(DataSet,"Customers");

// hiển thị lại ListBox với dư liệu thay đổi

PopulateLB( );

// thông báo cho ngươi dùng biết

lblMessage.Text = msg;

Application.DoEvents( );

}

public static void Main(string[] args)

{

Application.Run(new ADOForm1( ));

}

}

Bai tập thưc hanh Chuyên đề Visual Studio .NET 136

Page 137: Giao trinh visual studio[bookbooming.com]

}

PPHÂHÂ NN 4 4

XXÂYÂY DƯDƯ NGNG ƯƯ NGNG DUDU NGNG W WEBEB VƠVƠ II W WEBEBFFORMSORMS

Công nghệ .NET được dùng để xây dựng các ưng dung Web là ASP.NET, nó cung câp hai vùng tên khá mạnh và đây đủ phuc vu cho việc tạo các ưng dung Web là System.Web và System.Web.UI. Trong phân này chúng ta sẽ tâp trung chủ yếu vào việc dùng ngôn ngư C# để lâp trinh với ASP.NET.

Bộ công cu Web Form cũng được thiết kế để hỗ trợ mô hinh phát triển nhanh (RAD). Với Web Form, ta có thể kéo tha các điêu khiển trên Form thiết kế cũng như có thể viết mã trực tiếp trong tâp tin .aspx hay .aspx.cs. Ứng dung Web sẽ được triển khai trên máy chủ, còn ngươi dùng sẽ tương tác với ưng dung thông qua trinh duyệt. .NET còn hỗ trợ ta bộ cung cu để tạo ra các ưng dung tuân theo mô hinh n - lớp (tâng - n tier), giúp ta có thể quan lý được ưng dung được dễ dàng hơn và nhơ thế nâng cao hiệu suât phát triển phân mêm.

4.1 Tim hiểu về Web Forms

Web Form là bộ công cu cho phép thực thi các ưng dung mà các trang Web do nó tạo động ra được phân phối đến trinh duyệt thông qua mạng Internet. Với Web Forms, ta tạo ra các trang HTML với nội dung tĩnh và dùng mã C# chạy trên Server để xử lý dư liệu tĩnh này rồi tạo ra trang Web động, gửi trang này vê trinh duyệt dưới mã HTML chuẩn. Web Forms được thiết để chạy trên bât kỳ trinh duyệt nào, trang HTML gửi vê sẽ được gọt giũa sao cho thich hợp với phiên ban của trinh duyệt. Ngoài dùng C#, ta cũng có thể dùng ngôn ngư VB.NET để tạo ra các ưng dung Web tương tự. Web Forms chia giao diện ngươi dùng thành hai phân: phân thây trực quan ( hay UI ) và phân trang mã phia sau của UI. Quan điểm này thi tương tự với Windows Form, nhưng với Web Forms, hai phân này nằm trên hai tâp tin riêng biệt. Phân giao diện UI được lưu trư trong tâp tin có phân mở rộng là .aspx, còn mã được lưu trư trong tâp tin có phân mở rộng là .aspx.cs. Với môi trương làm việc được cung câp bởi bộ Visual Studio .NET, tạo các ưng dung Web đơn gian chỉ là mở Form mới, kéo tha và viết ma quan lý sự kiện thich hợp. Web Forms được tich hợp thêm một loạt các điêu khiển thực thi trên Server, có thể tự kiểm tra sự hợp lệ của dư liệu ngay trên máy khách mà ta không phai viết mã mô ta gi cà.

4.2 Cac sư kiên của Web Forms

Một sự kiện (Events) được tạo ra khi ngươi dùng nhân chọn một Button, chọn một muc trong ListBox hay thực hiện một thao tác nào đó trên UI. Các sự kiện cũng có thể được phát sinh hệ thống bắt đâu hay kết thúc. Phương thưc đáp ưng sự kiện gọi là trinh quan lý sự kiện, các trinh quan lý sự kiện này được viết bằng mã C# trong trang mã (code-behind) và kết hợp với các thuộc tinh của các điêu khiển thuộc trang.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 137

Page 138: Giao trinh visual studio[bookbooming.com]

Trinh quan lý sự kiện là một “Delegate”, phương thưc này sẽ tra vê kiểu void, và có hai đối số. Đối số đâu tiên là thể hiện của đối tượng phát sinh ra sự kiện, đối số thư hai là đối tượng EventArg hay một đối tượng khác được dân xuât tư đối tượng EventArgs. Các sự kiện này được quan lý trên Server.

4.2.1 Sư kiên PostBack va Non-PostBack

PostBack là sự kiện sẽ khiến Form được gửi vê Server ngay lâp tưc, chẳng hạn sự kiện đệ trinh một Form với phương thưc Post. Đối lâp với PostBack là Non- PostBack, sự kiện này không gửi Form nên Server mà nó lưu sự kiện trên vùng nhớ Cache cho tới khi có một sự kiện PostBack nưa xay ra. Khi một điêu khiển có thuộc tinh AutoPostBack là true thi sự kiện PostBack sẽ có tác dung trên điêu khiển đó:măc nhiên thuộc tinh AutoPostBach của điêu khiển DropDownList là false,ta phai đăt lại là true thi sự kiện chọn một muc khác trong DropDownList này mới có tác dung.

4.2.2 Trạng thai của ưng dung Web (State)

Trạng thái của ưng dung Web là giá trị hiện hành của các điêu khiển và mọi biến trong phiên làm việc hiện hành của ngươi dùng. Web là môi trương không trạng thái, nghĩa là mỗi sự kiện Post lên Server đêu làm mât đi mọi thông tin vê phiên làm việc trước đó. Tuy nhiên ASP.NET đã cung câp cơ chế hỗ trợ việc duy tri trạng thái vê phiên của ngươi dùng. Bât kỳ trang nào khi được gửi lên máy chủ Server đêu được máy chủ tổng hợp thông tin và tái tạo lại sau đó mới gửi xuống trinh duyệt cho máy khách. ASP.NET cung câp một cơ chế giúp duy tri trạng thái của các điêu khiển phia máy chủ (Server Control ) một cách tự động. Vi thế nếu ta cung câp cho ngươi dùng một danh sách dư liệu ListBox, và ngươi dùng thực hiện việc chọn lựa trên ListBox này, sự kiện chọn lựa này sẽ vân được duy tri sau khi trang được gửi lên máy chủ và gửi vê cho trinh duyệt cho máy khách.

4.2.3 Chu trinh sống của một Web-Form

Khi có yêu câu một trang Web trên máy chủ Web sẽ tạo ra một chuỗi các sự kiện ở máy chủ đó, tư lúc bắt đâu cho đến lúc kết thúc một yêu câu sẽ hinh thành một chu trinh sống ( Life-Cycle ) cho trang Web và các thành phân thuộc nó. Khi một trang Web được yêu câu, máy chủ sẽ tiến hành mở ( Load ) nó và khi hoàn tât yêu câu máy chủ sẽ đóng trang này lại, kết xuât của yêu câu này là một trang HTML tương ưng sẽ được gửi vê cho trinh duyệt. Dưới đây sẽ liệt kê một số sự kiện, ta có thể bắt các sự kiện để xử lý thich hợp hay bo qua để ASP.NET xử lý măc định.

Khởi tạo (Initialize) Là sự kiện đâu tiên trong chu trinh sống của trang, ta có thể khởi bât kỳ các thông số cho trang hay các điêu khiển thuộc trang.

Mở trạng thai vùng quan sat (Load View State) Được gọi khi thuộc tinh

ViewState của điêu khiển được công bố hay gọ. Các giá trị trong ViewState sẽ được lưu trư trong một biến ẩn ( Hidden Field ), ta có thể lây giá trị này thông qua hàm

Bai tập thưc hanh Chuyên đề Visual Studio .NET 138

Page 139: Giao trinh visual studio[bookbooming.com]

LoadViewState() hay lây trực tiếp. Kết thúc (Dispose) Ta có thể dùng sự kiện này để giai phóng bât kỳ tài nguyên nguyên nào: bộ nhớ hay hủy bo các kết nối đến cơ sở dư liệu.

Vi du: Hiển thị chuỗi lên trang

Đâu tiên ta cân chạy Visual Studio .NET, sau đó tạo một dự án mới kiểu WebApplication, ngôn ngư chọn là C# và ưng dung sẽ có tên là ProgrammingCSharpWeb.Url măc nhiên của ưng dung sẽ có tên là http://localhost/ ProgrammingCSharpWeb. Visual Studio .NET sẽ đăt hâu hết các tâp tin nó tạo ra cho ưng dung trong thư mucWeb măc định trên máy ngươi dùng, vi du: D:\Inetpub\wwwroot\ProgrammingCSharpWeb. Trong .NET, một giai pháp (Solution) có một hay hiêu dự án (Project), mỗi dự án sẽ tạo ra một thư viện liên kết

động (DLL) hay tâp tin thực thi (EXE). Để có thể chạy được ưng dung Web Form, ta cân phai cài đăt IIS và FrontPage Server Extension trên máy tinh.

Khi ưng dung Web Form được tạo, .NET tạo sẵn một số tâp tin và một trang Web có tên măc định là WebForm1.aspx chỉ chưa mã HTML và WebForm1.cs chưa mã quan lý trang. Trang mã .cs không nằm trong cửa sổ Solution Explorer, để hiển thị nó ta chọn Project\Show All Files, ta chỉ cân nhân đúp chuột trái trên trang Web là cửa sổ soạn thao mã (Editor) sẽ hiện nên, cho phép ta viết mã quan lý trang. Để chuyển tư cửa số thiết kế kéo tha sang cửa sổ mã HTML của trang, ta chọn hai Tab ở góc bên trái phia dưới màn hinh.

Đăt tên lại cho trang Web bằng cách nhân chuột phai lên trang và chọn muc Rename để đổi tên trang thành HelloWeb.aspx, .NET cũng sẽ tự động đổi tên trang mã của trang thành HelloWeb.cs. NET cũng tạo ra một số mã HTML cho trang:

.NET đã phát sinh ra một số mã ASP.NET:

<%@ Page language="c#"

Codebehind="HelloWeb.cs"

AutoEventWireup="false"

Inherits="ProgrammingCSharpWeb.WebForm1" %>

Thuộc tinh language chỉ ra ngôn ngư lâp trinh được dùng trong trang mã để quan lý trang, ở đây là C#. Codebehide xác định trang mã quan lý có tên HelloWeb.cs và thuộc tinh Inherits chỉ trang Web được thưa kế tư lớp WebForm1 được viết trong HelloWeb.cs:

public class WebForm1: System.Web.UI.Page

Ta thây trang này được thưa kế tư lớp System.Web.UI.Page, lớp này do ASP.NET cung câp, xác định các thuộc tinh, phương thưc và các sự kiện chung cho các trang phia máy chủ. Mã HTML phát sinh định dạng thuộc tinh của Form:

Bai tập thưc hanh Chuyên đề Visual Studio .NET 139

Page 140: Giao trinh visual studio[bookbooming.com]

<form id="Form1" method="post" runat="server">

Thuộc tinh id làm định danh cho Form, thuộc tinh method có giá trị là “POST” nghĩa là Form sẽ được gởi lên máy chủ ngay lâp tưc khi nhân một sự kiện do ngươi dùng phát ra ( như sự kiện nhân nút ) và cơ IsPostBack trên máy chủ khi đó sẽ có giá trị là true. Biến cơ này có giá trị là false nếu Form được đệ trinh với phương thưc “GET” hay lân đâu tiên trang được gọi. Bât kỳ điêu khiển nào hay Form có thuộc tinh runat=”server” thi điêu khiển hay Form này sẽ được xử lý bởi ASP.NET Framework trên máy chủ. Thuộc tinh MS_POSITIONING =“GridLayout” trong thẻ <Body>, cho biết cách bố tri các điêu khiển trên Form theodạng lưới, ngoài ra ta còn có thể bố tri các điêu khiển trôi lổi trên trang, bằng cáchgán thuộc tinh MS_POSITIONING thành “FlowLayout”.

Hiện giơ Form của ta là trống, để hiển thị một chuỗi gi đó lên màn hinh, ta gõ dòng mã sau trong thẻ <body>:

Hello World! It is now <% = DateTime.Now.ToString( ) %>

Giống với ASP, phân nằm trong dâu <% %> được xem như là mã quan lý cho trang, ở đây là mã C#. Dâu = chỉ ra một giá trị nhân được tư một biến hay một đối tượng nào đó, ta cũng có thể viết mã trên lại như sau với cùng chưc năng:

Hello World! It is now

<% Response.Write(DateTime.Now.ToString( )); %>

Thực thi trang này ( Ctrl-F5 ), kết qua sẽ hiện trên trinh duyệt như sau:

Để thêm các điêu khiển cho trang, hoăc là ta có thể viết mã trong của sổ HTML hoăc là kéo tha các điêu khiển trên bộ công của Web Form vào cửa sổ thiết kế trang. ASP.NET sẽ tự động phát sinh ra kết qua tư mã HTML thành các điêu khiển cũng như tư các điêu khiển trên trang thiết thành mã HTML tương ưng. Vi du, kéo hai RadioButton vào trang và gán cùng một giá trị nào đó cho thuộc tinh GroupName của ca hai điêu khiển, thuộc tinh này sẽ làm cho các nút chọn loại trư lân nhau. Mã HTML của trang trong thẻ <Form> do ASP.NET phát sinh sẽ như sau:

Các điêu khiển của ASP.NET, có thêm chư “asp:” phia trước tên của điêu khiển đó, được thiết kế mang tinh hướng đối tượng nhiêu hơn.

<asp:RadioButton>

<asp:CheckBox>

<asp:Button>

<asp:TextBox rows="1">

<asp:TextBox rows="5">

Bai tập thưc hanh Chuyên đề Visual Studio .NET 140

Page 141: Giao trinh visual studio[bookbooming.com]

Ngoài các điêu khiển của ASP.NET, các điêu khiển HTML chuẩn cũng được ASP.NET hỗ trợ. Tuy nhiên các điêu khiển không tạo sự dễ đọc trong mã nguồn do tinh đối tượng trên chúng không rõ ràng, các điêu khiển HTML chuẩn ưng với năm điêu khiển trên là:

<input type = "radio">

<input type="checkbox">

<input type="button">

<input type="text">

<textarea>

4.3 Điều khiển xac nhân hợp

ASP.NET cung câp một tâp các điêu khiển xác nhân hợp lệ dư liệu nhâp phia máychủ cũng như ở dưới trinh duyệt của máy khách. Tuy nhiên việc xác nhân hợp lệ dưới máy khách chỉ là một chọn lựa, ta có thể tắt nó đi, nhưng việc xác nhân hợp lệ trên máy chủ thông qua các điêu khiển này là bắt buộc, nhằm phòng ngưa một số trương hợp dư liệu nhâp là gia mạo. Việc kiểm tra hợp lệ của mã trên máy chủ là đê phòng các trương hợp. Một số loại xác nhân hợp lệ: dư liệu không được rỗng, thoa một định dạng dư liệu nào đó …

Các điêu khiển xác nhân hợp lệ phai được gắn liên với một điêu khiển nhân dư liệuHTML nào đó, các điêu khiển nhâp được liệt trong bang sau:

Ứng với một điêu khiển nhâp HTML, ta có thể gắn nhiêu điêu khiển xác nhân hợplệ cho nó, bang dưới đây sẽ liệt kê các điêu khiển nhâp hiện có:

CompareValidator So sánh các giá trị của hai điêu khiển để xem có bằng nhau hay

không

CustomValidator Gọi một hàm do ngươi dùng định nghĩa để thi hành việc kiểm tra

RangeValidator Kiểm tra xem một muc có nằm trong một miên đã cho hay không

RegularExpressionvalidator Kiểm tra ngươi dùng có sửa đổi một muc ( mà giá trị của nó khác

với một giá trị đã chỉ định ban đâu, ngâm định giá trị ban đâu là

một chuỗi trống ) hay không

ValidationSummary Thông báo sự hợp lệ trên các điêu khiển

4.4 Một số ví du mẫu minh họa

Một cách thuân tiện nhât để học một công nghệ mới chinh là dựa vào các vi du, vivây trong phân này chúng ta sẽ khao sát một vài vi du để minh họa cho phân lý thuyết của chúng ta. Như ta đã biết, ta có thể viết mã quan lý theo hai cách: hoăc là viết trong tâp

Bai tập thưc hanh Chuyên đề Visual Studio .NET 141

Page 142: Giao trinh visual studio[bookbooming.com]

tin .cs hoăc là viết trực tiếp trong trang chưa mã HTML. Ở đây để dễ tâp trung vào các vi du của chúng ta, ta sẽ viết mã quan lý trực tiếp trên trang HTML.

Kết buộc dư liêu

Không thông qua thuộc tính DataSource

Ứng dung của chúng ta đơn gian chỉ hiện lên trang tên khách hàng và số hóa đơn bằng cách dùng hàm DataBind(). Hàm này sẽ kết buộc dư liệu của mọi thuộc tinh hay của bât kỳ đối tượng.

<html>

<head>

// mã quan lý C# sẽ___ được viết trong thẻ <script> này

<script language="C#" runat="server">

// trang sẽ___ gọi hàm này đâu tiên, ta sẽ___ thực hiện kết buộc

// trực tiếp trong hàm này

void Page_Load(Object sender, EventArgs e) {

Page.DataBind();

}

// lây giá trị của thuộc tinh thông qua thuộc tinh // get

string custID{

get {

return "ALFKI";

}

}

int orderCount{

get {

return 11;

}

}

</script>

</head>

<body>

<h3><font face="Verdana"> Ket buoc khong dung DataSource

Bai tập thưc hanh Chuyên đề Visual Studio .NET 142

Page 143: Giao trinh visual studio[bookbooming.com]

</font></h3>

<form runat=server>

Khach hang: <b><%# custID %></b><br>

So hoa don: <b><%# orderCount %></b>

</form>

</body>

</html>

Điều khiển DataList vơi DataSource

Trong vi du này, ta sẽ dùng thuộc tinh DataSource của điêu khiển <asp:DataList> để kết buộc dư liệu, ta sẽ cung câp cho thuộc tinh DataSource này một bang dư liệu gia, sau đó dùng hàm DataBinder.Eval()để kết buộc dư liệu trong DataSource theo một định dạng ( Format ) thich hợp mong muốn. Dư liệu sẽ được hiển thị lên màn hinh dưới dạng một bang các hóa đơn sau khi ta gọi hàm DataBind().

//Không gian tên chưa cac đối tượng của ADO.NET

<%@ Import namespace="System.Data" %>

<html>

<head>

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs e) {

// nếu trang được gọi lân đâu tiên

if (!Page.IsPostBack) {

// tạo ra một bang dư liệu mới gồm 4 cột , sau đó thêm dư

// liệu gia cho bang

DataTable dt = new DataTable();

DataRow dr;

// thêm 4 cột DataColumn vào bang, mỗi cột có các

// kiểu dư liệu riêng

dt.Columns.Add(new DataColumn("IntegerValue", typeof(Int32)));

dt.Columns.Add(new DataColumn("StringValue", typeof(string)));

dt.Columns.Add(new DataColumn("DateTimeValue", typeof(DateTime)));

dt.Columns.Add(new DataColumn("BoolValue", typeof(bool)));

Bai tập thưc hanh Chuyên đề Visual Studio .NET 143

Page 144: Giao trinh visual studio[bookbooming.com]

// thêm 9 dòng dư liệu cho bang bằng cách tạo ra

// một dòng mới dùng phương thưc NewRow() của đối

// tượng DataTable, sau đó gán dư liệu gia cho

// dòng này và thêm dòng dư liệu này vào bang

for (int i = 0; i < 9; i++) {

dr = dt.NewRow();

dr[0] = i;

dr[1] = "Item " + i.ToString();

dr[2] = DateTime.Now;

dr[3] = (i % 2 != 0) ? true: false;

dt.Rows.Add(dr);

}

// gán bang dư liệu cho thuộc tinh DataSource của điêu

// khiển DataList, sau đó thực hiện kết buộc bằng hàm

// DataBind()

dataList1.DataSource = new DataView(dt);

dataList1.DataBind();

}

}

</script>

</head>

<body>

<h3><font face="Verdana">Ket buoc du lieu dung DataSource thong qua

ham DataBind.Eval() </font></h3>

<form runat=server>

// điêu khiển danh sách cho phép ta kết buộc dư liệu khá

// linh động, ta chỉ cân cung câp cho nó một DataSource

// thich hợp, sau đó gọi hàm DataBind()để hiển thị dư liệu // lên

trang

<asp:DataList id="dataList1" runat="server"

Bai tập thưc hanh Chuyên đề Visual Studio .NET 144

Page 145: Giao trinh visual studio[bookbooming.com]

RepeatColumns="3"

Width="80%"

BorderColor="black"

BorderWidth="1"

GridLines="Both"

CellPadding="4"

CellSpacing="0">

// đây là một thuộc tinh của lưới, khi gọi hàm

// DabaBind(), dư liệu trong DataSource sẽ___ được trich ra

// (nếu là danh các đối tượng thi mỗi lân trich sẽ___ lây ra

// một phân tử kiểu đối tượng đó, sau đó dùng hàm

// DataBinder.Eval()để gán giá trị, còn nếu là một bang

// dư liệu thi mỗi lân kết buộc sẽ___ lây ra một dòng dư

// liệu, hàm DataBind.Eval() sẽ___ lây dư liệu của tưng

// trương) để kết buộc lên trang. Nó sẽ___ lăp lại thao tác

// này cho tới khi dư liệu được kết buộc hết.

<ItemTemplate>

//lây dư liệu trên cột đâu tiên để kết buộc

Ngay hoa don: <%# DataBinder.Eval(Container.DataItem,

"DateTimeValue", "{0:d}") %>

//lây dư liệu trên cốt thư 2

So luong: <%# DataBinder.Eval(Container.DataItem, "IntegerValue",

"{0:N2}") %>

//cột thư 3

Muc: <%# DataBinder.Eval(Container.DataItem, "StringValue") %>

//cột thư 4

Ngay hoa don: <asp:CheckBox id=chk1 Checked='<%#

(bool)DataBinder.Eval(Container.DataItem, "BoolValue") %>'

runat=server/><p>

</ItemTemplate>

Bai tập thưc hanh Chuyên đề Visual Studio .NET 145

Page 146: Giao trinh visual studio[bookbooming.com]

</asp:Datalist>

</form>

</body>

</html>

Kết buộc vơi điều khiển DataGrid

Trong vi trước, ta đã tim hiểu sơ qua vê cách đẩy dư liệu vào thuộc tinh DataSource của điêu khiển DataList thông qua hàm kết buộc DataBind().Vi du này chúng ta sẽ khao sát thêm vê cách kết buộc trên điêu khiển lưới DataGrid và cách dùng điêu khiển xác nhân hợp lệ trên dư liệu. Khi ưng dung chạy sẽ hiển thị một bang dư liệu lên trang, ngươi dùng có thể hiệu chỉnh bât kỳ một dòng nào trên bang dư liệu bằng cách nhân vào chuỗi lệnh hiệu chỉnh ( Edit ) trên lưới, gõ vào các dư liệu cân hiệu chỉnh, khi muốn hủy bo thao tác hiệu chỉnh ta nhân chọn chuỗi bo qua (Cancel). Để tâp trung vào muc đich của vi du, chúng ta sẽ dùng bang dư liệu gia, cách làm sẽ tương tự trên bang dư liệu lây ra tư cơ sở dư liệu. Sau đây là mã của vi du:

//không gian tên cân thiết để truy câp đến cac đối tương ADO.NET

<%@ Import Namespace="System.Data" %>

<html>

<script language="C#" runat="server">

//khai báo đối tượng bang và khung nhin

DataTable Cart;

DataView CartView;

// lây dư liệu trong Session, nếu không có thi ta sẽ___ tạo ra một

// bang dư liệu khác

void Page_Load(Object sender, EventArgs e) {

if (Session["DG6_ShoppingCart"] == null) {

Cart = new DataTable();

//bang sẽ___ có 3 cột đêu có kiểu là chuỗi

Cart.Columns.Add(new DataColumn("Qty", typeof(string)));

Cart.Columns.Add(new DataColumn("Item", typeof(string)));

Cart.Columns.Add(new DataColumn("Price", typeof(string)));

//đẩy định danh của bang vào phiên làm việc hiện thơi

Session["DG6_ShoppingCart"] = Cart;

Bai tập thưc hanh Chuyên đề Visual Studio .NET 146

Page 147: Giao trinh visual studio[bookbooming.com]

// tạo dư liệu mâu cho bang

for (int i=1; i<5; i++) {

DataRow dr = Cart.NewRow();

dr[0] = ((int)(i%2)+1).ToString();

dr[1] = "Item " + i.ToString();

dr[2] = ((double)(1.23 * (i+1))).ToString();

Cart.Rows.Add(dr);

}

}

else {

//nếu bang đã có sẵn trong Session, ta sẽ___ lây ra dùng

Cart = (DataTable)Session["DG6_ShoppingCart"];

}

// tạo ra khung nhin cho bang, sau đó sắp xếp khung nhin theo // cột

Item

CartView = new DataView(Cart);

CartView.Sort = "Item";

// nếu trang được gọi lân đâu tiên thi kết buộc dư liệu thông // qua

hàm BindGrid()của ta

if (!IsPostBack) {

BindGrid();

}

}

// sự kiện nhân chuỗi hiệu chỉnh (Edit) trên lưới, ta sẽ___ lây chỉ //

muc của dòng cân hiệu chỉnh thông qua đối tượng

// DataGridCommandEventArgs, sau đó truyên chỉ muc này cho điêu //

khiển lưới của ta và gọi hàm kết buộc của ta để đẩy dư liệu

// lên lưới

public void MyDataGrid_Edit(Object sender, DataGridCommandEventArgs

e) {

Bai tập thưc hanh Chuyên đề Visual Studio .NET 147

Page 148: Giao trinh visual studio[bookbooming.com]

MyDataGrid.EditItemIndex = (int)e.Item.ItemIndex;

BindGrid();

}

//sự kiện nhân bo qua trên lưới (Cancel)

public void MyDataGrid_Cancel(Object sender,

DataGridCommandEventArgs e) {

MyDataGrid.EditItemIndex = -1;

BindGrid();

}

//sau khi hiệu chỉnh dư liệu, ngươi dùng tiến hành câp nhât public

void MyDataGrid_Update(Object sender, DataGridCommandEventArgs e) {

// lây dư liệu trên TextBox

string item = e.Item.Cells[1].Text;

string qty = ((TextBox)e.Item.Cells[2].Controls[0]).Text;

string price = ((TextBox)e.Item.Cells[3].Controls[0]).Text;

// Ở đây, do chúng ta dùng dư liệu gia lưu trên bộ nhớ chinh, // nếu

dùng cơ sở dư liệu thi chúng ta sẽ___ tiến hành hiệu chỉnh // trực tiếp

trong cơ sở dư liệu bằng các câu truy vân:

// UPDATE, SELECT, DELETE

//xóa dòng cũ

CartView.RowFilter = "Item='"+item+"'";

if (CartView.Count > 0) {

CartView.Delete(0);

}

CartView.RowFilter = "";

//tạo dòng mới và thêm vào bang

DataRow dr = Cart.NewRow();

dr[0] = qty;

dr[1] = item;

dr[2] = price;

Bai tập thưc hanh Chuyên đề Visual Studio .NET 148

Page 149: Giao trinh visual studio[bookbooming.com]

Cart.Rows.Add(dr);

MyDataGrid.EditItemIndex = -1;

BindGrid();

}

//kết buộc dư liệu thông qua thuộc tinh DataSource của lưới

public void BindGrid() {

MyDataGrid.DataSource = CartView;

MyDataGrid.DataBind();

}

</script>

<body style="font: 10pt verdana">

<form runat="server">

<h3><font face="Verdana">Using an Edit Command Column in

DataGrid</font></h3>

//Khai báo các thông số cho lưới, các sự kiện trên lưới:

OnEditCommand: khi ngươi dùng nhân chuỗi hiệu chỉnh (Edit)

OnCancelCommand: nhân chuỗi bo qua hiệu chỉnh (Cancel)

OnUpdateCommand: nhân chuỗi câp nhât hiệu chỉnh (Update)

<asp:DataGrid id="MyDataGrid" runat="server"

BorderColor="black"

BorderWidth="1"

CellPadding="3"

Font-Name="Verdana"

Font-Size="8pt"

HeaderStyle-BackColor="#aaaadd"

OnEditCommand="MyDataGrid_Edit"

OnCancelCommand="MyDataGrid_Cancel"

OnUpdateCommand="MyDataGrid_Update"

AutoGenerateColumns="false"

>

Bai tập thưc hanh Chuyên đề Visual Studio .NET 149

Page 150: Giao trinh visual studio[bookbooming.com]

// các thông số hiệu chỉnh trên cột, ở đây ta chỉ cho ngươi

// dùng hiệu chỉnh trên cột số lượng và giá hóa đơn

<Columns>

<asp:EditCommandColumn

EditText="Edit"

CancelText="Cancel"

UpdateText="Update"

ItemStyle-Wrap="false"

HeaderText="Edit Command Column"

HeaderStyle-Wrap="false"

/>

<asp:BoundColumn HeaderText="Item" ReadOnly="true"

DataField="Item"/>

<asp:BoundColumn HeaderText="Quantity" DataField="Qty"/>

<asp:BoundColumn HeaderText="Price" DataField="Price"/>

</Columns>

</asp:DataGrid>

</form>

</body>

</html>

Điều khiển xac nhân hợp lê

Việc xác nhân hợp lệ là cân thiết với các ưng dung cân yêu câu nhâp liệu, việc đưa ra các điêu khiển có kha năng xác nhân hợp lệ trực tiếp dưới máy khách lân ở trên máy chủ, đây có thể là một tinh năng mới của ASP.NET, ta không cân phai viết mã kiểm tra gi ca, mã kiểm tra dưới trinh duyệt ( chẳng hạn như Java Script ) sẽ được ASP.NET tự động phát sinh. Để gắn một điêu khiển bắt lỗi vào một điêu khiển cân bắt lỗi ta chỉ cân gán thuộc tinh ControlToValidate của điêu khiển bắt lỗi bằng giá trị định danh id của điêu khiển cân bắt lỗi, vi du: Để bắt lỗi điêu khiển TextBox không được trống, ta viết má như sau:

//điêu khiển cân bắt lỗi

<ASP:TextBox id=TextBox1 runat=server />

//điêu khiển bắt lỗi hộp nhâp liệu TextBox1

Bai tập thưc hanh Chuyên đề Visual Studio .NET 150

Page 151: Giao trinh visual studio[bookbooming.com]

<asp:RequiredFieldValidator id="RequiredFieldValidator2"

ControlToValidate="TextBox1"

ErrorMessage="Card Number. "

Display="Static"

Width="100%" runat=server>

*

</asp:RequiredFieldValidator>

Vi du của chúng ta sẽ cho hiển thị 2 hộp thoại DropDownList, 2 nút chọn RadioButton và một hộp thoại nhâp TextBox, nếu tồn tại muc nhâp nào trống khi nhân nút xác nhân Validate, thi các điêu khiển xác nhân hợp lệ sẽ hiển thị lỗi tương ưng. Thông điệp lỗi có thể được hiển thị theo ba cách khác nhau: liệt kê theo danh sách (List), liệt kê trên cùng một dòng ( Single Paragraph ), liệt kê danh sách với dâu châm tròn ở đâu ( Bullet List ). Mã hoàn chỉnh của vi du được liệt kê như sau:

// không cho phép điêu khiển xác nhân hợp lệ dưới máy khách bằng

// cách gán thuộc tinh clienttarget = downlevel

<%@ Page clienttarget=downlevel %>

<html>

<head>

<script language="C#" runat=server>

// thay đổi chế___ độ hiển thị lỗi bằng cách chọn 1 trong 3 muc

// trong hộp thoại ListBox

void ListFormat_SelectedIndexChanged(Object Sender, EventArgs E )

{

valSum.DisplayMode = (ValidationSummaryDisplayMode)

ListFormat.SelectedIndex;

}

</script>

</head>

<body>

<h3><font face="Verdana">Vi du vê___ xác nhân điêu khiển hợp lệ

ValidationSummary</font></h3>

<p>

Bai tập thưc hanh Chuyên đề Visual Studio .NET 151

Page 152: Giao trinh visual studio[bookbooming.com]

<form runat="server">

<table cellpadding=10><tr> <td>

<table bgcolor="#eeeeee" cellpadding=10><tr><td colspan=3>

<font face=Verdana size=2><b>Credit Card

Information</b></font></td></tr>

<tr>

<td align=right>

<font face=Verdana size=2>Card Type:</font></td>

<td>

// danh sách các nút chọn được bắt lỗi bởi điêu //khiển xác nhân hợp

lệ RequireFieldValidator1

<ASP:RadioButtonList id=RadioButtonList1 RepeatLayout="Flow"

runat=server>

<asp:ListItem>MasterCard</asp:ListItem>

<asp:ListItem>Visa</asp:ListItem>

</ASP:RadioButtonList>

</td>

//điêu khiển xác nhân hợp lệ cho các nút chọn //RadioButtonList1

<td align=middle rowspan=1>

<asp:RequiredFieldValidator id="RequiredFieldValidator1"

ControlToValidate="RadioButtonList1"

ErrorMessage="Card Type. "

Display="Static"

InitialValue="" Width="100%" runat=server>

*

</asp:RequiredFieldValidator>

</td></tr>

<tr>

<td align=right>

<font face=Verdana size=2>Card Number:</font>

Bai tập thưc hanh Chuyên đề Visual Studio .NET 152

Page 153: Giao trinh visual studio[bookbooming.com]

</td>

<td>

<ASP:TextBox id=TextBox1 runat=server />

</td>

<td>

//điêu khiển xác nhân hợp lệ trên hộp thoại //nhâp liệu TextBox, nếu

chuỗi là trống khi //nhân nút Validate thi sẽ___ bị bắt lỗi.

<asp:RequiredFieldValidator id="RequiredFieldValidator2"

ControlToValidate="TextBox1"

ErrorMessage="Card Number. "

Display="Static"

Width="100%" runat=server>

*

</asp:RequiredFieldValidator>

</td>

</tr>

<tr>

<td align=right>

<font face=Verdana size=2>Expiration Date:</font>

</td>

<td>

//hộp thoại DropDownList dùng để hiển thị //danh sách các ngày, nếu

ngươi dùng chọn //muc trống trong DropDownList này thi sẽ___ bị //điêu

khiển xác nhân hợp lệ //RequireFieldValidator3 bắt lỗi

<ASP:DropDownList id=DropDownList1 runat=server>

<asp:ListItem></asp:ListItem>

<asp:ListItem >06/00</asp:ListItem>

<asp:ListItem >07/00</asp:ListItem>

<asp:ListItem >08/00</asp:ListItem>

<asp:ListItem >09/00</asp:ListItem>

Bai tập thưc hanh Chuyên đề Visual Studio .NET 153

Page 154: Giao trinh visual studio[bookbooming.com]

<asp:ListItem >10/00</asp:ListItem>

<asp:ListItem >11/00</asp:ListItem>

<asp:ListItem >01/01</asp:ListItem>

<asp:ListItem >02/01</asp:ListItem>

<asp:ListItem >03/01</asp:ListItem>

<asp:ListItem >04/01</asp:ListItem>

<asp:ListItem >05/01</asp:ListItem>

<asp:ListItem >06/01</asp:ListItem>

<asp:ListItem >07/01</asp:ListItem>

<asp:ListItem >08/01</asp:ListItem>

<asp:ListItem >09/01</asp:ListItem>

<asp:ListItem >10/01</asp:ListItem>

<asp:ListItem >11/01</asp:ListItem>

<asp:ListItem >12/01</asp:ListItem>

</ASP:DropDownList>

</td>

<td>

//điêu khiển xác nhân hợp lệ trên //DropDownList1 hiển thị ngày hết

hạn, nếu //ngươi dùng chọn một muc trống trên //DropDownList thi

điêu khiển này sẽ___ phát //sinh ra lỗi

<asp:RequiredFieldValidator id="RequiredFieldValidator3"

ControlToValidate="DropDownList1"

ErrorMessage="Expiration Date. "

Display="Static"

InitialValue=""

Width="100%"

runat=server>

*

</asp:RequiredFieldValidator></td>

</tr>

Bai tập thưc hanh Chuyên đề Visual Studio .NET 154

Page 155: Giao trinh visual studio[bookbooming.com]

<tr>

<td>

//nút nhân để xác định hợp lệ

<ASP:Button id=Button1 text="Validate" runat=server /></td></tr>

</table>

</td>

<td valign=top>

<table cellpadding=20><tr><td>

//điêu khiển dùng để hiện thị các lỗi lên trang, //nó sẽ___ bắt bât kỳ

lỗi nào được phát sinh bởi các //điêu khiển DropDownList để hiển thị

<asp:ValidationSummary ID="valSum" runat="server"

HeaderText="You must enter a value in the following fields:"

Font-Name="verdana"

Font-Size="12"

/>

</td></tr></table>

</td>

</tr>

</table>

<font face="verdana" size="-1">Select the type of validation summary

display you wish: </font>

//Danh sách liệt kê 3 cách hiển thị lỗi

<asp:DropDownList id="ListFormat" AutoPostBack=true

OnSelectedIndexChanged="ListFormat_SelectedIndexChanged"

runat=server >

<asp:ListItem>List</asp:ListItem>

<asp:ListItem selected>Bulleted List</asp:ListItem>

<asp:ListItem>Single Paragraph</asp:ListItem>

</asp:DropDownList>

</form>

Bai tập thưc hanh Chuyên đề Visual Studio .NET 155

Page 156: Giao trinh visual studio[bookbooming.com]

</body>

</html>

4.5 Cac dịch vu Web

Hiện nay, vân còn một số hạn chế lớn trong các ưng dung Web. Ngươi dùng bị giới hạn chỉ thực hiện được nhưng nội dung đã được câu trúc cho một trang cu thể và xem dư liệu thông qua một số giao diện cu thể nào đó đã được thiết kế trên máy chủ. Do đó ngươi dùng muốn lây được thông tin được linh động và hiệu qua hơn. Hơn nưa, thay vi ta hiển thị thông tin thông qua trinh duyệt Web, ta muốn chạy một phân mêm trực tiếp trên máy khách mà có thể trao đổi dư liệu trên máy chủ tuỳ ý. Công nghệ .NET cho phép xây dung cách dịch vu Web ( Web Services ) đáp ưng được các yêu câu trên. Ý tưởng chinh là: thay vi liệt kê các thông tin theo dạng HTML, trang tạo sẵn một loạt các lệnh gọi hàm. Các lệnh gọi hàm này có thể trao đổi thông tin qua lại giưa các hệ cơ sở dư liệu trên máy chủ. Các hàm này có thể châp nhân các tham số và có thể tra vê một giá trị tùy ý.

Các dịch vu Web vân dựa trên giao thưc HTTP để truyên dư liệu, đồng thơi nó cân phai sử dung thêm một loại giao thưc để phuc vu cho việc gọi hàm. Hiện nay có hai giao thưc được dùng chủ yếu là: SOAP ( Simple Object Access Protocol ) và SDL ( Service Description Language, đây là giao thưc riêng của Microsoft ). Ca hai giao thưc này đêu được xây dung dựa trên XML, muc đich chung của chúng là giúp định nghĩa các lệnh gọi hàm, tham số và giá trị.

Ngoài ra, Microsoft cũng đưa ra thêm một ý tưởng mới vê tâp tin Discovery File, có phân mở rộng là .disco. Tâp tin dạng này dùng để cung câp các thông tin cho các trinh duyệt để các trinh duyệt này có thể xác định được các trang trên các máy chủ mà có chưa các dịch vu Web.

Sau đây, ta sẽ tim hiểu một vi du nhằm minh họa việc tạo ra một dịch vu Web, đóng vai trò là một thư viện chưa một tâp các hàm tiện ich. Trang Web của chúng ta sẽ sử dung các hàm của dịch vu này. Dịch vu Web của chúng sẽ có tên MathService, đơn gian là định nghĩa bốn phương thưc cộng, trư, nhân, chia trên hai số thực bât kỳ. Mỗi phương thưc đêu nhân vào hai đối số kiểu số thực và tra vê kết qua cũng có kiểu số thực.

Đâu tiên ta cân tạo một dự án kiểu Web Service bằng cách chọn: New Project\Visual C# Project\ASP.NET Web Service và đăt tên cho dự án là MathService và đổi tên dịch vu thành MathService.asmx. NET có tạo sẵn cho chúng ta một số tâp tin như:

• Service1.asmx: được trinh duyệt yêu câu, tương tự với tâp tin .aspx.

• WebService1.cs: trang chưa mã C# quan lý.

• DiscoFile1.disco: tâp tin khám phá.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 156

Page 157: Giao trinh visual studio[bookbooming.com]

Trong vi du này, chúng ta sẽ tạo ra một Web Form mới và thiết giao diện như sau:

Web Form sẽ gọi thưc thi cac ham của dịch vu Web.

Dự án của ta sẽ thưa kế namespace là System.Web.Services.WebService,nơi chưa các thuộc tinh và phương thưc cân thiết để tạo dịch vu Web.

public class MathService: System.Web.Services.WebService

Trên mỗi phương thưc ta cân khai báo thuộc tinh [WebMethod], để chỉ ra đây là phương thưc sẽ được sử dung cho dịch vu Web. Mã của tâp tin dịch vu sẽ như sau:

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.Web;

using System.Web.Services;

namespace MathService

{

public class MathService:System.Web.Services.WebService

{

public MathService()

{

InitializeComponent();

}

#region Component Designer generated code

private IContainer components = null;

private void InitializeComponent()

{

}

protected override void Dispose( bool disposing )

{

if(disposing && components != null)

{

Bai tập thưc hanh Chuyên đề Visual Studio .NET 157

Page 158: Giao trinh visual studio[bookbooming.com]

components.Dispose();

}

base.Dispose(disposing);

}

#endregion

//4 hàm toán học của dịch vu Web, trên mỗi phương thưc

//ta cân khai báo thuộc tinh [WebMethod] để chỉ đây là

//phương thưc dành cho dịch vu Web.

[WebMethod]

public float Add(float a, float b)

{

return a + b;

}

[WebMethod]

public float Subtract(float a, float b)

{

return a - b;

}

[WebMethod]

public float Multiply(float a, float b)

{

return a * b;

}

[WebMethod]

public float Divide(float a, float b)

{

if (b==0) return -1;

return a / b;

}

}

Bai tập thưc hanh Chuyên đề Visual Studio .NET 158

Page 159: Giao trinh visual studio[bookbooming.com]

}

Bây giơ chúng ta sẽ viết mã thực thi cho trang Web. Trang Web của chúng ta sẽ gọi các hàm của dịch vu tương ưng với các phép cộng, trư, nhân, chia . Sau đây là mã của trang Web:

<%@ Import Namespace="MathService" %>

<html>

<script language="C#" runat="server">

float operand1 = 0;

float operand2 = 0;

public void Submit_Click(Object sender, EventArgs E)

{

try

{

operand1 = float.Parse(Operand1.Text);

operand2 = float.Parse(Operand2.Text);

}

catch (Exception) { /* bo qua lỗi nếu có */ }

Các dịch vu Web Gvhd: Nguyễn Tân Trân Minh Khang

195

//tạo ra một đối tượng dịch vu MathService để có thể truy câp đến

//các hàm thành viên của chúng.

MathService service = new MathService();

switch (((Control)sender).ID)

{

case "Add": Result.Text = "<b>Result</b> = " +

service.Add(operand1, operand2).ToString(); break;

case "Subtract": Result.Text = "<b>Result</b> = " +

service.Subtract(operand1, operand2).ToString(); break;

case "Multiply": Result.Text = "<b>Result</b> = " +

service.Multiply(operand1, operand2).ToString(); break;

case "Divide": Result.Text = "<b>Result</b> = " +

Bai tập thưc hanh Chuyên đề Visual Studio .NET 159

Page 160: Giao trinh visual studio[bookbooming.com]

service.Divide(operand1, operand2).ToString(); break;

}

}

</script>

<body style="font: 10pt verdana">

<h4>Using a Simple Math Service

</h4>

<form runat="server">

<div style="padding:15,15,15,15;backgroundcolor:

beige;width:300;border-color:black;borderwidth:

1;border-style:solid">

Operand 1:<br>

<asp:TextBox id="Operand1" Text="15" runat="server"

/><br>

Operand 2:<br>

<asp:TextBox id="Operand2" Text="5" runat="server"

/><p>

<input type="submit" id="Add" value="Add"

OnServerClick="Submit_Click" runat="server">

<input type="submit" id="Subtract" value="Subtract"

OnServerClick="Submit_Click" runat="server">

<input type="submit" id="Multiply" value="Multiply"

OnServerClick="Submit_Click" runat="server">

<input type="submit" id="Divide" value="Divide"

OnServerClick="Submit_Click" runat="server">

<p>

<asp:Label id="Result" runat="server" />

</div>

</form>

</body>

Bai tập thưc hanh Chuyên đề Visual Studio .NET 160

Page 161: Giao trinh visual studio[bookbooming.com]

</html>

PPHÂHÂ NN 5 5PPHUHU LULU CCPhu luc A Chuỗi kết nối cho cac loại nguồn dư liêu

Phu luc B Bang tương quan/chuyển đổi kiểu dư liêu ở .NET Framework vơi cac Data Provider

.NET Framework type

System.Data.DbType

SqlDbType OleDbType OdbcTypeOracleType

bool Boolean Bit Boolean Bit Byte

byte Byte TinyInt UnsignedTinyInt

TinyInt Byte

byte[] Binary VarBinary. Việc chuyển đổi ngâm định này là không đúng nếu mang byte là lớn hơn kich thước tối đa của một VarBinary (8000 bytes).

VarBinary Binary Raw

char   Không hỗ trợ.

Char Char Byte

DateTime

DateTime DateTime DBTimeStamp

DateTime DateTime

Decimal Decimal Decimal Decimal Numeric Number

double Double Float Double Double Double

float Single Real Single Real Float

Guid Guid UniqueIdentifier

Guid UniqueIdentifier

Raw

Int16 Int16 SmallInt SmallInt SmallInt Int16

Int32 Int32 Int Int Int Int32

Int64 Int64 BigInt BigInt BigInt Number

Bai tập thưc hanh Chuyên đề Visual Studio .NET 161

Page 162: Giao trinh visual studio[bookbooming.com]

.NET Framework type

System.Data.DbType

SqlDbType OleDbType OdbcTypeOracleType

object Object Variant Variant Không hỗ trợ.

Blob

string String NVarChar. Chuyển đổi ngâm định này là không đúng nếu string lớn hơn kich thước tối đa của một NVarChar (4000 ký tự).

VarWChar NVarChar NVarChar

TimeSpan

Time Không hỗ trợ.

DBTime Time DateTime

UInt16 UInt16 Không hỗ trợ.

UnsignedSmallInt

Int UInt16

UInt32 UInt32 Không hỗ trợ.

UnsignedInt BigInt UInt32

UInt64 UInt64 Không hỗ trợ.

UnsignedBigInt

Numeric Number

  AnsiString VarChar VarChar VarChar VarChar

  AnsiStringFixedLength

Char Char Char Char

  Currency Money Currency Không hỗ trợ.

Number

  Date Không hỗ trợ.

DBDate Date DateTime

  SByte Không hỗ trợ.

TinyInt Không hỗ trợ.

SByte

  StringFixedLength

NChar WChar NChar NChar

  Time Không hỗ trợ.

DBTime Time DateTime

  VarNumeric Không hỗ VarNumeric Không hỗ Number

Bai tập thưc hanh Chuyên đề Visual Studio .NET 162

Page 163: Giao trinh visual studio[bookbooming.com]

.NET Framework type

System.Data.DbType

SqlDbType OleDbType OdbcTypeOracleType

trợ. trợ.

Bai tập thưc hanh Chuyên đề Visual Studio .NET 163

Page 164: Giao trinh visual studio[bookbooming.com]

PPHÂHÂ NN TTAA II LIÊLIÊ UU THAMTHAM KHAKHA OO

(1) Stephen C. Perry, Core C# and .NET, Prentice Hall PTR, 2005(2) Microsoft Corporation, MSDN 2005

Bai tập thưc hanh Chuyên đề Visual Studio .NET 164