Giáo trình Lập trình mạng nâng cao hướng .NET - Nghề: Lập trình máy tính - Trình độ: Lành nghề bậc cao

pdf 86 trang Gia Huy 17/05/2022 1690
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Lập trình mạng nâng cao hướng .NET - Nghề: Lập trình máy tính - Trình độ: Lành nghề bậc cao", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfgiao_trinh_lap_trinh_mang_nang_cao_huong_net_nghe_lap_trinh.pdf

Nội dung text: Giáo trình Lập trình mạng nâng cao hướng .NET - Nghề: Lập trình máy tính - Trình độ: Lành nghề bậc cao

  1. BỘ LAO ĐỘNG - THƯƠNG BINH VÀ XÃ HỘI TỔNG CỤC DẠY NGHỀ Dự án giáo dục kỹ thuật và dạy nghề (VTEP) ﻱﻱﻱﻱﻱﻱﻱﻱﻱﻱ GIÁO TRÌNH Môn học: LẬP TRÌNH MẠNG NÂNG CAO HƯỚNG .NET Mã số: ITPGR3_13 NGHỀ : LẬP TRÌNH MÁY TÍNH Trình độ :Lành nghề bậc cao Đà Lạt - 2007 Trang 1
  2. Tuyên bố bản quyền : Tài liệu này thuộc loại sách giáo trình Cho nên các nguồn thông tin có thể được phép dùng nguyên bản hoặc trích dùng cho các mục đích về đào tạo và tham khảo . Mọi mục đích khác có ý đồ lệch lạc hoặc sử dụng với mục đích kinh doanh thiếu lành mạnh sẽ bị nghiêm cấm. Tổng Cục Dạy nghề sẽ làm mọi cách để bảo vệ bản quyền của mình. Tổng Cục Dạy Nghề cám ơn và hoan nghênh các thông tin giúp cho việc tu sửa và hoàn thiện tốt hơn tàI liệu này. Địa chỉ liên hệ: Dự án giáo dục kỹ thuật và nghề nghiệp Tiểu Ban Phát triển Chương trình Học liệu Trang 2
  3. LỜI TỰA Đây là tài liệu được xây dựng theo chương trình của dự án giáo dục kỹ thuật và dạy nghề, để có đươc giáo trình này dự án đã tiến hành theo hai giai đoạn. Giai đoạn 1 : Xây dựng chương trình theo phương pháp DACUM, kết quả của gian đoạn này là bộ khung chương trình gồm 230 trang cấp độ 2 và 170 trang cấp độ 3. Giai đoạn 2 : 29 giáo trình và 29 tài liệu hướng dẫn giáo viên cho nghề lập trình máy tính 2 cấp độ. Để có được khung chương trình chúng tôi đã mời các giáo viên, các chuyên gia đang làm việc trong lĩnh vực công nghệ thông tin cùng xây dựng chương trình. Trong giai đoạn viết giáo trình chúng tôi cũng đã có những sự điều chỉnh để giáo trình có tính thiết thực và phù hợp hơn với sự phát triển của lĩnh vực công nghệ thông tin. Trong quá trình biên soạn, mặc dù đã cố gắng tham khảo nhiều tài liệu và giáo trình khác nhưng tác giả không khỏi tránh được những thiếu sót và hạn chế. Tác giả chân thành mong đợi những nhận xét, đánh giá và góp ý để cuốn giáo trình ngày một hoàn thiện hơn. Tài liệu này được thiết kế theo từng mô đun/ môn học thuộc hệ thống mô đun/môn học của một chương trình, để đào tạo hoàn chỉnh nghề Lập trình máy tính ở cấp trình độ lành nghề và được dùng làm Giáo trình cho học viên trong các khoá đào tạo, cũng có thể được sử dụng cho đào tạo ngắn hạn hoặc cho các công nhân kỹ thuật, các nhà quản lý và người sử dụng nhân lực tham khảo. Đây là tài liệu thử nghiệm sẽ được hoàn chỉnh để trở thành giáo trình chính thức trong hệ thống dạy nghề. Trang 3
  4. 8ỤC LỤC ĐỀ MỤC TRANG 1. Lời tựa 3 2. Mục lục 4 3. Các hình thức học tập chính trong modun/môn học 11 4. Yêu cầu về đánh giá hoàn thành modun/môn học 12 5. Chương I : VB.NET 13 I. Bài 1 :Microsoft .NET Framework 6. Cài đặt Visual Studio.NET 13 7. Mở các Samples của QuickStart 16 8. Giới hạn của Software Tools hiện giờ 18 9. Giới hạn của VB6 19 10. .NET Framework 20 11. Metadata 23 12. Hổ trợ và phối hợp mọi ngôn ngữ lập trình 23 II. Bài 2 .:Visual Studio.NET 13. Visual Studio.NET 25 14. Visual Studio.NET IDE 27 15. Demo Program 30 16. Walk Through Code 34 17. Biểu diển DragDrop 40 III. Bài 3 :NHỮNG CHỨC NĂNG ĐỐI TƯỢNG MỚI CỦA VB.NET 18. Classes và Objects, nguyên tắc Abstraction 44 19. Fields, Properties, Methods và Events, nguyên tắc Encapsulation 45 20. Inheritance (Thừa Kế) 47 21. Polymorphism (Đa dạng) 48 22. Tạo một Class mới 49 23. Overloading methods 54 24. Object Lifecycle 55 25. Thừa kế 58 26. Ngăn cản Thừa kế 62 27. Thừa kế và Phạm vi hoạt động 62 28. Protected Methods 63 Trang 4
  5. 29. Overriding Methods 64 30. Overridding Method New 69 31. Tạo BaseClasses và Abstract Methods 70 32. Shared class members(Các thành viên để dùng chung của class) 72 33. Early Binding hay Late Binding (Hiệu lực Sớm hay Trễ) 81 34. Thừa kế từ một ngôn ngữ khác 83 35. Thừa kế hình ảnh (Visual Inheritance) 86 IV. Bài 4 :NHỮNG CHỨC NĂNG MỚI TRONG GIAO DIỆN CỬA SỔ CỦA VB.NET 36. Sự quan trọng của Windows Forms ? 89 37. Những điểm căn bản của Windows Forms ? 90 38. Kiến trúc (Architecture) của Windows Forms ? 92 39. Những Controls tàn hình được chứa riêng 93 40. Chọn Startup Form 94 41. Owned Forms (Forms có chủ) 95 42. Độ đậm (Opacity) của Form 96 43. Form properties cho Cancel Button và Default Button 96 44. Sự khác biệt trong các Hộp Giao Thoại (Dialog Boxes) 97 45. ShowDialog thay vì Show vbModal 99 46. DialogResult 100 47. Property Size 102 48. Tab Oder của các Controls 102 49. Control Arrays 103 50. Tự động Resize và định chỗ (positioning) 105 51. Anchoring (bỏ neo) 106 52. Docking (gắn vào) 108 53. Control Splitter 110 54. Các control Providers 113 55. Controls HelpProvider và ToolTip 113 56. Control ErrorProvider 114 57. Menus 115 58. Context Menus 118 59. Sửa đổi Menus lúc Runtime 120 60. Duplicating Menus 122 61. MDI Forms 123 62. Toolbars 125 63. Items là một collection of Strings 129 64. Items là một Array of Objects 132 65. ComboBox 135 Trang 5
  6. 66. Bài 5 .Data Grid 67. Giới thiệu ADO.NET 139 68. Dùng thẳng XML làm cơ sở dữ liệu 139 69. Tạo DataSet từ XML Schema 144 70. Dùng DataGrid 144 71. Bind DataSource của DataGrid vào một Dataset 144 72. Hiển thị các cột data theo ý mình 145 73. Dùng Dataview để Filter và Sort 148 74. Làm việc với một Row trong DataGrid 151 75. Edit XML file dựa trên XML Schema 157 76. Typed Dataset 159 77. Dùng Dataform wizard để phát sinh form từ Dataset 160 78. Chương :II ASP.NET 164 V. Bài 1 :Làm Quen với ASP.NET 79. ASP.NET là gì? 168 80. Phương pháp làm việc trong mạng 169 81. Sơ lược về .NET Framework 171 82. Bố trí và cài đặt ASP.NET 171 83. Tạo trang ASP.NET đầu tiên 178 VI. Bài 2 :Xây Dựng Trang ASP.NET 84. Phân tích mã ở trang ASP.NET đầu tiên 186 85. Xây dựng một trang ASP.NET đơn giản 188 86. Vài nhận xét khi dùng ASP.NET và HTML 192 VII. Bài 3 :Giới thiệu về WEB MATRIX 87. Sơ lược về Web Matrix 195 88. Khác biệt giữa Visual Studio.NET và Web Matrix 196 89. Các đặc điểm của Web Matrix 197 90. Cài đặt Web Matrix 198 91. Ði dạo một vòng với Web Matrix 198 92. Tạo trang ASP.NET với Web Matrix 201 Trang 6
  7. VIII. Bài 4 :Dùng ASP.NET Objects với VB.NET 93. Ðối tượng (object) cơ bản và đặc tính (properties) 204 94. Ðối tượng ASP.NET Objects và phương pháp khai 95. Phương pháp làm việc với Session và Cookies 214 96. HttpCookie Object 220 97. HttpApplication Object 224 98. HttpServerUtility Object 225 IX. Bài 5 :ASP.NET và VB.NET 99. Giới thiệu tổng quát về .NET Framework 229 100. Classes 238 X. Phương pháp (method) lập trình tổng quát 239 111. Thuật ngữ chuyên môn 242 112. Tài liệu tham khảo 244 Trang 7
  8. GIỚI THIỆU VỀ MÔN HỌC Vị trí, ý nghĩa, vai trò môn học : Đây là môn học nằm ở học kỳ cuối trong chương trình đào tạo, là nền tảng để học sinh ứng dụng trong thực tiễn khi tốt nghiệp, ứng dụng các môn học trước đểt ạo ra một phần mềm (trang Web) hoàn chỉnh. Mục tiêu của môn học: Cài đặt Visual Studio.net, thao tác trên VB.Net và ASP.net, tìm hiểu về Form, các cấu trúc điều khiển, cách tạo một phần mềm, trang Web, gắn kết giữa VB.net và ASP.net Mục tiêu thực hiện của mô đun/môn học: Cài và sử dụng được VB.net và ASP.net Xây dựng kiến thức cơ bản về VB.net, ASP.net Nắm được các thuộc tính, công dụng của các công cụ Cách thiết kế một phần mềm, trang Web Cách trang trí, hiệu chỉnh sản phẩm Nội dung chính của môn học : PHẦN I VB.NET Microsoft .NET Framework Visual Studio.NET Những chức năng đối tượng mới của VB.NET Những chức năng mới trong giao diện cửa sổ của VB.NET DataGrid PHẦN II ASP.NET Làm Quen với ASP.NET Xây Dựng Trang ASP.NET Giới thiệu về WEB MATRIX Dùng ASP.NET Objects với VB.NET ASP.NET và VB.NET Trang 8
  9. .NET là tầng trung gian giữa các ứng dụng (applications) và hệ điều hành (OS). Tầng .NET cung cấp mọi dịch vụ cơ bản giúp ta tạo các công dụng mà ứng dụng (application) đòi hỏi, giống như hệ điều hành cung cấp các dịch vụ cơ bản cho ứng dụng (application), tỷ như: đọc hay viết các tập tin (files) vào dĩa cứng (hard drive), Tầng này bao gồm 1 bộ các ứng dụng (application) và hệ điều hành gọi là .NET Servers. Như vậy, .NET gần như là một bộ sưu tập (collection) các nhu liệu và khái niệm kết hợp trộn lẫn nhau làm việc nhằm tạo giải đáp các vấn đề liên quan đến thương nghiệp của ta. Trong đó: Tập hợp các đối tượng (objects) được gọi là .NET Framework và Tập hợp các dịch vụ yểm trợ mọi ngôn ngữ lập trình .NET gọi là Common Laguage Runtime (CLR). .NET Servers Mục tiêu chính của .NET là giúp ta giảm thiểu tối đa công việc thiết kế hệ thống tin học phân tán (distributed system). Đa số công việc lập trình phức tạp đòi hỏi đều được thực hiện ở hậu phương (back end) trong các máy cung cấp dịch vụ (servers). Microsoft đã đáp ứng với bộ sưu tập '.NET Enterprise Servers', bộ này chuyên trị và yểm trợ mọi đặc tính (features) hậu phương cần có cho một hệ thống tin học phân tán (distributed system). Bộ sưu tập '.NET Enterprise Servers' bao gồm: Server Operationg Systems: MS Windows Server, Advanced Server và Data Center Server Clustering và Load Balancing Systems: MS Application Center, MS Cluster Server Database System: MS SQL Server E-Mail System: MS Exchange Server Data-transformation engine trên cơ sở XML: MS Biz Talk Server Accessing Legacy Systems: Host Integration Server Tất cả các máy server này cung cấp mọi dịch vụ cần thiết cho các ứng dụng (application) về .NET và là nền tảng xây dựng hệ thống Tin Học cho mọi dự án lập trình. .NET Framework Đối với Visual Basic.NET (VB.NET), tất cả mọi thứ đều thay đổi tận gốc rễ. Một trong những thành phần quan trọng của .NET là .NET Framework. Đây là nền tảng cho mọi công cụ phát triển các ứng dụng (application) .NET .NET Framework bao gồm: Môi trường vận hành nền (Base Runtime Environment) Bộ sưu tập nền các loại đối tượng (a set of foundation classes) Môi trường vận hành nền (Base Runtime Environment) hoạt động giống như hệ điều hành cung cấp các dịch vụ trung gian giữa ứng dụng (application) và các thành phần phức tạp của hệ thống. Bộ sưu tập nền các loại đối tượng (a set of foundation classes) bao gồm 1 số lớn các công dụng đã soạn và kiểm tra trước, tỷ như: giao lưu với hệ thống tập tin (file system access) hay ngay cả các quy ước về mạng (Internet protocols), nhằm giảm thiểu gánh nặng lập trình cho các chuyên gia Tin Học. Do đó, việc tìm hiểu .NET Framework giúp ta lập trình dễ dàng hơn vì hầu như mọi công dụng đều đã được yểm trợ. Ta xem .NET Framework như là một tầng công dụng trừu tượng cung cấp dịch vụ trên hệ điều hành (nhìn dưới khía cạnh cung cấp dịch vụ) Để mọi ngôn ngữ lập trình sử dụng được các dịch vụ cung cấp bởi .NET Framework, Microsoft tạo ra 1 tiêu chuẩn chung cho ngôn ngữ lập trình gọi là Common Language Specifications (CLS). Tiêu chuẩn này giúp các chương trình biên dịch (compilers) làm việc hữu Trang 9
  10. hiệu. Microsoft sáng chế ra Visual Basic.NET (VB.NET), Visual C++.NET và C# (đọc là C Sharp) cho nền .NET Framework và cũng không quên phổ biến rộng rãi CLS trong Công Nghệ Tin Học giúp các ngôn ngữ lập trình khác làm việc trong nền .NET, tỷ như: COBOL.NET, Smalltalk.NET, Lưu ý ở đây, mặc dù Visual Basic.NET (VB.NET), Visual C++.NET hay C# khác nhau về syntax và các công dụng phụ thuộc nhưng tất cả đều biên dịch ra cùng 1 ngôn ngữ trung gian gọi là MSIL (Microsoft Intermediate Language) và do đó, không có ngôn ngữ lập trình .NET nào hùng mạnh hơn ngôn ngữ lập trình .NET nào. Tất cả đều bình đẳng, 'không ai bảnh hơn ai', việc chọn ngôn ngữ lập trình nào cũng là chuyện nhỏ, tùy ý thích lập trình viên. Visual Basic.NET (VB.NET) là ngôn ngữ lập trình khuynh hướng đối tượng (Object Oriented Programming Language) do Microsoft thiết kế lại từ con số không. Visual Basic.NET (VB.NET) không kế thừa VB6 hay bổ sung, phát triển từ VB6 mà là một ngôn ngữ lập trình hoàn toàn mới trên nền Microsoft 's .NET Framework. Do đó, nó cũng không phải là VB phiên bản 7. Thật sự, đây là ngôn ngữ lập trình mới và rất lợi hại, không những lập nền tảng vững chắc theo kiểu mẫu đối tượng như các ngôn ngữ lập trình hùng mạnh khác đã vang danh C++, Java mà còn dễ học, dễ phát triển và còn tạo mọi cơ hội hoàn hảo để giúp ta giải đáp những vấn đề khúc mắc khi lập trình. Hơn nữa, dù không khó khăn gì khi cần tham khảo, học hỏi hay đào sâu những gì xảy ra bên trong hậu trường OS, Visual Basic.NET (VB.NET) giúp ta đối phó với các phức tạp khi lập trình trên nền Windows và do đó, ta chỉ tập trung công sức vào các vấn đề liên quan đến dự án, công việc hay doanh nghiệp mà thôi. Trong khóa học này, các bạn sẽ bắt đầu làm quen với kiểu lập trình dùng Visual Basic.NET (VB.NET) và dĩ nhiên, các khái niệm và thành phần cơ bản của .NET Framework. Nếu ta để ý tên của Visual Basic.NET (VB.NET), ta thấy ngay ngôn ngữ lập trình này chuyên trị tạo ứng dụng (application) dùng trong mạng, liên mạng hay trong Internet. Tuy nhiên, khi học bất cứ một ngôn ngữ lập trình mới nào, ta cũng cần 'tập đi trước khi tập chạy'. Do đó, ta sẽ tập trung vào việc lập trình các ứng dụng (applications) trên nền Windows và đó cũng là mục tiêu chính yếu của khóa học cơ bản Visual Basic.NET Ta nên chuẩn bị sẵn một số kiến thức căn bản về lập trình hay phát triển mạng khi bước vào khóa học này thì tốt hơn, vì tuy bạn không cần phải biết về ASP cổ điển (classic ASP) nhưng, như chúng tôi đã trình bày trong phần FAQ ở trang Chào Mừng đầu khóa học, bạn cần: tham khảo các bài viết trong khóa Học Microsoft .NET của thầy Lê Ðức Hồng để làm quen với .NET framework, Visual Basic.NET, Visual Studio.NET. VB.NET sẽ được dùng làm ngôn ngữ mặc định (default) trong các thí dụ, các bài tập hay các dự án của khoá. biết tổng quát về HTML (HyperText Markup Language) khi ta cần trình bày các trang web trên browser. Browser được dùng trong khoá này là IE6 (Internet Explorer Version 6). quen thuộc với các hệ điều hành mới hiện nay (Operating System) như Windows 2000 (Professional hay Server) hay Windows XP (Home hay Professional), cũng như quen thuộc cách quản lý các ứng dụng liên hệ như Web Server (Personal Web Server hay Internet Information Server - IIS) và các cơ sở dữ liệu (database) MS SQL Server 2000 - xin tham khảo các bài viết về MCSE của thầy Vũ Hữu Tín, thầy Tăng Vinh Tài và lớp MCSE. vài kiến thức căn bản về XML liên quan đến việc chuyển thông tin từ chổ này qua chổ khác. Về XML, bạn nên tham khảo các bài viết XML, Kỹ Thuật Nồng Cốt trong Tương Lai của thầy Lê Ðức Hồng và các bài tự học XML của cô Bạch Trí cũng trên mạng Vovisoft này). Thật ra, ta đâu làm khó nhau chi nhưng phải rào trước đón sau như vậy là vì con đường ta đi tìm hiểu về ASP.NET hơi lắt lẽo gập ghềnh. Một khi ta phát triển mạng với ASP.NET, ta phải vận dụng tất cả các ứng dụng liên hệ và kết hợp mọi thứ vào nhau. Ðó cũng là lý do tại sao khoá học này chỉ nhắm vào các lập trình viên đã có kinh nghiệm phát triển mạng. Tuy vậy, chúng tôi sẽ cố gắng trình bày một cách đơn sơ, ngắn và gọn khi đề cập đến các ứng dụng kể trên trong các bài học có liên quan đến để bạn (nhất là bạn nào thích thú trong việc phát triển mạng và mới làm quen với ASP.NET) dễ dàng theo dỏi và tìm hiểu về ASP.NET. Trang 10
  11. CÁC HÌNH THỨC HỌC TẬP CHÍNH TRONG MÔ ĐUN/MÔN HỌC Học trên lớp về lý thuyết của ngôn ngữ lập trình và các thành phần của môi trường lập trình, giáo viên hướng dẫn học sinh ghi chép và tiếp thu bài. Học sinh thực tập tại xưởng thực hành, giáo viên đưa ra các bài tập và tổ chức cho học sinh thực hành có sự giúp đỡ và sửa sai của giáo viên. Giáo viên đưa ra các bào tập lớn, học sinh làm bài tập theo nhóm và bảo vệ kết quả trên lớp, giáo viên đặt những câu hỏi với học sinh để xác nhận tính trung thực của học sinh trong quá trình thực hiện bài tập lớn. 1 : Học lý thuyết trên lớp. Giáo viên giảng dạy tại phòng lý thuyết có sự hỗ trợ của các thiết bị đa phương tiện để giới thiệu mẫu cho học sinh 2 : Thực hành tại xưởng Giáo viên đưa ra các bài tập, hứơng dẫn cho học sinh các bài tập mẫu, phát các bài tập cho học sinh, học sinh tự thực hiện có sự hướng dẫn của giáo viên. 3. Làm bài tập lớn Kết thúc môn học, giáo viên đưa ra các bài tập lớn cho học sinh ( dạng đề tài thực tập) học sinh thực hiện thành từng nhóm, sau khi hoàn thành, học sinh sẽ bào vệ cho các sản phẩm của mình. Trong quá trình học sinh bảo vệ, giáo viên phải có những cân hỏi để xác định tình trung thực của đề tài như: đề tài này học sinh có tự làm hay nhờ người khác, các thành viên trong nhóm phân công làm việc như thế nào. Trang 11
  12. YÊU CẦU VỀ ĐÁNH GIÁ HOÀN THÀNH MÔ ĐUN/MÔN HỌC Lý thuyết: Đánh giá thông qua kiểm tra trắc nghiệm : - Dùng phần mềm thi trắc nghiệm. - Kiểm tra trắc nghiệm có thể trên giấy hoặc trên máy tính. - Xây dựng ngân hàng câu hỏi, học viên sẽ nhận được một bộ để phát sinh ngâu nhiên và chất lượng các đề như nhau (trung bình, khá, giỏi, xuất sắc). - Thời gian làm bài tuỳ theo số lượng các câu trong đề. - Thang điểm 10 chia đều cho các câu. - Kết quả đánh giá dựa vào bài làm theo điểm đạt được. Thực hành: Đánh giá thông qua khả năng giải hoàn thành chương trình (đề kiểm tra) đề ra, khả năng giải quyết các bài toán đã đưa ra trong quá trình làm bài tập lớn thang điểm đánh giá 100. Thang điểm: (đánh giá câu hỏi trắc nghiệm) 0-49 : Không đạt 50-69 : Đạt trung bình 70-85 : Đạt khá 86-100 : Đạt Giỏi Thang điểm tổng hợp là thang điểm 100, tùy theo qui chế cụ thể sẽ có cách tính theo tỷ lệ thích hợp. Trang 12
  13. Chương : I VB.NET Bài 1 Microsoft .NET Framework MÃ BÀI: ITPRG23.1 Mục tiêu thực hiện: - Nắm được mục đích, lợi ích và một số thuật ngữ của trong .Net - Cài được Visual studio.net - So sánh được sự khác nhau giữa VB Visual studio 6.0 và VB.Net - Giải thích được lợi ích, tầm quan trọng của .Net Nội dung: 1. Cài đặt Visual Studio.NET 2. Mở các Samples của QuickStart 3. Giới hạn của Software Tools hiện giờ 4. Giới hạn của VB6 .NET Framework Metadata Hổ trợ và phối hợp mọi ngôn ngữ lập trình Cài đặt Visual Studio.NET Visual Studio.NET nằm trong 3 CD Trước hết chạy Setup.exe của Windows Component Update như dưới đây, click No khi Warning dialog hiện ra: Trang 13
  14. hình 1.1 : hộp thọai hình 1.2 :chạy Setup.exe của Visual Studio.NET Tiếp theo, chạy Setup.exe của Visual Studio.NET: hình 1.3 : chọn đường dẩn cài đặt Trang 14
  15. hình 1.4 : Visual Studio.Net at a Glance Trang 15
  16. hình 1.4 : chọn đối tượng cài đặt Bạn nên có CPU Pentium III, 500MHz trở lên, với 256 MB RAM và ít nhất 10GB Harddisk. Về OS bạn nên dùng Windows 2000 (Professional hay Server) hay Windows XP. Lý do chính là các versions Windows nầy hổ trợ Unicode và có Internet Information Server (IIS) hổ trợ ASPX để ta dùng cho ASP.NET. Mở các Samples của QuickStart Trước khi expand Samples của Quickstart bạn cần phải cài đặt IIS. Nếu chưa làm việc ấy bạn bỏ CD của Windows2000 hay WindowsXP vào để install IIS component. QuickStart Samples của .NET Framework chứa các giải thích căn bản và nhiều thí dụ. Để expand các Samples doubleclick Webpage Starthere.htm như trong hình dưới đây: Trang 16
  17. hình 1.5 :Mở các Samples của QuickStart Khi trang Web của QuickStart hiện ra, click QuickStart, tutorials and samples rồi sau đó theo chỉ dẫn từng bước. hình 1.6 : trang Web của QuickStart hiện ra Trang Framework SDK QuickStart Tutorials cho ta các bài tập của ASP.NET, Windows Forms và How Do I Trang 17
  18. hình1.7 :trang Web của QuickStart Nhớ để nguyên các folders của Unzipped files (E:\CD, E:\CD\WINCUP), đừng delete chúng, vì .NET sẽ còn dùng chúng. Ngoài ra, nếu sau nầy .NET bị corrupted vì conflict với các application software khác, bạn có thể cài đặt .NET lại. Giới hạn của Software Tools hiện giờ Architect của application software hiện giờ có nói chung ba tầng (three tiers): tầng giao diện (Presentation Tier), tầng giữa (Middle Tier) và tầng dữ kiện (Data Tier): Presentation Tier: Trong desktop Client ta dùng VB6 và nối với middle tier qua DCOM. Trong browser based Client ta dùng Javascript hay Java applet. Từ browser based Client ta dùng http để nối với middle tier qua IIS/ASP (có thể dùng COM ở đây). Middle Tier: Chứa các rules để validate data trên client và các business rules khác. Ta dùng VB6 ở đây, nhưng cách triển khai COM với những Object Oriented Programming concepts rắc rối hơn bình thường. Ta phải thiết kế sao cho các components scale well (dùng cho mọi cở). Có khi dùng Microsoft Transaction Server trên Windows NT hay COM+ Services trên Windows 2000. Lấp ráp các versions của components là một thách thức lớn. Nhiều khi middle tier còn nói chuyện với các database qua HTTP, ADO và CDO (Collaborative Data Objects), .v.v Trang 18
  19. Data Tier: Thường là relational database như Microsoft SQL Server hay Oracle. Ngoài ra còn có Exchange hay các database xưa của mainframe. Do đó ta thấy: Desktop tools không thích hợp cho Distributed System hay Internet Phải dùng nhiều thứ codes như VB6 Code, VBScript, JavaScript, Dynamic HTML, Cascading Style Sheet, VC++, Stored Procedures (Transact-SQL trong SQLServer hay PL-SQL trong Oracle). Tùy thuộc quá nhiều vào central database: Ngay cả ADO dù là tiện dụng cũng đòi hỏi Client luôn luôn connect với Server. Điều nầy không thích hợp cho Internet applications, vì bản chất của Internet là stateless (không giữ trạng thái), mỗi lần cần làm việc mới connect lại một chút thôi. DLL "Hell": Các ActiveX cần phải được registered với Windows Registry, chỉ có một version được chấp nhận. Nếu version mới nhất của một DLL không compatible với các versions trước đó mà applications trên máy đang cần thì có rắc rối. Trang 19
  20. Giới hạn của VB6 hình 1.8 :Giới hạn của VB6 Thiếu khả năng inheritance (thừa kế) và một số Object Oriented features khác. Khả năng Error handling giới hạn: On Error Goto , On Error Resume Next Nhiều khi cần phải gọi Windows API để làm những việc VB6 không hổ trợ: việc nầy không tự nhiên và đôi khi nguy hiểm. Không có multi-threading: không thể đoán trước response của code chạy trong các windows của cùng một VB6 application. Ngay cả giải quyết vấn đề multitasking bằng Timers cũng không đáng tin cậy. Không dễ dùng chung với các ngôn ngữ khác như VC++. Không tiện cho Web development: WebClass không thành công lắm. Ít ai chịu cho ta cài ActiveX trên máy của họ. Trang 20
  21. .NET Framework .NET được developed từ đầu năm 1998, lúc đầu có tên là Next Generation Windows Services (NGWS). Nó được thiết kế hoàn toàn từ con số không để dùng cho Internet. Viển tượng của Microsoft là xây dựng một globally distributed system, dùng XML (chứa những databases tí hon) làm chất keo để kết hợp chức năng của những computers khác nhau trong cùng một tổ chức hay trên khắp thế giới. Những computers nầy có thể là Servers, Desktop, Notebook hay Pocket Computers, đều có thể chạy cùng một software dựa trên một platform duy nhất, độc lập với hardware và ngôn ngữ lập trình. Đó là .NET Framework. Nó sẽ trở thành một phần của MS Windows và sẽ được port qua các platform khác, có thể ngay cả Unix. Mặc dầu hãy còn là Beta, .NET Framework rất stable và Visual Studio.NET rất ít bugs, có thể dùng cho software development ngay từ bây giờ. Hiện nay đã có một số sách về lập trình .NET do Wrox và Oreilly xuất bản. hình 1.9 :.NET Framework Các phần chính của Microsoft.NET Framework: Trang 21
  22. hình 1.10 : Các phần chính của Microsoft.NET Framework: .NET application được chia ra làm hai loại: cho Internet gọi là ASP.NET, gồm có Web Forms và Web Services và cho desktop gọi là Windows Forms. Windows Forms giống như Forms của VB6. Nó hổ trợ Unicode hoàn toàn, rất tiện cho chữ Việt và thật sự Object Oriented. Web Forms có những Server Controls làm việc giống như các Controls trong Windows Forms, nhất là có thể dùng codes để xử lý Events y hệt như của Windows Forms. Điểm khác biệt chánh giữa ASP (Active Server Pages) và ASP.NET là trong ASP.NET, phần đại diện visual components và code nằm riêng nhau, không lộn xộn như trong ASP. Ngoài ra ASP.NET code hoàn toàn Object Oriented. Web Services giống như những Functions mà ta có thể gọi dùng từ các URL trên Internet, thí dụ như Credit Card authorisation. ADO.NET là một loại cache database nho nhỏ (gọi là disconnected database) để thay thế ADO. Thay vì application connects vĩnh viễn với database mẹ qua ADO, application trong .NET làm việc với portable database chỉ chứa một hai tables, là copy từ database mẹ. Khi nào cần, portable database nầy (ADO.NET) sẽ được reconciled với database mẹ để update các thay đổi. Hai tables trong ADO.NET có thể được related nhau trong Master/Details relationship. Vì ADO.NET có chứa original data lẫn data mới nhất nên Rollback trong ADO.NET rất dễ dàng và nhẹ ký. XML được yểm trợ tối đa. Nằm phía sau ADO.NET là XML. XML có thể là Table of records trong ADO.NET hay Tree of nodes trong DOM (Document Object Model). IO được hổ trợ bằng toàn bộ Stream kể cả Memory Stream và StreamReader/StreamWriter. Thêm vào là DataFormatting cho Serialisation để chứa Object xuống binary file hay text file. TCP/IP và http là hai protocols thông dụng nhất trong .NET, nhưng chúng làm việc phía sau sân khấu giúp ta gọi một remote procedure (nằm trên computer khác) dễ dàng như một local procedure. Kỹ thuật ấy gọi là Remoting. Security hổ trợ Cryptography, Permissions và Policy. Trang 22
  23. Diagnostics cho ta Debug và Trace. Threading rất tiện và đơn giản để implement Lightweight Process. Vấn đề Timing trong .NET program rất linh động, hiệu quả và chính xác. Việc thiết kế Common Language Runtime nhắm vào các mục tiêu chính sau đây: Việc triển khai đơn giản và nhanh hơn: developers sẽ dành thì giờ quyết định ráp những software components nào lại với nhau nhiều hơn là lập trình thật sự. Các công tác thiết yếu ("plumbing") như memory management, process communication .v.v. được lo liệu tự động. Các công cụ hổ trợ rất đầy đủ (no more API): .NET Framework Base classes rất phong phú cho file, network, serialisation, mã hóa, XML, database, v.v Cài đặt đơn giản và an toàn (no more DLL "hell"): chỉ cần xcopy files, giống như thời vàng son của DOS. Lý do là .NET application chạy trên .NET framework, một khi ta đã cài .NET framework vào máy rồi thì có đầy đủ mọi .DLL cần thiết. Có lẽ trong tương lai Microsoft cài .NET framework chung với Windows. Dùng cho từ WindowsCE đến Desktop, đến Web (scalability). hình 1.11 : WindowsCE đến Desktop Metadata Metadata là các dữ kiện cắt nghĩa cho ta biết về dữ kiện. Thí dụ XML Schema của một XML file là metadata cắt nghĩa về data structure của data trong XML file. Chính cái XML Schema cũng là một XML file. Các .NET application components, gọi là Assembly, chứa rất nhiều metadata để cắt nghĩa về chính nó (self describing). Tìm biết về một .NET application để có thể làm việc với nó thì gọi là Reflection. Hổ trợ và phối hợp mọi ngôn ngữ lập trình Common Language Runtime (CLR) là trung tâm điểm của .NET Famework, nó là hầm máy để chạy các năng tính của .NET. Trong .NET, mọi ngôn ngữ lập trình đều được compiled ra Microsoft Intermediate Language (IL) giống giống như byte code của Java. Nhờ bắt buộc mọi ngôn ngữ đều phải dùng cùng các loại data types (gọi là Common Type System) nên Common Language Runtime có thể kiểm soát mọi interface, gọi giữa các components và cho phép các Trang 23
  24. ngôn ngữ có thể hợp tác nhau một cách thông suốt. Tức là trong .NET, VB.NET program có thể inherit C# program và ngược lại một cách hoàn toàn tự nhiên. Điều nầy chẳng những giúp các VC++ hay Java programmers bắt đầu dùng C# một cách dễ dàng mà còn làm cùng một dự án với VB.NET programmers nữa. Nếu VC++ linh động và hiệu năng hơn VB6, thì C# chẳng khác gì VB.NET. Bạn có thể port C# code qua VB.NET code rất dễ dàng. Vì source code VC++ và Java gần gũi C# hơn VB6 với VB.NET nên ngoài đời có nhiều C# code hơn VB.NET. Do đó, mặc dầu hai ngôn ngữ VB.NET và C# đều ngang cơ nhau, nếu dùng C# bạn được lợi điểm có nhiều source code sẵn và nhất là lâu nay người ta vẫn mang ấn tượng rằng VC++ hay Java programmers mới thật sự là các cao thủ lập trình, và có khuynh hướng trả lương các guru VC++/Java cao hơn VB programmers. Khi chạy .NET application, nó sẽ được compiled bằng một JIT (Just-In-Time) compiler rất hiệu năng ra machine code để chạy. Điểm nầy giúp .NET application chạy nhanh hơn Java interpreted code trong Java Virtual Machine. Just-In-Time cũng có nghĩa là chỉ phần code nào cần xử lý trong lúc ấy mới được compiled. IL code chạy trong CLR đuợc nói là managed code. .NET code có thể chạy chung với ActiveX, nhưng code trong ActiveX được gọi là unmanaged code, tức là CLR không chịu trách nhiệm. Ngoài việc allocation và management of memory, CLR còn giữ các refrerence đến objects và đỗ rác (handle garbage collection), tức là thâu lại các mảnh vụn memory khi chúng không cần dùng nữa. Trước đây, mỗi khi một DLL đuợc loaded vào memory, system sẽ ghi nhận có bao nhiêu task dùng nó để khi task cuối cùng chấm dứt thì system unload DLL và trả lại phần memory nó dùng trước đây để system dùng cho chuyện khác. Chớ nếu allocate memory để dùng mà không nhớ dispose nó thì sẽ bị memory leak (rỉ ), lần lần ta dùng hết memory, bị bắt buộc phải reboot OS. Nhưng bây giờ .NET dùng một process độc lập để làm việc garbage collection. Cái phản ứng phụ của việc nầy là khi ta đã Dispose một Object rồi, ta vẫn không biết chắc chắn chừng nào nó mới thật sự biến mất. Vì garbage collector là một low priority process làm việc trong background, chỉ khi nào system memory gần cạn nó mới nâng cao priority lên. Dĩ nhiên, nếu muốn, ta có thể đòi hỏi system Dispose một Object ngay lập tức. Trang 24
  25. Bài 2. VISUAL STUDIO.NET MÃ BÀI: ITPRG23.2 Mục tiêu thực hiện: - Tắt mở được các ứng dụng - Biết được các công dụng của ToolBox - Tạo được một project đơn giản trong VB.Net - Làm quen với một số thủ thuật để thiết kế phần mềm dể hơn - Tạo được một project đơn giản trong VB.Net Nội dung: Visual Studio.NET Visual Studio.NET IDE Demo Program Walk Through Code Biểu diển DragDrop a. Visual Studio.NET Có hai cách để bắt đầu một project mới trong VS.NET. Hoặc Click New Project trong trang Web StartPage như dưới đây: Hình 2.1 :Web StartPage Hoặc dùng Menu command File | New | Project giống như trong VB6 IDE: Trang 25
  26. hình 2.2 :Tạo mới Khi Add New Project, Name sẽ là subfolder name của New Project. Bạn có thể chọn VB.NET, C# hay VC++.NET project. Trong tương lai chúng ta sẽ chỉ nhắm vào VB.NET và C# thôi. Ngoài ra SetUp and Deployment bây giờ là một loại project nằm trong IDE của Visual Studio.NET, ta không cần phải chạy riêng chương trình Package and Deployment bên ngoài VB6 IDE như trước đây. Solution trong VS.NET có thể chứa hơn một Project và bao gồm tất cả những files bạn liệt ra là cần thiết cho Solution. Nếu một trong những files ấy bị thay đổi bên ngoài VS.NET, khi VS.NET khám phá ra nó sẽ load vào trong VS.NET cho bạn nếu bạn đồng ý. hình 2.3 : Solution trong VS.NET Trang 26
  27. Để mở một Solution/Project có sẵn, bạn có thể click link của tên project trên trang StartPage, hay dùng Menu command File | Open | Project , hay Menu Command File | Recent Projects. Visual Studio.NET IDE hình 2.4: Visual Studio.NET IDE Giao diện của VS.NET có những đặc điểm giống như Delphi và Visual InterDev ở chỗ code được generated tự động, Windows nằm chung thành Tab set hay float khắp nơi, và hổ trợ Solution rất thích hợp cho việc triển khai của cả đội. Toolbox bên trái chứa Controls cho Windows Forms, Web Forms, General Components, Data Components, HTML tags, XML Schema tools v.v Khi một Form đang hiển thị, click lên một button trong Toolbox để chọn Tool Set bạn cần. Toolbox ở trạng thái Fixed displayed (như trong hình trên) khi cây ghim phía trên đâm xuống. Bạn có thể click cây ghim cho nó nằm ngang và vertical Toolbox tab hiện ra bên trái. Lúc ấy, Toolbox ở trong trạng thái Auto Hide (hiện ra/rút vào) như dưới đây: hình 2.5 :Auto Hide Bạn có thể gọi hầu hết các Windows hiển thị bằng cách dùng Menu commands View, View | Other Windows và Debug | Windows: Trang 27
  28. hình 2.6 :hiển thị Windows Các Windows bên phải có thể float, nằm chồng lên nhau thành những Tabs trong một Window set hay nằm cạnh nhau vertically tiled. Nắm Tittle bar để dời nguyên một Window set đi. Nắm Window Tab của một Window set để kéo chỉ một Window ra. Bạn có thể để chồng hai Windows lại với nhau bằng cách nắm Tittle bar của một Window để chồng lên một Window khác. Thử nhích đi, nhích lại, trước khi buông Window ra để làm quen với kết quả. Phía dưới có Task List Window để bạn giữ sổ sách về diễn tiến của dự án và quản lý cả đội. Khi bạn dùng menu command Build | Build để compile program, nếu có errors chúng sẽ được hiển thị trong Task List Window. Double click lên một hàng error để mang cursor đến chỗ gây ra error ấy trong code window. Trong hình dưới đây, ta cố ý comment out hàng Dim sw As StreamWriter: Trang 28
  29. hình 2.7 :Task List Window Ngoài ra, để Debug bây giờ bạn có Output Window để in ra các messages mà trong VB6 bạn dùng Immediate Window. Thí dụ trong VB6 bạn viết: Debug.Print "Count=" & CStr(Count) để in ra trong Immediate Window, thì trong VB.NET bạn có thể viết: Console.WriteLine("Count= {0}", Count) để in ra trong Output Window. Dĩ nhiên bạn vẫn có thể tiếp tục dùng Immediate Window trong công tác Debug như trước đây trong VB6. Chưa hết, VS.NET còn cho bạn Command Window để ta có thể enter những VS.NET commands để manipulate IDE, xử lý macros, .v.v Để hiển thị Window nầy bạn dùng menu command View | Other Windows | Command Window. Để tiện hơn, bạn drag title bar của nó để chồng lên tab bar của Task List và Output windows. Hình 2.8 :Cửa sổ lệnh Trang 29
  30. Nếu ta enter một command như: File.AddNewProject IDE sẽ hiển thị Add New Project dialog. VS.NET hổ trợ Macro để bạn có thể record và playback một chuổi công tác. Phương tiện Integrated Debugging cho ta Debug Menu, Call Stack Window, Breakpoints Window và Watch and Value Display Windows. Thường thường bạn sẽ Add Reference các .NET components. Nhưng bạn cũng có thể dùng ActiveX (có sẵn trong VB6) trong .NET application bằng cách Add Reference COM (click Tab COM trên Add Reference Dialog). .NET sẽ gói ActiveX thành một NET component (click Yes trả lời câu hỏi "Would you like to have a wrapper generated for you?"). Ngoài ra dùng Add Reference Projects để refer đến DLL của các User developed DLL. hình 2.10 : Thêm tham chiếu Demo Program Trong chương trình biểu diễn nầy, ta dùng giao diện hầu như hoàn toàn bằng chữ Việt. Ta có thể đánh chữ Việt (Unicode) cho Title Bar, Menu, TextBox, ListBox .v.v Nếu bạn cần một key input software cho chữ Việt hổ trợ Unicode thì download VPS, Vietkey hay Unikey. Các documents như Form, XML .v.v. trong .NET project đều được Saved với UTF-8 encoding. Trang 30
  31. Trong program Sở thú Saigon nầy ta có hai Listboxes. Khi chạy, bạn có thể drag tên các loại thú từ Listbox1 (bên trái) để drop vào Listbox2 (bên phải). Phía dưới là một Label dùng để hiển thị ngày giờ. Có một button Lưu trử danh sách để ta save data trong Listbox2 vào file animal.txt trong subFolder bin. Ngoài ra bạn cũng có thể dùng Main menu Item Đọc danh sách để Load data từ file animal.txt vào Listbox2. hình 2.11 :Chương trình Demo Những components không cần phải hiện ra lúc runtime như Timer, Menu, Tooltip .v.v. nằm trong một Component Tray (mâm) riêng. Muốn Edit MainMenu, click lên MainMenu1 icon rồi đánh trực tiếp vào MainMenu. Thêm các menuitems mới bằng cách đánh thẳng vào các chỗ có chữ Type Here. Lưu ý các Tabs bên trên Editing Area khi bạn mở nhiều forms. Hình 2.12 : Cửa sổ thiết kế Edit MainMenu, insert một Separator Trang 31
  32. hình 2.13 : Chèn một Separator Chú ý danh sách các References được liệt kê trong Solution Explorer. hình 2.14 : danh sách các References Edit Shortcut cho một menu item. Trang 32
  33. hình 2.15 :Sửa Shortcut cho một menu item. Button bây giờ chẳng những có thể chứa hình mà còn cho bạn chọn vị trí của hình trong button bằng ImageAlign nữa. hình 2.16 : Edit ImageAlign Bạn có thể Anchor một Button để nó dính vào một góc của form để khi form resizes thì Button chạy theo góc ấy của form. Ở đây ta click hai thanh Dưới và Phải cho chúng trở nên màu đen để chọn Anchor Bottom và Right. Trang 33
  34. hình 2.17 : Điểu chỉnh Trong lúc thiết kế ta có thể edit các List items của một Listbox bằng cách mở property Items Collection ra và Edit vào một trang. hình 2.18 : Collection ra Walk Through Code Trong .NET, các classes được chia ra thành nhiều nhóm như System.IO, System.XML, System.Data, System.Drawing v.v Ngoài ra trong mỗi nhóm lại còn chia thành những nhóm con, cháu như System.Windows.Forms,System.Windows.Collections,System.Windows.Diagnostics, .v.v Mặc dầu một khi đã Project | Add Reference các .NET components ấy ta có thể dùng chúng trong program nhưng vẫn phải biên một tên dài như System.IO.StreamReader để tránh lẫn lộn. Để có thể viết tên class gọn hơn ta dùng Imports như Imports System.IO, sau đó ta chỉ cần viết Trang 34
  35. StreamReader là đủ. Công việc Imports nầy được gọi là importing Namespace (của System.IO). Tương tự như thế, để có thể tiếp tục dùng các Functions Left, Right, Mid của VB6 trong .NET ta có thể thêm câu Imports VB6 = Microsoft.VisualBasic ở đầu chương trình. Sau đó ta có thể viết: AppPath = VB6.Left(AppPath, Pos) Nguyên program chúng ta tại đây là Public Class Form1. Form1 thừa kế standard form class của .NET Framework nên ta declare: Inherits System.Windows.Forms.Form Imports System.IO Imports VB6 = Microsoft.VisualBasic Public Class Form1 Inherits System.Windows.Forms.Form Dim AppPath As String Private Sub MenuItem4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem4.Click End ' Terminate the program End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ' Obtain the folder where this program EXE resides and initialise tooltip Dim AppPath As String Dim Pos As Integer ' Fetch full pathname of the EXE file AppPath = System.Reflection.Assembly.GetExecutingAssembly.Location ' Locate the last slash in the pathname string Pos = InStrRev(AppPath, "/") ' Extract the part up to the backslash Trang 35
  36. AppPath = VB6.Left(AppPath, Pos) ' Initialise the tooltip for Listbox1 ToolTip1.SetToolTip(ListBox1, "Xin nắm kéo tên một con thú qua Listbox bên phải") End Sub Hãy xem cách viết một Event Handler như: Private Sub MenuItem4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem4.Click Khác với VB6, nó có thêm các chữ Handles MenuItem4.Click ở phía cuối để nói handling event Click của MenuItem4. Mọi Event Handler đều được passed cho hai parameters: ByVal sender As System.Object và ByVal e As System.EventArgs. Parameter thứ nhất, sender, là Object chủ động chuyện RaiseEvent, còn e là Event có chứa nhiều dữ kiện khác nhau tùy theo tình huống. Khi edit code bạn có thể nhờ Intellisense của IDE giúp đỡ cho biết parameter e chứa những dữ kiện gì. Trong .NET, vấn đề handling event không phải là một điều bí hiểm như trong VB6. Khi một control có thể RaiseEvent thì chẳng những một, mà nhiều controls khác đều có thể Đăng ký (Register) để được Thông báo (Notified) khi Event ấy xãy ra. Control RaiseEvent được gọi là Publisher (Nhà Xuất Bản), các controls muốn handle event được gọi là Subcribers (những Người Đặt Mua dài hạn) . Dĩ nhiên cách handle event của mỗi control đều khác nhau, dầu rằng được passed cho cùng hai parameters. Các EventHandlers nầy được gọi là Delegates (những Nhà Đại Diện lãnh trách nhiệm giải quyết một sự cố). Do đó, ta có thể dùng vỏn vẹn một EventHandler để handle nhiều Event khác nhau, xuất phát từ nhiều Objects. Nói cho đơn giản ra, sau khi ta đã đăng ký một hay nhiều Delegates (tức là EventHandler Subs), thì khi Event xảy ra, các EventHandler Subs ấy sẽ được xử lý. Nếu bạn vẫn còn thấy khó hiểu thì hãy đọc thí dụ nầy. Tưởng tượng bạn làm biếng nấu ăn nên đặt nhà hàng giao cơm mỗi ngày đến tận nhà. Có hai cách để bạn nhận "gà-mên" cơm: 1. Người giao cơm sẽ để "gà-mên" cơm trước nhà, cạnh bên hộp thư. Khi đi làm về, bạn sẽ mang nó vô nhà. Trong trường hợp nầy bạn xử lý công việc khi nào tiện, tức là lúc về đến nhà. Cách nầy có điểm bất lợi là hôm nào bạn đi làm về trể thì cơm có thể bị thiêu vì trời nóng. 2. Bạn đưa chìa khóa nhà cho người giao cơm giữ. Khi giao cơm, người ấy sẽ tự động mở cửa vô nhà để "gà-mên" thẳng vào trong tủ lạnh. Trong cách nầy Event GiaoCơm được handled bằng EventHandler Sub OpenDoorPutIntoFridge, do người giao cơm xử lý, chớ không phải chính bạn. Như thế, là Subscriber (người ăn cơm tháng giao tận nhà) bạn register EventHandler "Sub OpenDoorPutIntoFridge" với người giao cơm qua việc đưa chìa khóa. Khi Event "GiaoCơm" xãy ra, người giao cơm tự động executes Sub OpenDoorPutIntoFridge. Kỹ thuật giao AddressOf Sub cho một Object khác để nó execute khi cần còn có tên là CallBack. Do đó, ngay cả trong lúc runtime (không phải khi design), để Register EventHandler Sub MenuItem4_Click với system để handle Event Click của MenuItem4 ta có thể execute code: AddHandler MenuItem4.Click, AddressOf MenuItem4_Click Trang 36
  37. Lưu ý cách ta dùng control ToolTip1 để register Tooltip Text với Listbox1. Ta có thể dùng chỉ một control ToopTip1 để register nhiều Tooltip Texts với những controls khác nhau như TextBox, ComboBox .v.v Bạn có thể thay thế hàng: AppPath = VB6.Left(AppPath, Pos) bằng AppPath = AppPath.SubString(0,Pos) Trong VB6, Visual components của một form được chứa dưới dạng Text diễn tả các controls rất dễ đọc ở ngay đầu form file, nhưng nó không phải là VB6 code. Trong .NET, Visual components của một form được chứa dưới dạng code thật sự. Tức là, nếu không có VS.NET ta có thể dùng Notepad viết code như thế và sau khi compile, nó vẫn chạy y hệt như trong trường hợp ta dùng VS.NET. Điểm nầy giống như trong Java, ta có thể viết code bằng Notepad và dùng Command line để compile và link code file với các components khác. Thí dụ như khi ta viết một VB.NET program đơn giản để chạy trên trong DOS Console, ta có thể compile nó như sau: vbc /t:exe /r:system.dll mysource.vb vbc là VisualBasic Compiler, /t: có nghĩa target tức là EXE để chạy trong DOS console. /r: có nghĩa reference đến DLL. Nếu muốn chạy trong Windows, ta dùng: vbc /t:winexe /r:system.dll /r:system.windows.forms.dll mysource.vb Bình thường generated code được dấu trong Region để khỏi choán chỗ, hay khêu gợi chúng ta sửa đổi. Click dấu + bên lề trái để mở một Region hay Sub/Function. Click dấu - để đóng lại. Đôi khi ta cũng có thể Edit generated code, nhưng bạn nhớ backup code trước, để rủi form không thể hiển thị vì bị error, chỉ cho ta một trang giấy trắng, thì ta còn có đường restore. Trang 37
  38. Mỗi class đều có ít nhất một Sub New, gọi là Constructor (giống như Class_Initialize của VB6 class) và Sub Dispose, gọi là Destructor. Đó là hai Sub dùng để tạo ra và phá hủy Object. Vì Form1 thừa kế từ Standard Form nên trong Sub New trước hết phải gọi constructor MyBase.New() của cha nó, và trong Sub Dispose sau hết phải gọi destructor MyBase.Dispose của cha nó. Mở Class View Window Trang 38
  39. Hình 2.19 : đối tượng Class View Bạn có thể Navigate trong Code qua Class View. DoubleClick lên tên của Object hay Sub/Function trong Class View để mang cursor đến code của nó trong trang Edit. Trang 39
  40. Biểu diển DragDrop Hình 2.2. :Biểu diển DragDrop Code của DragDrop, lưu ý ta phải viết thêm Sub ListBox2_DragEnter để handle Event DragEnter. Private Sub ListBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseDown ' Start the DragDrop process Dim ItemIndex As Integer ' Identify the Listbox item that has mousedown using mouse coordinates ItemIndex = ListBox1.IndexFromPoint(New System.Drawing.Point(e.X, e.Y)) ' Start the DragDrop process passing along the ListboxItem as ListBox1.Items(ItemIndex) ListBox1.DoDragDrop(ListBox1.Items(ItemIndex), DragDropEffects.Copy Or DragDropEffects.Move) End Sub Private Sub ListBox2_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragEnter ' Apply the copy effect ' AND remember to set the property Allow Drop of Listbox2 to TRUE If (e.Data.GetDataPresent(DataFormats.Text)) Then Trang 40
  41. e.Effect = DragDropEffects.Copy Else e.Effect = DragDropEffects.None End If End Sub Private Sub ListBox2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragDrop Dim LItem As String ' Obtain the Source ListItem String LItem = e.Data.GetData(DataFormats.Text).ToString ' Add it to Listbox2 ListBox2.Items.Add(LItem) ' Remove the Item from Listbox1 ListBox1.Items.RemoveAt(ListBox1.FindString(LItem)) End Sub Khi Load data vào Listbox ta dùng StreamReader để Open một File as Input. Khi Save data của Listbox vào một Text file ta dùng StreamWriter để Open một File as Output (hay Append nếu ta cho thêm Option Append=True): Private Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem2.Click ' Read the list of animals from a text file into Listbox2 Dim sr As StreamReader Dim Pos As Integer Dim TStr As String ListBox2.Items.Clear() ' Clear Listbox2 ' Use a StreamReader to open the UTF-8 file to read. sr = New StreamReader(AppPath & "animals.txt") Trang 41
  42. ' Read each line in the file. ' When the end of the file is reached, return the value "-1". Dim x As String While sr.Peek <> -1 x = sr.ReadLine() ' Read a line ListBox2.Items.Add(x) ' Add it to Listbox2 End While sr.Close() ' Close the file EndSub Private Sub SaveAnimalList() ' Save the content of Listbox2 into a UTF-8 Text file Dim i As Integer Dim sw As StreamWriter ' Open the file to write in UTF-8 mode, using a StreamWriter. sw = New StreamWriter(AppPath & "Animals.txt") ' Write each line in the Listbox. For i = 0 To ListBox2.Items.Count - 1 sw.WriteLine(ListBox2.Items(i)) Next sw.Close() ' Close the file End Sub Ta hiển thị ngày và giờ bằng cách dùng Timer1 và Shared Function DateTime.Now formated bằng hai Functions có sẵn ToLongDateString và ToLongTimeString. Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick ' Display Date and Time every half a second Label3.Text = DateTime.Now.ToLongDateString & " " & DateTime.Now.ToLongTimeString Trang 42
  43. End Sub Bạn cũng có thể hiển thị ngày giờ trong format khác bằng cách viết: Label3.Text = DateTime.Now.ToString("ddd dd/MM/yyyy hh:mm:ss") để có: WED 18/07/2001 09:16:42 Để ý trong Format string ta dùng MM cho Month và mm cho Minute. Trang 43
  44. Bài 3 NHỮNG CHỨC NĂNG ĐỐI TƯỢNG MỚI CỦA VB.NET MÃ BÀI: ITPRG23.3 Mục tiêu thực hiện: - Tiếp cận với các chức năng mới của VB.net - Viết được code cho chương trình Vb.net - Tạo được các Class mới - Hiểu và sử dụng tính kế thừa trong VB.net Nội dung: Classes và Objects, nguyên tắc Abstraction Fields, Properties, Methods và Events, nguyên tắc Encapsulation Inheritance (Thừa Kế) Polymorphism (Đa dạng) Tạo một Class mới Overloading methods Object Lifecycle Thừa kế Ngăn cản Thừa kế Thừa kế và Phạm vi hoạt động Protected Methods Overriding Methods Overridding Method New Tạo BaseClasses và Abstract Methods Shared class members ( Các thành viên để dùng chung của class) Early Binding hay Late Binding (Hiệu lực Sớm hay Trễ) Thừa kế từ một ngôn ngữ khác Thừa kế hình ảnh (Visual Inheritance) Trang 44
  45. V B.NET khắc phục những giới hạn về Đối Tượng (Object-Oriented) của VB6 và mang đến cho ta một ngôn ngữ lập trình hoàn toàn Object-Oriented (OO). Gần như mọi thứ trong VB.NET đều liên hệ với Object. Nếu bạn còn mới với lập trình theo hướng đối tượng (Object Oriented Programming) thì phần giải thích sau đây sẽ giúp bạn làm quen với nó. a. Classes và Objects, nguyên tắc Abstraction Theo phương pháp đối tượng, program được thiết kế để một phần code đại diện cho một vật tương đương ngoài đời. Nó được gọi là Class. Khi lập trình VB6 ta đã dùng những controls từ Toolbox như Textbox, Label, Listbox v.v Textbox là Class của các Objects Text1, Text2. Cũng như Label1, Label2 là những Objects tạo ra từ Class Label. Ta hay dùng hai từ Class và Object lẫn lộn nhau. Điều đó không quan trọng, miễn là ta biết rằng Class là một ý niệm Trừu tượng (Abstraction), còn Object là một vật thực hữu. Giống như Class CaSĩ là một ý niệm trừu tượng, còn Object KhánhHà của Class CaSĩ là một người bằng da, bằng thịt với tiếng hát được nhiều người ngưỡng mộ. hình 3.1 :Classes và Objects Ta nói Object là một Instance của Class, và ta instantiate Class để có một Object. Thường thường khi ta phân tích một vấn đề để thiết kế chương trình thì các Danh từ (Nouns) là những Classes. Giả dụ ta phân tích hoạt động của một Nhà Kho (warehouse). Ta có phòng chứa, ngăn tủ, bãi nhận hàng, xe nâng hàng, nhân viên v.v., mỗi thứ đều có thể là một Object nên ta sẽ thiết kế một Class cho nó. Fields, Properties, Methods và Events, nguyên tắc Encapsulation Class CaSĩ diễn tả CaSĩ là người như thế nào. Như SốBàiHát là một Public Variable của Class, được gọi là Field có thể được đọc/viết trực tiếp. Còn Kiểu tóc (dài, ngắn, màu đen, có sọc nâu ), Giọng hát (cao, trầm, ). là những Properties. Chúng cũng giống như Field nhưng được implemented (thi hành) bằng cách dùng procedures Property Get và Property Set. Property Set có thể được coded để kiểm soát nếu "Kiểu tóc" không thích hợp thì sẽ bị loại bỏ. Ngược lại, nếu "Kiểu tóc" thích hợp và được áp dụng thì ta sẽ thấy kết quả ngay là CaSĩ lại đẹp thêm ra. Thường thường Fields và Properties là các Danh từ (Nouns). Trang 45
  46. Một CaSĩ có khả năng ĐơnCa, KýTênLưuNiệm, TrìnhDiễn. Ta gọi đó là những Methods mà ta implemented bằng Subs và Functions (thí dụ như Function KýTênLưuNiệm sẽ return một chữ ký). Thường thường Methods là những Động từ (Verbs) Đối với code bên trong Class thì Property giống như một Method còn đối với Client (tức là program đang dùng Class) thì Property giống như Field. Đôi khi, nếu trình diễn lâu, CaSĩ cần một ly nước. CaSĩ sẽ Raise Event KhátNước để nhân viên trong hậu trường phục vụ. Ta gọi chung Fields, Properties, Methods và Events là những Class Members (Các Thành viên của Class) Có một ngoại lệ về sự khác biệt giữ Class và Member, đó là khi ta dùng các Shared Class Members của một Class thì ta không nhất thiết phải instantiate một Object. Ta có thể dùng thẳng tên của Class như một Object. Cái lợi điểm của Object Oriented Programming là ta có thể gói tất cả những đặc điểm, khả năng của một Class vào trong một Unit of Code (Đơn vị mã) tự túc. Khi chúng ta lịch sự yêu cầu thì CaSĩ ĐơnCa. Ta biết CaSĩ ca thì thu hút lòng người, nhưng ta không cần biết làm sao CaSĩ đạt đến trình độ như vậy. Đó không phải là chuyện để chúng ta quan tâm. Đối với ta Class CaSĩ là một Black Box, ta không biết và không cần biết chuyện gì xãy ra bên trong. Nếu sau nầy CaSĩ thay đổi kỹ thuật đơn ca để hát dễ và hay hơn, điều đó không ảnh hưởng gì đến chúng ta. Đặc tính OO ấy gọi là Encapsulation (Gói kín). hình 3.2 :Encapsulation (Gói kín). Cách ta lập trình với Class chỉ khác cách ta lập trình trước đây một chút thôi. Nếu trước đây ta phải tự làm, thì bây giờ ta instantiate một Object của Class chuyên trị những chuyện ta muốn làm, rồi bảo nó làm cho ta. So với ngoài đời, thí dụ bạn có mở một tiệm photocopy. Sau một năm bạn tự trông coi, công chuyện làm ăn ổn định và có kết quả tốt. Bạn muốn mở thêm một tiệm photocopy nữa ở chỗ khác. Trước khi đi lo chỗ khác bạn huấn luyện nghề photocopy cho Trang 46
  47. một người làm công trung thành, rồi giao cho người ấy làm quản lý để thay thế bạn. Người đó là môt Object của Class QuảnLýTiệmPhotoCopy. Trở lại cách lập trình, những công việc bạn làm hằng ngày trong tiệm photocopy là những Methods. Tất cả đồ đạc, sổ sách của tiệm là những Properties. Bạn đã sắp đặt mỗi tuần phải gọi người lại quét dọn tiệm, mỗi tháng phải bảo trì các máy photocopiers, đó là những Events. Bây giờ bạn gói tất cả những thứ ấy lại thành Class QuảnLýTiệmPhotoCopy. Lần đầu bạn instantiate Class QuảnLýTiệmPhotoCopy làm thành ChúTưThông, người sẽ thay thế bạn làm quản lý tiệm photocopy đầu tiên. Khi bạn muốn mở thêm tiệm thứ ba, bạn sẽ instantiate Class QuảnLýTiệmPhotoCopy một lần nữa làm thành DìSáuHương , người sẽ thay thế bạn làm quản lý tiệm photocopy thứ nhì. Khi đã phân chia trách nhiệm các phần code thành những Class, bạn có thể tập trung tư tưởng vào từng Class một, không cần phải cố nhớ mọi thứ trong đầu khi giải quyết chuyện gì. Vì code của Class nào chỉ làm việc và ảnh hưởng trong phạm vi hoạt động của nó, không đụng chạm đến ai khác. Nếu có gì trục trặc, thường thường ta có thể xác định đó là lỗi của Class nào tương đối dễ dàng. Có một câu hỏi đùa rằng theo phương pháp OO thì: "Thay một bóng đèn cần bao nhiêu programmers?". Đáp: "Không cần programmer nào hết, bạn bảo đèn tự thay bóng của nó." (Lời đáp khác: "Không cần programmer nào hết, Microsoft đã đổi tiêu chuẩn ra bóng đêm.") Do đó, nếu trước kia bạn lập trình để tự mình lo liệu công chuyện thì bây giờ hãy giao cho các Objects tự lo cho chúng. Tức là trước đây, nếu bạn là chủ điền mỗi năm bạn phải đi góp lúa ruộng, thì bây giờ bạn bảo các tá điền phải tự đem nộp lúa vào trong kho cho bạn. Sướng không? Chỉ ở trong thế giới lập trình OO, ta mới có thể mơ mộng như vậy. Inheritance (Thừa Kế) Nguyên tắc Encapsulation nói trên cho phép ta dùng nhiều Objects của một hay nhiều Classes một cách an toàn, tức là không sợ Methods của các Objects giẫm chân lên nhau. Giả sử ta muốn dùng lại một Class để làm một Class mới, đặc biệt hơn, thí dụ như ta muốn làm nên một Class CaSĩ từ Class NghệSĩ. Cách làm ấy gọi là Inheritance (Thừa kế). Công việc thừa kế nầy được thực hiện qua một quá trình gọi là Subclassing. Ở đây ta dùng lại Class NghệSĩ mà hoàn toàn không đụng đến Source Code (Nguồn Mã) của Class NghệSĩ. Nguyên tắc ấy gọi là Reusability (Dùng lại). Lưu ý là nếu ta dùng lại Source code mà có sửa đổi một chút trong Source Code thì không thể gọi là Reuse được vì có thể việc sửa đổi Source Code đó sẽ gây ra bugs mới. Ta phải chỉ cần Inherit từ Object Code của một Class cũng được thì mới thật sự là Reuse. Ta dùng Inheritance để cho thêm các Class Members, tức là thêm đặc tính và chức năng. Thí dụ NghệSĩ thì có Property TâmHồn (NhạyCảm (Sentitive) , ThơMộng (Romantic), ), và Methods KýTênLưuNiệm, TrìnhDiễn. Class CaSĩ sẽ giữ y các đặc tính và chức năng ấy và thêm Sub ĐơnCa, Function HátNhạcYêuCầu, .v.v Tương tự như vậy, ta cũng có thể thừa kế từ Class NghệSĩ để tạo ra Class HọaSĩ. Class HọaSĩ sẽ giữ y các đặc tính và chức năng của Class NghệSĩ nhưng thêm Function VẽChânDung, Sub TrangTrí. Trong thí dụ nói trên, người ta gọi Class NghệSĩ là Parent Class, Super Class hay Base Class. Còn Class CaSĩ và Class HọaSĩ được gọi là Child Class hay SubClass. Trang 47
  48. hình 3.3 : inheritance Nếu ta lại Inherit Class CaSĩ để tạo ra Class CaSĩTânNhạc và Class CaSĩCổNhạc thì trong trường hợp nầy CaSĩ là Parent Class và CaSĩTânNhạc với CaSĩCổNhạc là Child Classes. Mỗi Casĩ là một NghệSĩ nên ta có mối liên hệ "IS (Là)" giữa hai classes nầy. Nó khác với mối liên hệ "HAS (Có)". Thí dụ nếu trong Class CaSĩ có một Object thuộc Class ĐầuBếp, thì một CaSĩ có thể cho ta một bữa ăn ngon nhưng không hẳn cho chính CaSĩ nấu. Nó giống như ngoài đời CaSĩ KhánhHà mướn một đầu bếp để đãi khách. Ta sẽ nói Class CaSĩ có mối liên hệ HAS (Có) với Class ĐầuBếp trong trường hợp nầy, chớ không phải Class CaSĩ IS (Là) một Class ĐầuBếp. Trong .NET ta chỉ có Single (Đơn) Inheritance, tức là một Class không thể Inherit từ hai hay ba Classes khác. Giống như nói Con thừa kế từ Cha và Cha thừa kế từ ÔngNội, không có nhắc gì đến Mẹ hay BàNội. Một Child Class chỉ có một Parent Class, ngược lại, một Parent Class có thể có nhiều Child Classes. Polymorphism (Đa dạng) Polymorphism là khả năng dùng Class Members trùng tên của Objects thuộc về các Classes khác nhau. Thí dụ Objects KháchHàng và NhânViên đều có Property Name. Nếu ta có thể lập trình để dùng Name mà không cần nói rõ nó thuộc về Object KháchHàng hay NhânViên thì đó là Polymorphism. Polymorphism thể hiện dưới nhiều hình thức: 1. Late Binding (Hiệu lực trễ): Có nghĩa là đợi đến giờ chót, khi execution, thì code mới biết nó đang làm việc với loại Object nào. Chữ binding nói đến "hiệu lực", late binding là có hiệu lực trễ. Điều nầy được thực hiện bằng cách hứa hẹn một Object thuộc Parent Class để trong lúc Trang 48
  49. runtime ta có thể giao cho code một Object thuộc Child Class. Thí dụ ta hứa với khán giả sẽ có một CaSĩ trình diễn, lúc mở màn ta có thể cung cấp một CaSĩTânNhạc hay một CaSĩCổNhạc. hình 3.4 : Late binding 2. Overloading (Quá tải, đã có rồi mà còn cho thêm) : Overloading cho phép ta viết trong cùng một Class nhiều versions khác nhau của Property hay Method. Chúng được phân biệt nhờ dùng parameters khác data type hay con số parameters khác nhau. Thí dụ một version của Sub được passed cho một Integer Parameter, một version khác được passed cho một String Parameter, một version khác lại được passed cho hai parameters. Khi ta gọi một Method của Class, nó sẽ dựa vào data type của parameters ta pass và số parameters ta pass để execute đúng version của Method. Một thí dụ về Overloading ngoài đời là khi ta yêu cầu CaSĩ đơn ca ta được phép đề nghị CaSĩ hát theo Karaoke, hay được Ban Nhạc Sống phụ họa, hay thêm cả một nhóm ca sĩ khác phụ họa .v.v 3. Overriding (Lấn quyền) : Overriding áp dụng cho Child Class đối với Parent Class. Trong Child Class ta cung cấp một Method cùng tên, cùng số parameters và cùng parameter data type với một Method trong Parent Class (ở đây không nhất thiết phải là Cha, có thể là ÔngNội hay nhiều đời trước) để dùng nó thay thế cho Parent Class Method. Ta nói Child Class thay đổi behaviour (tánh tình, cách xử sự) của Parent Class. Đại khái giống như cụ LữLiên trước đây Hát nhạc hài hước, bây giờ cô KhánhHà thừa kế từ cụ nhưng override Method Hát của cụ và cô implement một Method Hát mới dùng cho nhạc trử tình. Lúc runtime, nếu một Object không có implementation của một Method thì CLR (Common Language Runtime) sẽ dùng Method của Parent Class của nó. Trong thí dụ trên vì cô KhánhHà có một implementation cho method Hát nên system sẽ dùng method đó, thay vì dùng method Hát của cụ LữLiên. Tạo một Class mới Bạn tạo một Class mới trong VB.NET IDE bằng cách dùng Menu Command Project | Add Class. Dialog Add New Item sẽ hiện ra, chọn Class trong số hình các Icons nằm trong khung bên phải của Dialog. Trang 49
  50. hình 3.5 : add new item Source code của Class mới nầy sẽ được chứa trong một VB source file với extension vb. Trong VB.NET tất cả mọi VB source files đều có extension .vb. System sẽ nhận diện ra loại VB file (form, class, module,.v.v ) nhờ đọc content của file, chớ không dựa vào file extension. Nếu bạn muốn đặt tên cho Class mới nầy là TheClass chẳng hạn, thì bạn có thể sửa tên nó trong Dialog. Khi bạn click button Open một file mới sẽ được cho thêm vào trong Project và nó chứa hai hàng code sau: Public Class TheClass End Class a) Class Keyword Trong một .vb file ta có thể viết nhiều Classes, code của mỗi Class nằm trong một Class End Class block. Thí dụ: Public Class TheClass Public Sub Greeting() MessageBox.Show("Hello world", MsgBoxStyle.Information, "TheClass") End Sub End Class MessageBox.Show và MsgBoxStyle.Information trong VB.NET thay thế MsgBox và vbInformation trong VB6. Trang 50
  51. b) Classes và Namespaces Nhắc lại là .NET dùng Namespace để sắp đặt các Classes cho thứ tự theo nhóm, loại. Namespaces được declared với một Block Structure giống như sau: Namespace Vovisoft Public Class TheClass Public Sub Greeting() MessageBox.Show("Hello world", MsgBoxStyle.Information, "TheClass") End Sub End Class End Namespace Muốn nói đến bất cứ Class, Structure, hay thứ gì được declared bên trong một Namespace End Namespace block ta phải dùng tên Namespace trước. Thí dụ: Private myObject As Vovisoft.TheClass Một source file có thể chứa nhiều Namespaces, và bên trong mỗi Namespace lại có thể có nhiều Classes. Ngoài ra, Classes thuộc về cùng một Namespace có thể nằm trong nhiều files khác nhau trong một VB.NET project. Thí dụ ta có một source file với code như sau: Namespace Vovisoft Public Class TheClass ' Code End Class End Namespace Và một source file khác trong cùng project với code: Namespace Vovisoft Public Class TheOtherClass ' Code End Class End Namespace Trang 51
  52. Vậy thì trong Namespace Vovisoft ta có hai Classes TheClass và TheOtherClass. Nhớ là, by default, Root Namespace của một VB.NET project là tên của project ấy. Khi ta dùng Namespace block structure là chúng ta đang thêm một tầng tên vào Root Namespace. Do đó, trong thí dụ trên nếu tên project là MyProject thì, từ bên ngoài project ấy, ta có thể declare một variable như sau: Private myObject As MyProject.Vovisoft.TheClass c) Tạo ra Methods Methods trong VB.NET có hai thứ: Sub và Function. Function thì phải return một kết quả. By default, parameters của Method là ByVal chớ không phải ByRef. Tức là nếu muốn parameter nào ByRef thì phải nhớ khai ra rõ ràng. Nhắc lại là khi một variable được passed vào trong một method bằng ByVal thì system cho method đó một copy (bản sao) của variable, do đó, trị số của variable không bị thay đổi bởi công tác của method. Ngược lại, nếu một variable được passed vào trong một method bằng ByRef thì method dùng chính variable đó, do đó, trị số của variable có thể bị thay đổi bởi công tác của method. Ta có thể giới hạn việc sử dụng một method bằng cách áp đặt một Access Modifier (sửa đổi quyền truy nhập) hay còn gọi là Scoping keyword (phạm vi hoạt động): Private - chỉ cho phép code trong cùng Class được gọi. Friend - chỉ cho phép code trong cùng project/component được gọi. Public - cho phép ai gọi cũng được. Protected - cho phép code trong subclasses (classes con, cháu) được gọi. Protected Friend - cho phép code trong cùng project/component hay code trong subclasses được gọi. d) Tạo ra Properties Trong VB.NET ta chỉ dùng một routine duy nhất cho mỗi Property, với hai chữ Get và Set như sau (không còn dùng chữ Let của VB6 nữa): Private mdescription As String Public Property Description() As String Set (ByVal Value As String) mdescription = Value End Set Get Description = mdescription End Get End Property Trang 52
  53. e) ReadOnly và WriteOnly property Bây giờ nếu Property là ReadOnly ta sẽ lấy phần Set ra và viết: Public ReadOnly Property Age() As Integer Get Age = 3 End Get End Property hay WriteOnly ta sẽ ấy phần Get ra và viết: Private _data As Integer Public WriteOnly Property Data() As Integer Set (ByVal Value As Integer) _data = Value End Set End Property f) Default Properties Default Property là property của Object mà program dùng khi ta chỉ cho tên của Object và không nói rõ property nào. Thí dụ trong VB6 khi ta code: TextBox1 = "The house of rising sun" VB6 hiểu rằng ta muốn dùng Default Property text của Textbox1 nên code ấy tương đương với: TextBox1.text = "The house of rising sun" Trong VB6 khi ta dùng keyword Set với tên của Object, thí dụ như: Dim myTextBox As Textbox Set myTextBox = TextBox1 program sẽ hiểu là ta muốn nói đến chính Object myTextBox . Nếu không thì nó biết ta muốn nói đến Object Default Property mà làm biếng code cho rõ ra. Trang 53
  54. Trong VB.NET Default Property phải là một Property array. Một Property array là một property được Indexed (nói đến từng Item bằng con số Index) giống như một array. Lý do chính của sự bắt buộc nầy là để khỏi lẫn lộn giữa hai trường hợp ta nói đến Default property của một Object hay chính Object ấy, vì trong VB.NET ta không còn dùng Set keyword cho Object assignment nữa (ta chỉ còn dùng keyword Set trong Property mà thôi). Bây giờ hễ muốn nói đến Default Property của Object thì phải dùng Index. Thí dụ để nói đến chính Object, ta code: myValue = myObject để nói đến Default Property Item 3 của Object, ta code: myValue = myObject(3) Sự thay đổi từ VB6 nầy có nghĩa là một property array procedure phải nhận một parameter. Thí dụ: Private theData(100) As String Default Public Property Data(ByVal Index As Integer) As String Get Data = theData(Index) End Get Set(ByVal Value As String) theData(Index) = Value End Set End Property Từ nay ta không thể code: TextBox1 = "Good morning!" như trong VB6 được nữa, mà phải code: TextBox1.text = "Good morning!" Vì Property Text không còn là Default Property của TextBox. Overloading methods Một trong những chức năng đa diện (Polymorphism) hùng mạnh nhất của VB.NET là overload (quá tải, có rồi mà còn cho thêm) một method. Overloading có nghĩa là ta có thể dùng cùng một Trang 54
  55. tên cho nhiều methods - miễn là chúng có danh sách các parameters khác nhau, hoặc là parameter dùng data type khác nhau (td: method nầy dùng Integer, method kia dùng String), hoặc là số parameters khác nhau (td: method nầy có 2 parameters, method kia có 3 parameters). Overloading không thể được thực hiện chỉ bằng cách thay đổi data type của Return value của Function. Phải có parameter list khác nhau mới được. Dưới đây là thí dụ ta dùng Overloading để code hai Functions tìm data, một cái cho String, một cái cho Integer: Public Function FindData(ByVal Name As String) As ArrayList ' find data and return result End Function Friend Function FindData(ByVal Age As Integer) As ArrayList ' find data and return result End Function Để ý là ta có thể cho mỗi overloading Function một phạm vi hoạt động (Scope on implementation) khác nhau. Trong thí dụ trên ta dùng Access Modifier Public cho Function đầu và Friend cho Function sau. Object Lifecycle Object Lifecycle (cuộc đời của Object) được dùng để nói đến khi nào Object bắt đầu hiện hữu và khi nào nó không còn nữa. Sở dĩ ta cần biết rõ cuộc đời của một Object bắt đầu và chấm dứt lúc nào là để tránh dùng nó khi nó không hiện hữu, tức là chưa ra đời hay đã khuất bóng rồi. g) New method Trong VB6, khi một Object thành hình thì Sub Class_Initialize được executed. Tương đương như vậy, trong VB.NET ta có Sub New(), gọi là Constructor. VB.NET bảo đảm Sub New() sẽ được CLR gọi khi Object được instantiated và nó chạy trước bất cứ code nào trong Object. Nếu Sub Class_Initialize của một Class Object trong VB6 không nhận parameter thì Sub New() trong VB.NET chẳng những có nhận parameters mà còn cho phép ta nhiều cách để gọi nó. Sự khác biệt trong Constructors của VB6 và VB.NET rất quan trọng. Tưởng tượng ta có một Khuôn làm bánh bông lan; khuôn là Class còn những bánh làm ra từ khuôn sẽ là các Objects bánh bông lan. Nếu ta muốn làm một cái bánh bông lan với một lớp sô- cô-la trên mặt thì công tác sẽ gồm có hai bước: 1. Dùng khuôn (Class) nướng một cái Object bánh bông lan (dùng Sub Class_Initialize) 2. Đổ lên mặt bánh một lớp sô-cô-la (dùng class Public Sub ThoaSôcôla) Đến đây, mọi chuyên tương đối ổn thỏa. Bây giờ, nếu khách hàng muốn một cái bánh bông lan dùng trứng vịt thay vì trứng gà thì ta chịu thua thôi, vì không có cách nào bảo Sub Class_Initialize dùng trứng vịt thay vì trứng gà ngay trong lúc đang tạo dựng ra Object bánh bông lan. Trang 55
  56. Sub New() trong VB.NET có thể nhận parameters nên nó có thể nhận chỉ thị để dùng trứng vịt ngay trong lúc nướng cái Object bánh bông lan. Cái dạng đơn giản nhất của Sub New() mà ta có thể dùng là không pass parameter nào cả (trong trường hợp nầy thì giống như Sub Class_Initialize của VB6). Ta code Sub New() trong Class như sau: Public Class BanhBongLan Public Sub New() ' Code to initialise object here End Sub End Class Ta instantiate một Object bánh bông lan như sau: Dim myBanhBongLan As New BanhBongLan() Để cho Users có sự lựa chọn khi instantiate Object, ta có thể code thêm những Sub New khác, mỗi Sub dùng một danh sách parameter khác nhau. Thí dụ: Public Class BanhBongLan Public Sub New() ' Code to initialise object here End Sub Public Sub New(ByVal LoaiTrung As String) Select Case LoaiTrung Case "Vit" ' Code for TrứngVịt here Case "Ga" ' Code for TrứngGà here End Select End Sub End Class Trang 56
  57. Dùng cùng một tên method để implement nhiều methods khác nhau được gọi là overload. Đó là một trường hợp đa dạng (polymorphism) của OO programming. Trong thí dụ trên nếu TrứngVịt và TrứngGà là hai loại Data Types khác nhau thì ta cũng có thể dùng: Sub New (ByVal TrứngVịt As TrứngVịtDataType) để instantiate bánh TrứngVịt và Sub New (ByVal TrứngGà As TrứngGàDataType) để instantiate bánh Trứng Gà. Như thế ta khỏi bận tâm với Select Case LoaiTrung khi chỉ dùng một Sub New duy nhất với 1 parameter. Trong VisualStudio.NET, khi ta dùng tên của một overloaded method, IntelliSense sẽ hiển thị để hướng dẫn ta đánh vào parameter list khác nhau tùy theo method ta chọn. h) Termination Trong VB6 một Object sẽ bị huỷ diệt khi cái reference (chỗ dùng đến Object) cuối cùng bị lấy đi. Tức là khi không có code nào khác dùng Object nữa thì Object sẽ bị tự động huỷ diệt. System giữ một counter để đếm số clients đang dùng Object. Cách nầy hay ở chỗ khi counter trở thành 0 thì Object bị huỷ diệt ngay. Ta nói nó có deterministic finalization, nghĩa là ta biết rõ ràng khi nào Object biến mất. Tuy nhiên, nếu ta có hai Object dùng lẫn nhau (gọi là circular references), thì ngay cả đến lúc chúng không còn hoạt động nữa, chúng vẫn hiện hữu mãi trong bộ nhớ vì cái Reference counter của cả hai Objects không bao giờ trở thành 0. Nếu trường hợp nầy xảy ra thường lần lần system không còn memory nữa, ta gọi đó là memory leak (bị rỉ bộ nhớ) . .NET dùng phương pháp khác để quản lý chuyện nầy. Cứ mỗi chốc, một program sẽ chạy để kiểm xem có Object nào không còn reference nữa để huỷ diệt. Ta gọi đó là Garbage Collection (nhặt rác). Ngay cả trường hợp hai Objects có circular references nhưng nếu không có code nào khác reference một trong hai Objects thì chúng cũng sẽ được huỷ diệt. Có điều, công tác nhặt rác chạy in the background (phía sau hậu trường) với ưu tiên thấp, khi CPU rảnh rang, nên ta không biết chắc một Object sẽ bị hủy diệt đến bao giờ mới thật sự biến mất. Ta nói nó có nondeterministic finalization. Ta có thể ép CLR nhặt rác lập tức bằng code: System.GC.Collect() Tuy nhiên, ta chỉ làm việc ấy khi kẹt quá thôi. Tốt hơn, ta duyệt lại design của mình để cho phép các Objects hết xài có thể ngồi chơi trong bộ nhớ chờ đến lúc được hủy diệt. i) Dùng Dispose Method Nếu ta có một Object dùng nhiều tài nguyên (resources) như bộ nhớ, database connection, file handle,.v.v. và ta cần phải thả các tài nguyên ra ngay sau khi Object không còn hoạt động nữa, ta cần implement một Interface tên IDisposable với Implements keyword như sau: Public Class TheClass Implements IDisposable Trang 57
  58. Bạn phải viết code cho Sub Dispose giống như sau: Private Sub Dispose() Implements IDisposable.Dispose ' Viết clean up code ở đây để thả các tài nguyên ra End Sub Sau đó bạn vẫn phải viết code cho Client để nó gọi Dispose Method trong IDisposable interface. Bạn cần phải dùng CType để cast Object Class khi gọi Dispose. Dim objObject As New TheClass() CType (objObject, IDisposable).Dispose() Để lấy đi Reference đến một Object (gọi là Dereference Object) bạn có thể dùng: myObject = Nothing Để ý là ta không có dùng keyword Set như trong VB6. Nhớ là sau khi statement trên được executed thì myObject không biến mất ngay nhưng nó đợi Garbage Collector đến giải quyết. Thừa kế Thừa kế (Inheritance) là khả năng của một Class đạt được interface (giao diện) và behaviours (tánh tình) của một Class có sẵn. Cái quá trình để làm nên việc ấy được gọi là Subclassing. Khi ta tạo ra một Class mới thừa kế cả interface lẫn behaviours từ một Class có sẵn là chúng ta đã tạo ra một subclass của Class nguyên thủy. Người ta nói đó là một mối liên hệ is-a (là một), ý nói Class mới là một loại Class nguyên thủy. Ta phân biệt mối liên hệ is-a với mối liên hệ has-a (có một). Trong mối liên hệ has-a, Object chủ có thể làm chủ một hay nhiều Objects tớ, nhưng Object tớ là một loại có thể hoàn toàn khác với Object chủ. Để biểu diễn đặc tính Inheritance ta hãy xét trường hợp một công ty cung cấp Sản phẩm và Dịch vụ. Ta có thể code một Class cho Sản phẩm (ProductLine) và một Class cho Dịch vụ (ServiceLine) , riêng rẽ nhau. Nhưng vì thấy chúng có nhiều điểm tương đồng nên ta sẽ code một Class gọi là Món hàng (LineItem), rồi inherit từ LineItem ra ProductLine và ServiceLine. LineItem có các properties ID, Item, Price (giá) và Quantity (số lượng). Nó cũng có một Public Function để cho Amount (số tiền). Public Class LineItem Private mintID As Integer Private mstrItem As String Private msngPrice As Single Private mintQuantity As Integer Trang 58
  59. Public Property ID() As Integer Get Return mintID End Get Set (ByVal Value As Integer) mintID = Value End Set End Property Public Property Item() As String Get Return mstrItem End Get Set (ByVal Value As String) mstrItem = Value End Set End Property Public Property Price() As Single Get Return msngPrice End Get Set (ByVal Value As Single) msngPrice = Value End Set End Property Public Property Quantity() As Integer Get Return mintQuantity End Get Set (ByVal Value As Integer) mintQuantity = Value Trang 59
  60. End Set End Property Public Function Amount() As Single Return mintQuantity * msngPrice End Function End Class Để tạo Class ProductLine từ Class LineItem ta phải dùng Inherits keyword. Mỗi Object ProductLine là một Object LineItem với ProductID và Description. ProductID của ProductLine được pass vào Sub New lúc instantiate Object ProductLine. Còn Description là một ReadOnly property của ProductLine. Ta có thể code Class ProductLine như sau: Public Class ProductLine Inherits LineItem Private mstrDescription As String Public ReadOnly Property Description() As String Get Return mstrDescription End Get End Property Public Sub New(ByVal ProductID As String) Item = ProductID mstrDescription = "No description yet" ' Default description ' Viết code ở đây để đọc chi tiết của Product từ Database ' trong đó có thể có Description của Product End Sub End Class Statement Inherits LineItem khiến ProductLine thừa kế mọi interface và behaviours của LineItem. Do đó ta có thể code một Sub BtnProduct_Click để hiển thị chi tiết của ProductLine trong một Listbox như sau: Trang 60
  61. Protected Sub BtnProduct_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnProduct.Click Dim pl As ProductLine pl = New ProductLine("P1234") ListBox1.Items.Add("ProductItem:" & pl.Item) ListBox1.Items.Add("Description: $" & pl.Description) End Sub Trong code bên trên ta dùng cả property Item của Class LineItem lẫn property Description của Class ProductLine. Cả hai đều là property của ProductLine vì nó là một SubClass của LineItem. Giống như vậy, một ServiceLine có thể có ghi ngày giờ cung cấp service. Ta code Class ServiceLine như sau: Public Class ServiceLine Inherits LineItem Private mdtDateProvided As Date Public Sub New() ' Make 1 as default number of services of this kind for invoice Quantity = 1 End Sub Public Property DateProvided() As Date Get Return mdtDateProvided End Get Set (ByVal Value As Date) mdtDateProvided = Value End Set End Property End Class Trang 61
  62. Một lần nữa ta dùng Statement Inherits để nói rằng ServiceLine là một SubClass của LineItem. Ta thêm property DateProvided vào interface thừa kế từ Class LineItem. Ngăn cản Thừa kế Bình thường (By default) class nào cũng có thể được dùng làm base class để từ đó ta thừa kế. Nhưng đôi khi ta không muốn cho ai thừa kế từ một Class nào đó, để làm việc ấy ta dùng keyword NotInheritable khi declare class: Public NotInheritable Class KhôngCon End Class Khi ta đã dùng keyword NotInheritable rồi thì không class nào có thể dùng keyword Inherits để tạo một subclass từ class ấy. Thừa kế và Phạm vi hoạt động Khi ta dùng đặc tính thừa kế để tạo một SubClass thì class mới nầy có đủ mọi methods, propertỉes và variables với Access Modifier Public hay Friend của SuperClass. Bất cứ thứ gì declared là Private trong SuperClass thì SubClass không thấy hay dùng được. Có một ngoại lệ là New method. Các Constructor methods cần phải được implemented (định nghĩa) lại trong mỗi SubClass. Một chốc nữa ta sẽ bàn vào chi tiết về điểm nầy. Để làm sáng tỏ vấn đề SubClass có thể dùng Class Members nào của SuperClass, ta thử code lại Function Amount trong LineItem class bằng cách khiến nó gọi một Private Function tên CalculateAmount để tính ra Amount thay vì để nó tính trực tiếp như trước đây: Public Function Amount() As Single Return CalculateAmount End Function Private Function CalculateAmount() As Single Return mintQuantity * msngPrice End Function Khi ta SubClass LineItem để tạo ra ServiceLine class, bất cứ Object ServiceLine nào cũng thừa kế Function Amount vì Function ấy được declared Public trong BaseClass LineItem. Ngược lại, vì Function CalculateAmount là Private nên cả ServiceLine class lẫn bất cứ client code nào dùng một LineItem Object đều không truy cập nó được. Như thế, mặc dầu ta gọi Function Amount được, nhưng đến phiên nó gọi Private Function CalculateAmount thì có bị trở ngại không? Không sao cả. Vì Function Amount nằm trong cùng Trang 62
  63. Class với Private Function CalculateAmount nên nó có thể gọi được, dù rằng ta gọi Function Amount từ ServiceLine hay client code. Thí dụ trong client code ta có những hàng code như sau: Protected Sub BtnShowAmount_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnShowAmount.Click Dim Service As ServiceLine Service = New ServiceLine() Service.Item = "Delivery" Service.Price = 50 Service.DateProvided = Now MessageBox.Show (Service.Amount.ToString, "Amount", MessageBoxButtons.OK, MessageBoxIcon.Information) End Sub Kết quả sẽ được hiển thị trong message box, cho thấy Function CalculateAmount được Function Amount gọi dùm cho client code dù rằng cả client code lẫn ServiceLine code đều không thể gọi trực tiếp được. Điểm nầy nhắc tôi nhớ lại khi còn bé, có lần bà con trong vườn đem ra chợ cho ba má tôi cả thúng xoài thơm rất ngon. Bạn tôi ở lối xóm thấy vậy biểu tôi lén lấy hai trái xoài để ăn vụn. Vì không phải là người nhà nên bạn tôi không thể lấy đuợc xoài, bởi Access Modifier của thún xoài là Private trong nhà tôi. Nhưng vì tôi là Public, nên bạn tôi có thể nhờ tôi lấy dùm. Protected Methods Đôi khi Public hay Private thôi chưa đủ. Nếu ta declare thứ gì Private thì nó hoàn toàn giới hạn trong class, ngược lại nếu ta declare nó Public (hay Friend) thì nó có thể được dùng trong subclasses hay client code. Tuy nhiên, có lúc ta muốn một class member chỉ có thể được dùng trong subclasses thôi, chớ không cho client code dùng. Trong trường hợp ấy ta dùng keyword Protected. Thí dụ: Public Class FatherClass Protected DiSản As Single End Class Public Class SonClass Inherits FatherClass Public Function ChiaCủa() As Single Return Disản End Function Trang 63
  64. End Class Ở đây ta có BaseClass FatherClass với Protected Field Disản. Không có client code nào có thể thấy Field DiSản được. Thế nhưng bất cứ SubClass nào của FatherClass cũng đều thừa kế và dùng được DiSản. Trong thí dụ trên, một lần nữa SubClass có một Public method (ChiaCủa) có thể return một protected value - nhưng chính value ấy, DiSản, không trực tiếp cho phép client code dùng. Overriding Methods Chúng ta biết rằng đặc tính quan trọng của Inheritance là một SubClass chẳng những thừa kế behaviours của ParentClass mà còn có thể override (lấn quyền) các behaviours ấy nữa. Chúng ta đã thấy một SubClass có thể extend (thêm ra) ParentClass bằng cách cho thêm các methods Public, Protected và Friend. Hơn nữa, khi dùng overriding, một SubClass có thể alter (sửa đổi) behaviours của các methods trong ParentClass. Bình thường (By default), ta không thể override methods trong ParentClass trừ khi các methods ấy được declared với keyword Overridable trong ParentClass. Thí dụ: Public Class ClassCha Public Overridable Sub ChàoHỏi() MessageBox.Show("Chào các cháu", "Class Cha") End Sub End Class Tiếp theo, khi tạo một SubClass, nếu muốn ta có thể override behaviour của Sub ChàoHỏi bằng cách dùng keyword Overrides như sau: Public Class ClassCon Inherits ClassCha Public Overrides Sub ChàoHỏi() MessageBox.Show("Thưa các Bác", "Class Con") End Sub End Class Bây giờ ta có thể viết client code như sau: Private Sub BtnSubClassObject_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnSubClassObject.Click Dim obj As New ClassCon() Trang 64
  65. obj.ChàoHỏi() End Sub Khi ta click button BtnSubClassObject program sẽ hiển thị message dialog dưới đây: hình 3.6 : message dialog Virtual Methods Tuy nhiên, hãy xem trường hợp ta code như sau: Private Sub BtnParentClassObject_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnParentClassObject.Click Dim obj As ClassCha obj = New ClassCon() obj.ChàoHỏi() End Sub Trước hết, ở đây có vẻ kỳ kỳ, tại sao declare một variable loại ClassCha mà lại instantiate một object ClassCon. Chuyện đó hoàn toàn bình thường, vì ClassCon là một ClassCha. Tức là một variable loại ClassCha hay ClassCon đều có thể chứa, thật ra là hold references to (point to, chỉ tới), một instance của ClassCon. Điểm nầy áp dụng tổng quát khi ta dùng Inheritance. Một variable loại SuperClass có thể hold reference to bất cứ SubClass Object nào thừa kế từ SuperClass ấy. Đó là một cách để ta implement tính đa dạng (polymorphism). Đều có thể làm ta ngạc nhiên là khi ta click button BtnParentClassObject ta cũng thấy hiển thị message " Thưa các Bác". Trang 65
  66. hình 3.7 : hiển thị message Sao lạ vậy? Variable obj được declared là ClassCha tại sao message không phải là "Chào các cháu"? Lý do là Sub ChàoHỏi của ClassCon được gọi thay vì Sub ChàoHỏi của ClassCha. Ta nói Sub ChàoHỏi là Virtual method. Tất cả methods trong VB.NET đều là virtual. Ý niệm virtual để nói rằng cái implementation của con cháu trẻ nhất trong dòng họ được dùng - không cần biết là variable có data type là class của thế hệ nào trong dòng họ. Tức là, nếu variable dùng trong client code hold references to ClassÔngNội, ClassCha, ClassCon hay ClassCháu thì method trong ClassCháu được gọi. Nếu trong ClassCháu không có implementation của method thì ta gọi method trong ClassCon, nếu không có thì gọi method trong ClassCha .v.v theo thứ tự từ bề dưới lên bề trên. Keyword Me Keyword Me được dùng khi ta muốn nói rõ (explicitly) rằng ta muốn dùng method của chính cái Class đang chứa code ấy, chớ không phải một implementation nào khác của method ấy. Cũng có trường hợp ta phải dùng keyword Me để nói ta muốn dùng class-level variable chớ không phải procedure-level variable có cùng tên. Một procedure-level variable, tức là local variable của một method, có cùng tên với một class-level variable được gọi là shadowed variable. Thí dụ: Public Class TheClass Private strName As String Public Sub DoSomething() Dim strName As String strName = "Quang" End Sub End Class Ở đây, variable strName được declared ở class-level và bên trong Sub DoSomething. Bên trong method ấy local variables (kể cả shadowed variables) sẽ được dùng vì chúng che đậy class-level variables trừ khi ta nói rõ rằng phải dùng variable của class-level bằng cách dùng keyword Me: Trang 66
  67. Public Class TheClass Private strName As String Public Sub DoSomething() Dim strName As String strName = "Quang" ' thay đổi value của local (shadowed) variable Me.strName = "Kim" ' thay đổi value của class-level variable End Sub End Class Keyword MyBase Keyword Me rất tiện dụng khi ta muốn dùng Class members của chính Class chứa code. Tương tự như vậy, đôi khi ta muốn dùng Class method của BaseClass (cũng gọi là SuperClass), chớ không phải một implementation của method ấy trong SubClass. Nhớ là một virtual method luôn luôn gọi implementation của Class trẻ nhất. Từ trong một SubClass, nếu muốn gọi một method của BaseClass ta dùng keyword MyBase như sau: Public Class ClassCon Inherits ClassCha Public Overrides Sub ChàoHỏi() MessageBox.Show("Thưa các Bác", "Class Con") MyBase.ChàoHỏi() End Sub End Class Bây giờ nếu ta chạy Sub ChàoHỏi của ClassCon ta sẽ có hai messages, một cái từ ClassCon theo sau bởi một cái từ ClassCha. MyBase chỉ nói đến BaseClass trực tiếp, tức là Class cha thôi chớ không nói đến Class ông nội. Không có cách nào để nói đến hơn một thế hệ. Dầu vậy, keyword Mybase có thể được dùng cho bất cứ thứ gì đã được declared Public, Friend hay Protected trong ParentClass. Điều nầy kể luôn cả những thứ mà ParentClass thừa kế từ các thế hệ trước trong gia đình, tức là ClassÔngNội, ClassÔngCố .v.v Keyword MyClass Vì lý do virtual method, ta sẽ gặp những trường hợp rắc rối như khi code của ParentClass lại chạy code của SubClasses. Khi viết code của một class, từ method nầy ta thường gọi những methods khác nằm trong cùng class. Thí dụ như: Trang 67
  68. Public Class ClassCha Public Sub VôĐề() ChàoHỏi() End Sub Public Overridable Sub ChàoHỏi() MessageBox.Show("Chào các cháu", "Class Cha") End Sub End Class Trong trường hợp nầy, VôĐề gọi Sub ChàoHỏi để đón tiếp. Để ý là vì ChàoHỏi được declared Overridable nên rất có thể một SubClass sẽ implement method ChàoHỏi và lấn quyền nó. Thí dụ: Public Class ClassCon Inherits ClassCha Public Overrides Sub ChàoHỏi() MessageBox.Show("Thưa các Bác", "Class Con") End Sub End Class Vì đặc tính virtual của ChàoHỏi nên ta tưởng ClassCha execute chính Sub ChàoHỏi của nó nhưng té ra nó lại execute code của ChàoHỏi trong ClassCon. Trong code dưới đây, một Object ClassCon gọi Sub VôĐề của ClassCha: Private Sub BtnSubClassObject_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnSubClassObject.Click Dim obj As New ClassCon() obj.VôĐề() End Sub Trong ClassCha, Sub VôĐề gọi ChàoHỏi của chính nó, tuy nhiên Sub ChàoHỏi ấy bị overridden bởi implementation của ChàoHỏi trong ClassCon. Do đó, program sẽ hiển thị message "Thưa các Bác". Nếu ta không muốn như vậy, ta muốn VôĐề execute chính code của ChàoHỏi trong ClassCha thì phải dùng keyword MyClass như sau: Public Class ClassCha Trang 68
  69. Public Sub VôĐề() MyClass.ChàoHỏi() End Sub Public Overridable Sub ChàoHỏi() MessageBox.Show("Chào các cháu", "Class Cha") End Sub End Class Ở đây ta không thể dùng keyword Me vì VôĐề có gọi ChàoHỏi ở class-level trong ClassCha chớ không phải trong một SubClass, nhưng bị overridden. Hình dưới đây minh họa quá trình gọi VôĐề từ client code: hình : 3.8 : minh họa quá trình gọi VôĐề Sub VôĐề thật ra nằm trong ClassCha mà ClassCon thừa kế nên VôĐề được executed trong ClassCha và gọi Sub ChàoHỏi trong cùng class ( ClassCha). Nhưng vì ClassCon có một implementation của Sub ChàoHỏi nên nó overrides ChàoHỏi của ClassCha. Overridding Method New Chúng ta đã thấy ta có thể override methods và dùng các keywords Me, MyBase và MyClass để gọi các overriden methods trong dây chuyền thừa kế. Tuy nhiên, đối với Constructor của class thì có những luật lệ đặc biệt dành riêng cho method New. Những methods New không tự động di truyền từ BaseClass xuống SubClass. Mỗi SubClass phải có một implementation riêng cho Constructor dù rằng, nếu muốn, nó có thể gọi vào BaseClass với keyword MyBase: Public Class ClassCon Inherits ClassCha Public Sub New() Trang 69
  70. MyBase.New() ' để thêm các code khác để initialise tại đây End Sub End Class Khi gọi Constructor của BaseClass, ta phải gọi nó trước nhất - nếu không sẽ bị error. Tuy nhiên ta không cần gọi Constructor của BaseClass vì Constructor của BaseClass được gọi tự động. Có một luật đặc biệt là nếu tất cả methods New trong BaseClass đều đòi hỏi parameters thì ta phải implement ít nhất một method New trong SubClass và ta phải đặt statement MyBase.New ngay phía đầu. Dĩ nhiên là ta có thể Overload method New trong SubClass, nhưng ta phải tự lo liệu cách gọi một method New thích hợp trong BaseClass. Tạo BaseClasses và Abstract Methods Cho đến giờ ta đã bàn về virtual method với đặc tính override trong nguyên tắc thừa kế. Trong các thí dụ trước đây BaseClass được instantiated thành Object để làm chuyện nầy, chuyện kia. Nhưng đôi khi ta muốn tạo một BaseClass chỉ để dùng cho thừa kế mà thôi. Keyword MustInherit (Phải được Thừa Kế) Trở lại cái thí dụ về Inheritance với Class LineItem. Sở dĩ ta đặt ra Class LineItem là vì nó chứa những thứ chung cho cả hai classes ProductLine và ServiceLine. Chớ thật ra một Object của Class LineItem không chứa đủ mọi đặc tính để làm một việc gì thực tế. Nếu ta muốn nói rõ rằng Class LineItem chỉ được dùng để tạo những SubClasses bằng cách thừa kế từ nó, ta có thể declare như sau: Public MustInherit Class LineItem Tức là ta chỉ thêm keyword MustInherit thôi, chớ không thay đổi gì khác. Kết quả là từ nay Client code không thể instantiate một Object từ Class LineItem. Do đó dòng code sau sẽ bị syntax error: Dim myObject As New LineItem() Thay vào đó, nếu muốn dùng LineItem ta phải tạo SubClass từ nó. Trang 70
  71. Keyword MustOverride (Phải bị Lấn Quyền) Tương tự với ý niệm Phải-được-thừa-kế trong Class, ta cũng có MustOverride cho một method. Có thể trong BaseClass ta khai báo một method, nhưng ta đòi hỏi method ấy phải có một implementation trong SubClass. Ta declare như sau: Dim MustOverride Sub CalculatePrice Để ý là ở đây không có thân thể của Sub CalculatePrice hay statement End Sub gì cả. Khi dùng MustOverride ta không được phép cung cấp một implementation cho method trong BaseClass. Một method như thế được gọi là abstract method hay pure virtual function, vì nó chỉ có phần khai báo chớ không có phần định nghĩa. Những abstract methods phải được overridden trong bất cứ SubClass nào của BaseClass thì mới dùng được. Nếu không, ta sẽ không có phần implementation của method đâu cả và khi compile sẽ gặp syntax error. Abstract Base Classes Nếu hợp cả hai ý niệm MustInherit và MustOverride lại ta sẽ tạo ra một abstract base class. Đây là một Class chỉ có khai báo chớ hoàn toàn không có implementation. Ta phải SubClass từ nó thì mới làm việc được, thí dụ như: Public MustInherit Class ClassCha Public MustOverride Sub VôĐề() Public MustOverride Sub ChàoHỏi() End Class Kỹ thuật nầy rất thích hợp để ta code cái sườn hay bố cục của program ngay trong lúc thiết kế. Class nào thừa kế ClassCha thì phải implement cả Sub VôĐề lẫn Sub ChàoHỏi, nếu không sẽ bị syntax error. Nhìn về một phương diện, abstract base class rất giống khai báo Interface. Nếu dùng Interface, chúng ta có thể khai báo như sau: Public Interface ICha Sub VôĐề() Sub ChàoHỏi() End Interface Bất cứ class nào chịu implement interface ICha thì phải implement cả Sub VôĐề lẫn Sub ChàoHỏi, nếu không sẽ bị syntax error - do đó, ta thấy Interface rất giống một abstract base class. Sự khác biệt chính giữa abstract base class với Interface là ở chỗ thừa kế. Khi ta tạo một class con bằng cách SubClass từ ClassCha, chính class con ấy lại cũng có thể được SubClassed. Mấy class cháu nầy sẽ tự động thừa kế VôĐề và ChàoHỏi từ class con. Trang 71
  72. Trong khi ấy nói về Interface, mỗi class phải tự implement ICha một cách độc lập và phải cung cấp hai Subs VôĐề và ChàoHỏi của chính nó. Vì thế, nếu ta không có ý định dùng lại code của các Subs khi ta tạo các classes mới thì ta có thể dùng interface. Ngược lại nếu ta muốn dùng lại code trong SubClass theo nguyên tắc thừa kế thì ta nên dùng abstract base class. Shared class members ( Các thành viên để dùng chung của class) Mặc dù Object rất hiệu năng và hữu ích, có khi ta chỉ muốn truy cập các variables hay methods của một class để làm việc mà không cần phải instantiate một Object nào cả. Tức là y như trong quá khứ, khi viết VB6, ta dùng các variables hay methods của một BAS Module. Đại khái giống như thay vì ký giao kèo với một thầu (Object) để thực hiện một công trình, ta chỉ muốn mướn thợ hay chuyên viên làm việc gia công ( gọi các methods) thôi. Shared Methods Trong VB.NET chẳng những một Class có các methods và properties thông thường như ta đã thấy - tức là những methods và properties của một Object ta có thể dùng ngay sau khi Object ấy thành hình qua quá trình instantiation - mà còn có các methods và properties ta có thể dùng mà không cần phải tạo ra một instance nào từ Class. Chúng được gọi là shared methods. ( Trong các ngôn ngữ lập trình khác các methods nầy còn được gọi là static methods hay class methods). Ta không thể truy cập một shared method qua một Object như method bình thường, nhưng phải dùng trực tiếp tên của class. Thí dụ sau đây sẽ minh họa điều nầy: Public Class Math Shared Function Add( ByVal x As Single, ByVal y As Single) As Single Return x + y End Function End Class Sau khi định nghĩa Class Math, ta có thể dùng Shared Function Add mà không cần instantiate một Object thuộc class Math như sau: Dim Result As Single result = Math.Add(12.5, 36.8) Để ý thay vì dùng một object variable ta dùng thẳng tên của class Math để truy cập method Add. Với một method bình thường thì làm như thế sẽ bị syntax error, nhưng trong trường hợp nầy thì không sao. Ta cũng có thể overload shared methods, tức là có thể code nhiều shared methods với cùng một tên nhưng có những parameter lists khác nhau. Phạm vi hoạt động bình thường (Default Scope) của shared methods là Public. Tuy nhiên ta có thể giới hạn việc truy cập chúng bằng cách dùng những Access Modifiers như Friend, Trang 72
  73. Protected hay Private. Thật ra khi overloading một shared method ta có thể dùng những scopes khác nhau cho mỗi shared method. Có một thí dụ về shared method từ .NET system class libraries. Để mở một text file theo mode input, điển hình ta dùng shared method trong File class như sau: Dim inFile As StreamReader = File.OpenText("words.txt") Dim strIn As String strIn = inFile.ReadLine() Ở đây không có object File nào được tạo ra. Method OpenText là một shared Function, nó mở input text file words.txt và cho ta một object loại StreamReader tên inFile để ta dùng sau đó. Shared Variables Đôi khi ta muốn tất cả objects của cùng một class đều dùng chung một variable. Ta có thể thực hiện việc ấy với shared variables. Một shared variable được khai báo với keyword shared giống như shared method: Public Class MyCounter Private Shared mintCount As Integer End Class Ta có thể cho shared variable một scope Public hay Private tùy ý, nhưng By Default, scope của shared variables là Private, khác với shared methods thì By Default là Public. Điểm quan trọng của shared variables là chúng được dùng chung giữa mọi instances (objects) của cùng một class. Dưới đây là một thí dụ trong đó ta giữ cái counter có trị số tăng thêm 1 mỗi lần có một instance mới của class MyCounter. Bất cứ lúc nào ta cũng có thể biết có bao nhiêu objects đã được tạo ra bằng cách đọc property Count: Public Class MyCounter Private Shared mintCount As Integer Public Sub New() mintCount += 1 End Sub Public ReadOnly Property Count() As Integer Get Trang 73
  74. Return mintCount End Get End Property End Class Như thế, nếu ta chạy client code dưới đây nó sẽ hiển thị kết quả là 3: Protected Sub Button1_Click( ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click Dim obj As MyCounter obj = New MyCounter() obj = New MyCounter() obj = New MyCounter() MsgBox(obj.Count, MsgBoxStyle.Information, "Counter") End Sub Nếu ta chạy code thêm hai lần nữa, ta sẽ có 6 và 9. Hể ta còn chạy chương trình thì cái counter còn làm việc. Khi ta chấm dứt chương trình thì cái counter sẽ biến mất. Global values Một cách dùng rất thông dụng khác của shared variable là xem nó như một loại Global variable. Khi dùng scope Public ta sẽ có một dạng tương đương với VB6 Global variable trong một BAS Module. Thí dụ như: Public Class GlobalData Public Shared TotalCost As Single End Class Sau đó ta có thể dùng variable nầy khắp nơi trong client code: GlobalData.TotalCost += 45.60 Trang 74
  75. Raising Event để xử lý trong một Project khác VB.NET không hổ trợ Events từ đời cha đến đời con theo đúng nguyên tắc thừa kế. Nếu một BaseClass định nghĩa một Public Event thì ta chỉ có thể raise event ấy trong code của BaseClass thôi chớ không thể raise event ấy trong SubClass nào của BaseClass ấy. Khác với methods, ta không thể overload một Event, tức là không thể dùng một tên cho hai Events có parameter list khác nhau. Ta có thể tạo một Class Library Project với một Class trong đó có raise một Event rồi tạo một project khác trong đó có code để đón nhận và xử lý Event ấy. Để thử việc nầy bạn hãy tạo một Class Library Project mới với tên ClassLibrary1 về viết những dòng code định nghĩa Class Class1 với Event TheEvent và Sub LàmViệc để raise Event như sau: Public Class Class1 Public Event TheEvent() Public Sub LàmViệc() RaiseEvent TheEvent() End Sub End Class Kế đó bạn dùng Menu command File | Add Project | New Project để thêm một project mới với tên EventClass. Để có thể dùng Class1, bạn cần phải reference nó với Menu command Project | Add Reference , chọn Tab Projects và click Browse để chọn ClassLibrary1.DLL từ subfolder ClassLibrary1\bin của solution như trong hình dưới đây: Trang 75
  76. hình 3.9 : Project | Add Reference Một khi đã referenced ClassLibrary1 với Class1 trong ấy, bây giờ bạn có thể doubleclick lên Form1 để code như sau: Private WithEvents obj As ClassLibrary1.Class1 Private Sub Form1_Load( ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load obj = New ClassLibrary1.Class1() Trang 76
  77. End Sub Nhớ là ta phải declare variable obj thuộc loại ClassLibrary1.Class1 với WithEvents. Đặt một Button tên BtnLàmViệc và doubleclick lên nó để code như sau: Private Sub BtnLàmViệc_Click( ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnLàmViệc.Click obj.LàmViệc() End Sub Để xử lý Event của obj bạn chọn tên từ combobox phía trên bên trái, rồi chọn TheEvent từ combobox bên phải như trong hình dưới đây: Ở đây ta handle Event bằng cách hiển thị một message đơn giản: Đang xử lý một Event từ Class1. Bây giờ bạn có thể chạy program. Khi bạn click Button BtnLàmViệc program sẽ hiển thị message để chứng minh rằng từ một Application ta có thể handle event trong Class của một Project khác. Trang 77
  78. hình 3.10 : hiển thị message Ghi chú Nếu sau khi Unzip source file và load project vào, bạn dùng IDE Menu command Build | Rebuild Solution để compile lại hết các modules nhưng gặp error về references thì hãy làm như sau: Trong Solution Explorer click các tree nodes references để tìm các references có dấu chấm thang trong tam giác vàng và remove chúng. Dùng Menu command Project | Add Reference để chọn *.dll lại từ một \bin subfolder. Rebuild Solution. hình 3.11 : lựa chọn classLibrary Nếu bạn dùng chữ Việt Unicode trong program thì nhớ set up Advanced Save Option với Menu command File như trong hình dưới đây: Trang 78
  79. hình 3.12 : classLibrary Khi Dialog hiện ra, bạn chọn Unicode (UTF-8) cho Encoding: hình 3.13 : chọn kiểu fon Nếu bạn không thấy có menuItem Advanced Save Option trong Menu File thì cứ dùng menuItem Save As rồi click lên combo box Save phía dưới, bên phải của Save File As Dialog rồi chọn Save with Encoding như trong hình dưới đây: Trang 79
  80. hình 3.14 : chon kiểu save Nếu bạn quên set up Advanced Save Option như trên, chữ Việt sẽ bị lưu trử dưới dạng ANSI nên một số sẽ mất dấu chữ Việt và thay vào đó bằng những dấu ?. Shared Events Events có thể được declared là Shared. Shared methods chỉ có thể raise shared events, chúng không thể raise non-shared events. Thí dụ như: Public Class NguồnEvent Shared Event EventDùngChoSharedMethods() Public Shared Sub DùngChung() RaiseEvent EventDùngChoSharedMethods() End Sub End Class Một shared event có thể được raised bởi cả shared methods lẫn non-shared methods: Public Class NguồnEvent Public Event TheEvent() Shared Event EventDùngChoSharedMethods() Trang 80