Giới thiệu LINQ
LINQ (Language-Integrated Query) là ngôn ngữ truy vấn được tích hợp trong các ngôn ngữ lập trình .NET Framework. LINQ cho phép truy vấn dữ liệu, một cách trực tiếp từ mã lập trình, đến các nguồn khác nhau. Nói một cách tương đương, LINQ với các ngôn ngữ .NET cũng như ngôn ngữ SQL với cơ sở dữ liệu quan hệ.
Cú pháp LINQ gần giống ngôn ngữ SQL, nghĩa là cũng có các lệnh như Select, Where, From. Để dễ hình dung hãy xem ví dụ lệnh truy vấn LINQ trong VB dùng để hiển thị danh sách các tác giả (authors) có tên chứa chữ S hoa:
Dim authors As String() = New String() {"Hanselman, Scott", "Evjen, Bill", "Haack, Phil", "Vieira, Robert", "Spaanjaars, Imar"} Dim result = From author In authors Where author.Contains("S") Order By author Select author For Each author In result Label1.Text += author + "<br />" Next
C#
using System.Linq; ... string[] authors = new string[] { "Hanselman, Scott", "Evjen, Bill", "Haack, Phil", "Vieira, Robert", "Spaanjaars, Imar" }; var result = from author in authors where author.Contains("S") orderby author select author; foreach (var author in result) { Label1.Text += author + "<br />"; }
Kết quả là Scott Hanselman và Imar Spaanjaars.
LINQ là công cụ mạnh mẽ nên nó được tích hợp ở nhiều phần khía cạnh khác nhau trong .NET Framework. Một vài khía cạnh quan trọng:
- LINQ với các đối tượng (LINQ to Objects): LINQ cho phép truy vấn đến hầu hết các đối tượng (không chỉ string như ví dụ trên) trong .NET Framework.
- LINQ với XML (LINQ to XML): LINQ có thể truy vấn đến dữ liệu XML.
- LINQ với NET (LINQ to ADO.NET): làm việc với ADO.NET, LINQ cho phép truy vấn đến DataSet (LINQ to DataSet), chuyển thành các lệnh SQL (LINQ to SQL), và với các thực thể (entities) trong Entity Framework (EF) (LINQ to Entities).
Học LINQ tại đây.
Giới thiệu Entity Framework (EF)
EF là một ORM (Object Relational Mapper – Bộ ánh xạ đối tượng quan hệ) hỗ trợ phát triển các phần mềm ứng dụng hướng dữ liệu.Với EF, chúng ta có thể chuyển các đối tượng cơ sở dữ liệu, như các bảng (tables), thành các đối tượng .NET để chúng ta có thể dùng chúng trong truy vấn hay các ngữ cảnh kết buộc dữ liệu. Bên cạnh đó, EF cũng cho phép chúng ta thiết kế mô hình đối tượng trước rồi sau đó EF sẽ tạo ra cấu trúc dữ liệu cần thiết cho chúng ta. Với EF, chúng ta có thể làm việc dễ dàng với cơ sở dữ liệu mà không viết quá nhiều các dòng mã.
Như đã trình bày ở trên, EF sẽ giúp chúng ta ánh xạ các thành phần của cơ sở dữ liệu như các bảng, cột, quan hệ đến các đối tượng và các thuộc tính trong một mô hình đối tượng trong ứng dụng của chúng ta. VS làm điều này hết sức đơn giản thông qua bài thực hành dưới đây.
Thực hành làm quen LINQ và EF
Trong bài thực hành này chúng ta sẽ tạo một mô hình đối tượng (dùng template ADO.NET Entity Data Model), ánh xạ các bảng Genre, Review từ cơ sở dữ liệu đến mô hình, và cuối cùng là viết vài lệnh LINQ đơn giản.
- Nhấp chuột phải vào thư mục App_Code, chọn Add > Add New Item chọn ngôn ngữ Visual Basic (hay Visual C#) và chọn template NET Entity Data Model, nhập tên là ngocminhtran, và nhấp Add để thêm vào site
- Nhấn Next trong hộp thoại Entity Data Model Wizard (mặc định chọn Generate from database) xuất hiện sau đó.
- Tại bước kế tiếp đảm bảo các lựa chọn sau đây như trong hình:
Nhấp Next.
- Trong hộp thoại Choose Your Data Objects and Settings, mở rộng Tables và dbo, chọn bảng Genre và Review:
- Nhấp Finish để thêm mô hình (model) vào site. Nếu có một thông báo Security Warning xuất hiện thì chọn Do not show this message again và nhấn OK. VS sẽ tạo ra một mô hình (ngocminhtran.edmx) như sau:
- Nếu chúng ta xem trong thư mục App_Code sẽ có tập tin ngocminhtran.edmx và hai tập tin có phần mở rộng là .tt
- Bên cạnh đó cũng xuất hiện một thư mục Bin (cùng cấp với App_Code) chứa một file dll (một assembly) và một file XML
- Nhấp vào vị trí bất kỳ trong vùng xám (còn gọi là vùng Entity Designer), nhấn F4 mở cửa sổ Properties thay đổi Code Generation Strategy từ None đến Default
- Lưu và đóng tập tin edmx. Xoá hai tập tin không cần thiết trong thư mục App_Code là ngocminhtran.context.tt và ngocminhtran.tt.
- Mở trang All.aspx trong Reviews ở chế độ Design. Kéo một GridView từ Toolbox và thả vào vùng cpMainContent.
- Nhấp đôi vào vùng xám để đến sự kiện Load của trang (Page_Load) và thêm đoạn mã sau:
C#
protected void Page_Load(object sender, EventArgs e) { using (ngocminhtranEntities myEntities = new ngocminhtranEntities()) { var authorizedReviews = from review in myEntities.Reviews where review.Authorized == true orderby review.CreateDateTime descending select review; GridView1.DataSource = authorizedReviews; GridView1.DataBind(); } }
ngocminhtranEntities bị lỗi vì đây là lớp trong namespace ngocminhtranModel nên chỉ cần imports (hay using trong C#) nó là xong:
- Lưu tất cả và đóng aspx.vb. Mở trang All.aspx và Ctrl+F5
Sử dụng truy vấn LINQ với các server controls
Trong bài thực hành trên, chúng ta đã lấy dữ liệu từ các truy vấn LINQ và gán đến các controls bằng thuộc tính DataSource và phương thức DataBind(). Cách thức này có một vài bất tiện. Thứ nhất, phương thức DataBind() không hỗ trợ chỉnh sửa, cập nhật, hay xoá dữ liệu một cách trực tiếp. Thứ hai, chúng ta định nghĩa data source trong Code Behind (trang aspx.vb) nên GridView không biết dữ liệu của chúng ta cho đến khi thực thi và vì vậy, chúng ta sẽ không có công cụ để tạo các cột cho GridView. Các bất tiện này có thể được khắc phục thông qua các server controls là ListView và EntityDataSource.
Sử dụng data controls với Entity Framework (EF)
Trong chương XII chúng ta đã làm quen với các data controls gồm GridView và SqlDataSource. Trong phần này chúng ta sẽ tìm hiểu thêm các data controls sau:
Control | Mô tả |
EntityDataSource | Là chiếc cầu nối giữa nguồn dữ liệu (trong trường hợp này là EF) và data controls. |
ListView | Cung cấp một giao diện trực quan mẫu cho phép thêm, xoá, sửa dữ liệu trong một cơ sở dữ liệu, cung cấp các dịch vụ CRUD. |
DataPager | Sử dụng kết hợp với ListView cho phép phân trang dữ liệu thành từng nhóm hàng thay vì hiển thị tất cả các hàng cùng một lúc. |
EntityDataSource control
EntityDataSource là chiếc cầu nối giữa Entity Framework và data control (ví dụ như ListView hay GridView). Nó bao gồm các thuộc tính sau:
Thuộc tính | Mô tả |
EnableInsert
EnableDelete EnableUpdate |
Cho phép các data control (như GridView hay ListView) thực hiện chức năng thêm, xoá, hay chỉnh sửa dữ liệu. |
ContextTypeName | Tên của lớp ObjectContext mà data control sẽ dùng. |
EntitySetName | Tên của tập entity từ mô hình EF mà chúng ta muốn dùng, ví dụ Reviews hay Genres. |
Select
OrderBy Where |
Cho phép định nghĩa truy vấn để EntityDataSource kích hoạt đến mô hình EF. |
Cùng với các data control, EntityDataSource cung cấp cách thức truy cập đến cơ sở dữ liệu SQL Server thông qua LINQ to Entities.
Một ứng dụng đơn giản với EntityDataSource
Trong bài thực hành này, chúng ta sẽ bắt đầu xây dựng chức năng quản lý hình ảnh người dùng upload cho website. Chúng ta sẽ thấy cách dùng EntityDataSource và DetailsView để tạo một giao diện cho phép người dùng nhập tên album ảnh mới vào hệ thống. Trong các bài thực hành sau, chúng ta sẽ tạo chức năng cho phép người dùng upload hình ảnh yêu thích vào album vừa tạo.
- Mở cơ sở dữ liệu ngocminhtran bằng Microsoft SQL Server Management Sudio và thêm vào hai bảng mới là PhotoAlbum và Picture với lược đồ như sau:
PhotoAlbum
Picture
- Trong Object Explorer (của SQL Server Management) chọn Database Diagrams và nhấp đôi chuột vào gen_review (là diagram đã tạo ở chương XII) để mở vùng diagram như sau:
Kích chuột phải vào vùng diagram và chọn Add Table để thêm hai bảng mới bằng cách chọn bảng và nhấp Add sau đó nhấp Close:
Kết quả sau khi thêm hai bảng và sắp xếp lại như sau:
- Nhấp chuột và kéo khoá Id của bảng PhotoAlbum và thả vào ngay vị trí PhotoAlbumId của bảng Picture để xác nhận rằng Id là khoá chính trong bảng PhotoAlbum và là khoá ngoại (FK) trong bảng Picture (PhotoAlbumId). Kết quả xuất hiện cửa sổ Tables and Columns:
- Nhấp OK hai lần, kết quả:
Đóng vùng diagram và nhấn Yes để xác nhận sự thay đổi.
- Trở lại Visual Studio, tìm đến thư mục App_Code trong cửa sổ Solution Explorer và nhấp đôi chuột trái vào tập tin edmx:
- Nhấp chuột phải vào vùng trống, chọn Update Model from Database. Trong Update Wizard chọn tab Add chọn Tables > dbo và chọn hai bảng PhotoAlbum và Picture như sau:
- Nhấp Finish. Kết quả sau khi sắp xếp lại:
Lưu tất cả và đóng tệp ngocminhtran.edmx.
- Tạo một trang ASPX mới là NewPhotoAlbum.aspx (template là MyBasePage), giá trị thuộc tính title của trang là Create New Photo Album.
- Chuyển trang sang chế độ Design. Trong thanh Toolbox tại mục Data, kéo DetailsView và thả vào vùng cpMainContent của trang:
- Trong DetailsView Tasks tại Choose Data Source chọn <New data source>. Trong hộp thoại Data Source Configuration Wizard chọn Entity và nhấp OK:
- Trong Named Connection chọn ngocminhtranEntities:
- Nhấp Next và chọn PhotoAlbums trong mục EntitySetName của hộp thoại Configure Data Source:
- Trong bài thực hành này, chúng ta cần thêm dữ liệu nên chọn mục Enable automatic inserts trước khi nhấn Finish. Nhấn OK. Chọn Enable Inserting trong DetailsView Task:
- Trong hộp thoại Properties của DetailsView, tại DefaultMode thay đổi từ ReadOnly đến Insert.
- Chuyển đến chế độ Source, tìm đến BoundField cho thuộc tính Id của PhotoAlbum và thiết lập thuộc tính InsertVisible đến giá trị false.
- Chuyển qua chế độ Design, trong hộp thoại Poperties của EntityDataSource tìm đến tab sự kiện (Events – hình tia chớp) và nhấp đôi chuột vào sự kiện Inserted:
- Chúng ta thêm đoạn mã sau (cho sự kiện Inserted) vào tập tin .vb của trang (lưu ý có imports ngocminhtranModel):
C#
protected void EntityDataSource1_Inserted(object sender, EntityDataSourceChangedEventArgs e) { if (e.Entity != null) { PhotoAlbum myPhotoAlbum = (PhotoAlbum)e.Entity; Response.Redirect(string.Format( "ManagePhotoAlbum.aspx?PhotoAlbumId={0}", myPhotoAlbum.Id.ToString())); } }
- Lưu và thực thi trang NewPhotoAlbum.aspx, kết quả:
- Nhập tên một Album mới, ví dụ MyFavoriteSingers, và nhấp vào Insert ở dưới, kết quả sẽ xuất hiện lỗi:
- Lỗi này xuất hiện do chúng ta chưa tạo trang ManagePhotoAlbum.aspx (sẽ tạo trong bài thực hành kế tiếp), nhưng chúng ta có thể thấy được Id của Album mới vừa tạo thông qua địa chỉ trên thanh địa chỉ của trình duyệt:
Sử dụng ListView
ListView cho phép chúng ta hiển thị dữ liệu trong những hình thức khác nhau như dạng lưới (grid) hay dạng danh sách (list), v.v. ListView cũng hiển thị và quản lý dữ liệu thông qua các template cho phép chúng ta kiểm soát những cách nhìn khác nhau về dữ liệu. Một số template có thể thêm đến ListView như bảng sau:
Template | Mô tả |
<LayoutTemplate> | Giống như một bộ chứa (container), cho phép định nghĩa vị trí đặt các thành phần dữ liệu. Các thành phần dữ liệu như ItemTemplate và AlternatingItemTemplate có thể được thêm vào template này. |
<ItemTemplate>
<AlternatingItemTemplate> |
Định nghĩa chế độ chỉ đọc cho điểu khiển. Nếu hai template này sử dụng cùng nhau sẽ tạo ra “Zebra effect” (hiệu ứng Ngựa vằn) tức là các hàng chẵn và lẻ sẽ hiển thị khác nhau (thường là màu nền). |
<SelectedItemTemplate> | Cho phép định nghĩa cách chúng ta nhìn hay cảm thấy về thành phần được chọn hay kich hoạt. |
<InsertItemTemplate>
<EditItemTemplate> |
Cho phép chúng ta định nghĩa giao diện để thêm hay cập nhật các thành phần trong danh sách. |
<ItemSeparatorTemplate> | Định nghĩa đánh dấu được đặt giữa các thành phần trong danh sách. |
<EmptyDataTemplate> | Hiển thị khi điểu khiển không có dữ liệu để hiển thị. |
<GroupTemplate>
<GroupSeparatorTemplate> <EmptyItemTemplate> |
Được dùng khi dữ liệu có thể được hiển thị trong những nhóm khác nhau. |
Bên cạnh các template, chúng ta cần chú ý một số thuộc tính quan trọng của ListView:
Thuộc tính | Mô tả |
ItemPlaceholderID | ID của một điểu khiển được đặt trong LayoutTemplate. |
DataSourceID | ID của điểu khiển nguồn dữ liệu trên trang như EntityDataSource hay SqlDataSource. |
InsertItemPosition | Xác định vị trí cho InsertItemTemplate. Thuộc tính gồm 3 giá trị là None, FirstItem và LastItem. |
Giống như các điểu khiển khác, ListView cũng có một số các sự kiện sẽ được kích hoạt tại những thời điểm khác nhau trong chu kỳ sống của mình như ItemInserted hay ItemInserting.
( xem chi tiết hơn về ListView có thể tham khảo tại đây https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.aspx )
Thực hành thêm và xoá dữ liệu với ListView
- Tạo ra một trang Web Form mới dựa trên MyBasePage gọi là ManagePhotoAlbum.aspx, thiết lập Title là Manage Photo Album và chuyển nó đến chế độ Design.
- Kéo một ListView từ mục Data trên Toolbox và đặt vào vùng cpMainContent
- Trong ListView Tasks tại Choose Data Source chọn <New data source>. Nhấp chuột vào Entity và OK. Chọn ngocminhtranEntities tại Named Connection và nhấn Next. Chọn Pictures từ EntitySetName. Check vào 2 mục Enable automatic inserts và Enable automatic deletes và nhấp Finish.
Nhấp OK để đóng Configure Data Source Wizard
- Trở lại chế độ Design, chọn EntityDataSource và mở cửa sổ Properties. Trong cửa sổ Properties tìm đến thuộc tính Where và nhấp vào nút (…) bên phải để mở cửa sổ Expression Editor. Chúng ta cần cài đặt một QueryStringParameter để có thể lọc dữ liệu hiển thị đến ListView. Để làm điều này chúng ta nhập đoạn mã sau vào ô Where Expression:
it.PhotoAlbum.Id = @photoAlbumId
Lệnh này sẽ lọc các ảnh từ bảng Picture theo PhotoAlbumId. it là tên biến ngầm định được dùng bắt buộc để ASP.NET run time có thể hiểu.
- Nhấn nút Add Parameter
- Nhập PhotoAlbumId tại mục Name của Parameters, chọn QueryString cho Parameter source và PhotoAlbumId cho QueryStringField:
- Nhấp chuột vào liên kết Show advanced properties thay đổi giá trị thuộc tính Type thành Int32:
- Nhấp OK.
- Trong ListView Tasks, chọn Configure ListView (nếu chưa thấy tuỳ chọn này thì chọn Refresh Schema đầu tiên). Chọn Bulleted List trong Select a Layout, chọn Enable Inserting và Enable Deleting như hình sau:
- Nhấp OK.
- Trở lại trang trong chế độ Source. Chúng ta thấy rất nhiều template được thêm vào tự động vào ListView như sau (sau khi đã được thu gọn):
- Xoá tất cả các template và chỉ giữ lại 3 template là InsertItemTemplate, ItemTemplate và LayoutTemplate.
- Trong LayoutTemplate xoá các thuộc tính như ID, runat, style của phần tử ul; xoá phần tử div; thêm thuộc tính class là ItemConainer. LayoutTemplate lúc này như sau:
- Trong ItemTemplate, xoá các dòng mã tạo các cột Id, PhotoAlbumId và PhotoAlbum. Mã của ItemTemplate lúc này như sau:
- Phương thức Eval để nhận giá trị được yêu cầu từ đối tượng. Đối số của phương thức này là các thuộc tính (ví dụ Description) của đối tượng (ví dụ Picture) (hay các cột của một bảng). Các giá trị nhận được từ Eval không thay đổi (chỉ đọc) nên phù hợp cho các điều khiển như Label.
- Trong InsertItemTemplate chúng ta cũng xoá các đoạn mã tạo các cột Id, PhotoAlbumId và PhotoAlbum. Mã của InsertItemTemplate lúc này như sau:
- Phương thức Bind được sử dụng để nhận các giá trị từ đối tượng. Khác với Eval chỉ nhận giá trị một chiều từ đối tượng, phương thức Bind thiết lập cơ chế kết buộc dữ liệu hai chiều giữa thuộc tính (ví dụ Description) của đối tượng (ví dụ Picture) với một điều khiển (ví dụ TextBox). Các giá trị nhận được từ Bind thay đổi.
- Chuyển trang sang chế độ Design. Chọn EntityDataSource và mở hộp thoại Properties. Chọn tab Events và nhấp đôi chuột vào Inserting
- Đoạn mã (VB) cho sự kiện Inserting như sau:
- Dùng lệnh imports (VB) hay using (C#) để thêm namspace ngocminhtranModel và thêm đoạn mã sau vào thủ tục EntityDataSource1_Inserting:
Mã C#
using ngocminhtranModel; protected void EntityDataSource1_Inserting(object sender, EntityDataSourceChangingEventArgs e) { int photoAlbumId = Convert.ToInt32(Request.QueryString.Get("PhotoAlbumId")); Picture myPicture = (Picture)e.Entity; myPicture.PhotoAlbumId = photoAlbumId; }
- Thêm đoạn CSS sau vào tập tin Monochrome.css
.ItemContainer { width: 600px; list-style-type: none; clear: both; } .ItemContainer li { height: 300px; width: 200px; float: left; } .ItemContainer li img { width: 180px; margin: 10px 20px 10px }
- Thêm cùng đoạn mã CSS trên đến tập tin DarkGrey.css nhưng thiết lập width của .ItemContainer đến 400px
.ItemContainer { width: 400px; list-style-type: none; clear: both; } ….
- Lưu tất cả. Mở lại trang NewPhotoAlbum.aspx. Nhập tên Album mới
và nhấn Insert sẽ chuyển sang trang ManagePhotoAlbum.aspx để chúng ta có thể nhập các thông tin về ảnh trong Album mới:
Một số lỗi có thể xảy ra:
- Nếu chúng ta đã thêm một album trước đó thì khi chúng ta thêm album mới từ trang NewPhotoAlbum.aspx có thể xảy ra lỗi như sau:
Khắc phục: mở bảng PhotoAlbum (chế độ Design) trong MS Microsoft SQL Server Management Studio, chọn Id và tìm tới thuộc tính Identity Specification trong Column Properties, mở rộng và chọn Yes cho (Is Identity)
Lưu bảng. Trở lại Visual Studio, trong Solution Expoler tìm đến thư mục App_Code và mở tập tin ngocminhtran.edmx. Tìm đến PhotoAlbum, chọn Id và mở hộp cửa sổ Properties. Trong cửa sổ Properties của Id, tìm đến thuộc tính StoreGeneratedPattern và thiết lập giá trị là Identity:
Với cách làm như trên, mỗi lần chúng ta thêm một album mới, Id của PhotoAlbum sẽ tự động tăng 1 và là thuộc tính chỉ đọc (không cho chúng ta can thiệp).
Lưu tất cả và thực thi lại trang.
- Nếu chúng ta gặp lỗi:
Khắc phục: Lỗi này xuất hiện do trong quá trình nhập thông tin cho các tham số (parameters) (tại nút (…) của thuộc tính Where trong hộp Properties của EntityDataSource1), chúng ta vô tình nhập khoảng trắng ở kí tự đầu tiên. Để chỉnh sửa, chúng ta mở lại trang ManagePhotoAlbum.aspx ở chế độ Source, tìm đến <WhereParameters> và xác định phần tử con của nó là <QueryStringParameter>:
Xoá bỏ các khoảng trắng từ thuộc tính Name và QueryStringField. Lưu lại các thay đổi.
Sử dụng Bind hay Eval như trong phần thực hành trên là hữu ích nhưng bắt buộc chúng ta phải nhớ tên các thuộc tính (ví dụ Description) của đối tượng (ví dụ Picture). Điều này có thể không dễ dàng cho chúng ta, nhất là trong các dự án với cơ sở dữ liệu lớn.
ASP.NET 4.5 cung cấp một giải pháp để giúp chúng ta làm việc tốt hơn bằng cách cung cấp thêm thuộc tính ItemType đến các điều khiển như ListView. Thuộc tính này sẽ trỏ đến đối tượng (ví dụ Picture) được gán trong nguồn dữ liệu (data source). ItemType có hai tuỳ chọn là Item (hình thức thay thế cho Eval) và BindItem (hình thức thay thế cho Bind). Chúng ta sẽ hiểu hơn cách làm việc với ItemType qua phần thực hành sau.
Thực hành với ItemType trong ListView
- Mở trang ManagePhotoAlbum.aspx ở chế độ Source, tìm đến phần tử ListView và thêm thuộc tính ItemType với giá trị là ngocminhtranModel.Picture đến phần tử này:
- Trong InsertItemTemplate của ListView, tìm đến Bind của DescriptionTextBox, thay đổi từ Bind(“Description”) thành BindItem.Description
- Áp dụng tương tự cho TooltipTextBox
- Trong ItemTemplate của ListView, tìm đến Eval của DescriptionLabel, thay đổi từ Eval(“Description”) thành Item.Description
- Tương tự cho TooltipLabel
- Lưu các thay đổi. Thực thi lại trang NewPhotoAlbum.aspx và nhận thấy kết quả không thay đổi.
Trong phần thực hành tiếp theo, chúng ta sẽ học cách sử dụng điều khiển FileUpload để có thể upload hình ảnh đến trang web thay vì chỉ là những đường dẫn.
Thực hành dùng FileUpload
- Tạo một thư mục mới tên GigPics tại thư mục gốc của website chứa những hình ảnh người dùng upload lên trang web.
- Mở trang ManagePhotoAlbum.aspx ở chế độ Source tìm đến phần tử ItemTemplate và xoá Label có ID là ImageURLLabel và xoá luôn nhãn ImageURL. Thay thế Label này bằng điều khiển Image với các thuộc tính như sau:
<asp:Image ID="ImageUrl" runat="server" ImageUrl='<%# Item.ImageUrl %>' />
Đoạn mã được thay thế trông như sau:
- Để cho phép người dùng upload hình ảnh, chúng ta thay TextBox bằng FileUpload. Trong InsertItemTemplate, xoá nhãn ImageURL: và thay thế TextBox có ID là ImageURLTextBox bằng điều khiển FileUpload:
- Trong InsertItemTemplate, thiết lập thuộc tính CausesValidation của Button có ID là CancelButton đến giá trị false
- Tương tự trong ItemTemplate, thiết lập thuộc tính CausesValidation của Button có ID là DeleteButton đến giá trị false
- Mở tập tin ManagePhotoAlbum.aspx.vb, thêm các đoạn mã sau đến thủ tục của sự kiện Inserting:
Mã C#
FileUpload FileUpload1 = (FileUpload)ListView1.InsertItem.FindControl("FileUpload1"); string virtualFolder = "~/GigPics/"; string physicalFolder = Server.MapPath(virtualFolder); string fileName = Guid.NewGuid().ToString(); string extension = System.IO.Path.GetExtension(FileUpload1.FileName); FileUpload1.SaveAs(System.IO.Path.Combine(physicalFolder, fileName + extension)); myPicture.ImageUrl = virtualFolder + fileName + extension;
InsertItemTemplate: 2 điều khiển RequiredFieldValidator kết nối với các TextBox của Description và Tooltip, 1 điều khiển CustomValidator.
Điều khiển RequiredFieldValidator kết nối đến TextBox của Description có mã như sau:
<asp:RequiredFieldValidator ID="reqDesc" ControlToValidate="DescriptionTextBox" runat="server" ErrorMessage="Enter a description." />
Điều khiển RequiredFieldValidator kết nối đến TextBox của Tooltip có mã như sau:
<asp:RequiredFieldValidator ID="reqToolTip" ControlToValidate="ToolTipTextBox" runat="server" ErrorMessage="Enter a tool tip." />
Điều khiển CustomValidator
<asp:CustomValidator ID="cusValImage" runat="server" ErrorMessage="Select a valid .jpg file." />
Các điều khiển được đặt các vị trí như sau:
Bổ sung thêm thuộc tính TextMode có giá trị là MultiLine cho TextBox Description
- Mở trang ManagePhotoAlbum.aspx ở chế độ Design, thêm sự kiện ItemInserting đến ListView và thêm code như sau:
Mã C#
protected void ListView1_ItemInserting(object sender, ListViewInsertEventArgs e) { FileUpload FileUpload1 = (FileUpload)ListView1.InsertItem.FindControl("FileUpload1"); if (!FileUpload1.HasFile || !FileUpload1.FileName.ToLower().EndsWith(".jpg")) { CustomValidator cusValImage = (CustomValidator)ListView1.InsertItem.FindControl("cusValImage"); cusValImage.IsValid = false; e.Cancel = true; } }
- Lưu tất cả. Mở trang NewPhotoAlbum.aspx, nhập album mới (Ví dụ Bolero và là album đầu tiên nên Id = 0). Trong trang ManagePhotoAlbum.aspx, nhập một vài thông tin và chọn một ảnh jpg từ ổ cứng máy tính (ví dụ minh.jpg) bằng cách nhấp chuột vào nút Choose File:
- Nhấn Insert:
- Chúng ta có thể thêm bức thứ 2 gồm các thông tin:
- Nhấn Insert:
- Tương tự thêm hai bức nữa trong Album Bolero:
- Nếu nhấn nút Delete sẽ tự động xoá các thông tin chúng ta vừa nhập.
DataPager Control
DataPager là điều khiển cung cấp khả năng phân trang một cách tự động đến ListView. Chúng ta có thể kết nối DataPager đến ListView theo hai cách:
- Định nghĩa DataPager trong <LayoutTemplate> của ListView.
- Định nghĩa bên ngoài ListView nhưng cần kết nối thuộc tính PagedControlID của DataPager đến thuộc tính ID của ListView tương ứng.
Chúng ta sẽ làm quen với kĩ thuật phân trang trong ListView bằng cách dùng DataPager thông qua bài thực hành sau.
Thực hành phân trang với ListView và DataPager
Trong bài thực hành này, chúng ta sẽ cho phép người dùng chọn một album bất kỳ từ danh sách (drop-down list) và xem tất các hình ảnh đã được phân trang từ album.
- Thêm một thư mục đến Site (nhấp chuột phải vào Site > Add > New Folder) tên là PhotoAlbums. Trong thư mục này, tạo một trang ASPX (dựa vào MyBasePage template) tên Default.aspx. Thiết lập giá trị cho thuộc tính Title là All Photo Albums.
- Di chuyển đến chế độ Design của trang Default.aspx. Chọn DropDownList từ ToolBox và thả vào vùng cpMainContent của trang Default.aspx. Tại DropDownList Tasks chọn Enable AutoPostBack và chọn Choose Data Source. Trong hộp Data Source Configuration Wizard chọn <New data source…> từ Select a data source, chọn Entity và OK. Chọn ngocminhtranEntities từ Named Connection và Next. Trong hộp thoại Configure Data Selection chọn PhotoAlbums từ EntitySetName và chọn các trường Id và Name như hình sau:
Nhấn Finish và OK để đóng hộp Data Source Configuration Wizard.
- Dưới DropDownList thêm một ListView mới và kết nối nó đến EntityDataSource bằng cách chọn <New data source> trong Choose Data Source từ ListView Tasks. Nhấp Entity và OK. Chọn ngocminhtranEntities từ Named Connection và Next. Trong hộp thoại Configure Data Selection chọn Pictures từ EntitySetName và Finish.
- Chọn EntityDataSource2 và mở hộp thoại Properties, tìm đến thuộc tính Where và nhấn nút (…) bên phải để mở hộp thoại Expression Editor. Chọn checkbox Automatically generate…tại vị trí đầu tiên của hộp thoại, nhấn nút Add Parameter và gõ PhotoAlbumId thay cho newparameter, chọn Control tại Parameter Source, chọn DropDowList1 tại ControlID và cuối cùng là nhấn vào liên kết Show advanced properties thay đổi Type đến Int32. Expression Editor lúc này có thể trông như sau:
- Nhấp OK để đóng hộp thoại.
- Tại ListView Tasks (nhấn vào dấu mũi tên bên phải ListView), chọn Configure ListView (nhấn vào liên kết Refresh Schema nếu Configure ListView chưa xuất hiện). Chọn Bulleted List tại Select a Layout và chọn Enable Paging tại Option. Có hai hình thức phân trang là Next/Previous Pager và Numeric Pager. Trong bài này chúng ta chọn Next/Previous Pager. Kết quả lựa chọn như hình dưới:
- Nhấn OK.
- Chuyển đến chế độ Source và thêm thuộc tính ItemType đến ListView với giá trị là ngocminhtranModel.Picture. Mã nguồn ListView như sau:
<asp:ListView ID="ListView1" runat="server" DataKeyNames="Id" DataSourceID="EntityDataSource2" ItemType="ngocminhtranModel.Picture">
- Xoá tất cả các template sau: <AlternatingItemTemplate>, <EditItemTemplate>,<InsertItemTemplate>, <ItemSeparatorTemplate>, <SelectedItemTemplate>
- Tại <LayoutTemplate>, xoá các thuộc tính id, runat, style của <ul> và thay bằng thuộc tính class=”ItemContainer“; tìm đến phần tử <DataPager> thêm thuộc tính PageSize = 3; thêm clear:both đến thuộc tính style của <div>. Kết quả:
<LayoutTemplate> <ul class="ItemContainer"> <li runat="server" id="itemPlaceholder" /> </ul> <div style="clear:both"> <asp:DataPager ID="DataPager1" runat="server" PageSize="3"> <Fields> <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True" /> </Fields> </asp:DataPager> </div> </LayoutTemplate>
- Thêm điều khiển Image với các thuộc tính ImageUrl và Tooltip đến <ItemTemplate> bằng cách chỉnh sửa đoạn mã trong <ItemTemplate> như sau:
<ItemTemplate> <li> <asp:Image ID="Image1" runat="server" ImageUrl='<%# Item.ImageUrl %>' ToolTip='<%#Item.ToolTip %>' /> <asp:Label ID="DescriptionLabel" runat="server" Text='<%# Item.Description %>' /> </li> </ItemTemplate>
- Bọc toàn bộ nội dung của cpMainContent trong một UpdatePanel với một phần tử ContentTemplate để tránh hiệu ứng nhấp nháy khi phân trang hay chọn một album mới. Đoạn mã trông như sau:
<asp:Content ID="Content2" ContentPlaceHolderID="cpMainContent" Runat="Server"> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" DataSourceID="EntityDataSource1" DataTextField="Id" DataValueField="Id"> </asp:DropDownList> .... </ContentTemplate> </asp:UpdatePanel> </asp:Content>
- Mở tập tin Web.sitemap thêm một mục thực đơn mới (với hai mục con) cho phần GigPics vào giữa hai phần About và Reviews như sau:
</siteMapNode> <siteMapNode url="~/PhotoAlbums/" title="Gig Pics" description="All Gig Pics"> <siteMapNode url="~/PhotoAlbums/Default.aspx" title="Gig Pics" description="All Gig Pics" /> <siteMapNode url="~/NewPhotoAlbum.aspx" title="New Album" description="Create a new Photo Album with Gig Pics" /> </siteMapNode>
Vị trí đoạn mã:
- Điều chỉnh lại chiều rộng của các mục thực đơn trong theme Monochrome bằng cách tìm đến .MainMenu ul li trong tập tin Monochrome.cs và điều chỉnh giá trị của width từ 200px đến 160px:
.MainMenu ul li { width: 160px; }
- Lưu tất cả. Thực thi trang Default.aspx trong thư mục PhotoAlbums. Ví dụ xem album Bolero (Id = 0) và có 4 bức hình (xem lại phần thực hành dùng FileUpload)
Nhấn nút Next:
Vì chúng ta chọn PageSize = 3 trong DataPager nên sẽ phân trang và mỗi trang chứa không quá 3 ảnh.
Ý kiến bài viết