原文刊於 .NET Magazine國際中文電子雜誌
此篇文章改寫原刊於 .NET Magazine的文章,原文是使用Visual Studio 11 Developer Preview版工具撰寫的,本文改用Visual Studio Beta工具測試,重新抓圖並修訂部分工具的差異。原文URL:
本文撰寫時使用的工具是Visual Studio 11 Beta,資料庫則為SQL Server 2012版,因此本文探討的內容在正式版上市時可能不適用。
ASP.NET 4.5版中包含許多新特性來開發網站應用程式,Visual Studio 11 Beta版開發工具也有許多改善,讓撰寫網頁的動作更為簡化,本篇文章將介紹一些開發工具提供的新特性。
開發工具新增功能
在Visual Studio 2010設計ASP.NET網頁時,有很多工作我們會透過「Smart Task」來完成,例如底下有一個Entity Data Source控制項,透過「Smart Task」可以設定它的資料來源,參考圖1所示。
現在Visual Studio 11工具「Source View」編輯畫面也可以使用「Smart Task」,只要將滑鼠游標停留在控制項的開始標籤上方,就會自動顯示一條藍色的底線,只要點選它或按下「CTRL+ .」叫出「Smart Task」視窗,參考圖2所示。
圖 2:在「Source View」編輯畫面使用「Smart Task」。
在「Source View」編輯畫面也可以註冊事件,類似WPF應用程式的事件註冊動作。例如以下範例利用EntityDataSource透過ADO.NET Entity Data Model讀取AdventureWorks資料庫中Contacts資料表的ContactID、Title 與FirstName三個欄位的資料,透過資料繫結技術將資料呈現在GridView控制項中顯示。預設GridView控制項會使用BoundField來顯示資料:
<div>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<br />
<asp:EntityDataSource ID="EntityDataSource1" runat="server" ConnectionString="name=AdventureWorksEntities"
DefaultContainerName="AdventureWorksEntities" EnableFlattening="False"
EntitySetName="Contacts" Select="it.[ContactID], it.[FirstName], it.[Title]">
</asp:EntityDataSource>
<br />
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="EntityDataSource1">
<Columns>
<asp:CommandField ShowSelectButton="True"></asp:CommandField>
<asp:BoundField DataField="ContactID" HeaderText="ContactID" ReadOnly="True" SortExpression="ContactID">
</asp:BoundField>
<asp:BoundField DataField="FirstName" HeaderText="FirstName"
SortExpression="FirstName" ReadOnly="True"></asp:BoundField>
<asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title"
ReadOnly="True">
</asp:BoundField>
</Columns>
</asp:GridView>
</div>
</form>
EntityDataSource控制項有一個Selecting事件,這個事件在讀取資料庫資料的動作發生時自動觸發。我們希望每回從資料庫擷取資料時,能夠將存取時間顯示在畫面的Label控制項上。當你利用Visual Studio 11的HTML編輯工具在EntityDataSource控制項開頭標籤輸入「OnSelecting=」字串時,Visual Studio 11便自動跳出一個「Create New Event」選項以註冊事件與建立事件處理常式,參考圖3所示:
圖 5:註冊事件與建立事件處理常式。
這時只要按一次鍵盤的「Tab」鍵,就會自動產生事件處理常式,我在事件處理常式中,讀取目前伺服器的時間顯示在Label控制項上:
{
Label1.Text = "Fetching Data : " + System.DateTime.Now.ToString();
}
執行結果參考圖4所示:
圖 4:執行結果。
封裝使用者控制項
在設計網頁時,有時我們會將經常出現的HTML標籤封裝成利於重複使用的單位- 使用者控制項(User Control,附檔名為ASCX檔案),以便在網頁中重複地使用。Visual Studio 11 Beta提供一個小技巧,可以將網頁中的標籤封裝成ASCX檔案。例如,ASPX網頁中包含以下三個控制項:Label、TextBox與RequiredFieldValidator:
<asp:TextBox ID = "TextBox1" runat = "server"></asp:TextBox>
<asp:RequiredFieldValidator
ID = "RequiredFieldValidator1" runat = "server"
ErrorMessage = "RequiredFieldValidator" ControlToValidate = "TextBox1"
ForeColor = "Red"> * </asp:RequiredFieldValidator>
在Visual Studio 11 Beta 的HTML編輯工具中,可以將這些HTML標籤選取,然後按滑鼠右鍵,從突顯式選單中選取「Extract to User Control」選項,參考圖5所示:
圖 5:Extract to User Control。
接著你就會看到「Save as」對話盒,你可以輸入想要使用的使用者控制項的檔案名稱,參考圖6所示:
圖 6:設定使用者控制項名稱。
當你按下「OK」按鈕後, ASPX網頁內容上方利用Register註冊使用者控制項,原來HTML標籤所在的地方,便改用使用者控制項的標籤來顯示:
<%@ Page Language="C#" %>
<%@ Register Src="~/MyTextBox.ascx" TagPrefix="uc1" TagName="MyTextBox" %>
<!DOCTYPE html>
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<uc1:mytextbox runat="server" id="MyTextBox" />
<asp:Button ID="Button1" runat="server" Text="Button" /></div>
</form>
</body>
</html>
另外專案中就會多出一個MyTextBox.Ascx檔案,檔案內容如下:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyTextBox.ascx.cs" Inherits="MyTextBox" %>
<asp:Label ID="Label1" runat="server" Text="Input Text"> </asp:Label>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="RequiredFieldValidator"
ControlToValidate="TextBox1" ForeColor="Red"> * </asp:RequiredFieldValidator>
不過目前據筆者的測試,若使用者控制項包含程式碼,像是事件處理常式等,目前的Visual Studio 11 Beta版本便無法將其封裝,你可能得手動處理,舉例來說,若ASPX網頁內容如下,包含一個TextBox、Button與Label控制項:
<!DOCTYPE html>
<html xmlns = http://www.w3.org/1999/xhtml >
<head runat = "server" >
<title></title>
</head>
<body>
<form id = "form1" runat = "server" >
<div>
<asp:TextBox ID = "TextBox1" runat = "server"> </asp:TextBox>
<asp:Button ID = "Button1" runat = "server" OnClick = "Button1_Click" Text = "Click" />
<br />
<asp:Label ID = "Label1" runat = "server"> </asp:Label>
</div>
</form>
</body>
</html>
而網頁相關聯的程式碼後置cs檔案內容如下,Button若被按下觸發Click事件時,會將文字方塊輸入的字串顯示在Label控制項上:
{
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = TextBox1.Text ;
}
}
但當你將TextBox、Button與Label控制項同時選取,封裝成使用者控制項後,Button1_Click事件處理常式並不會被複製到ASCX檔案中。
WAI-ARIA支援
WAI-ARIA ( Accessible Rich Internet Applications Suite) 是W3C制定中的一個標準,定義了一個準則,讓身障人士能夠更容易存取使用Ajax、HTML、JavaScript設計的網站應用程式,或網際網路的內容。Visual Studio 11 Beta現在已經支援這個標準。
HTML編輯工具 - 智慧型感知功能
在Visual Studio 11 Beta中撰寫支援HTML5網頁時,HTML編輯工具提供了智慧型感知(IntelliSense)功能,方便撰寫程式碼,例如當你使用到HTML 5的Canvas項目時,便會自動顯示提示,參考圖7所示。
圖 7:HTML智慧型感知功能。
HTML編輯工具 - HTML 5程式碼片段功能
在Visual Studio 11 Beta中撰寫支援HTML5網頁的動作變的更簡單了,只要善用HTML 5程式碼片段功能,就可以很快達成任務。例如想要在HTML網頁中加入一個清單方塊,可以輸入部份的HTML標籤,Visual Studio 11 Beta會自動提醒可以使用程式碼片段功能,參考圖8所示:
圖 8:HTML 5程式碼片段功能。
這時只要按下Tab鍵兩次,程式碼片段功能就會自動填入<li>項目,參考圖9所示:
圖 9:HTML 5程式碼片段功能。
HTML編輯工具 - HTML標籤自動重新命名
在編輯HTML標籤方面,Visual Studio 11 Beta開發工具提供一個貼心的功能,只要你修改了開頭或結尾標籤,它就會自動將相符的結尾、開頭標籤的自動重新命名。例如以下範例,當修改開頭的<title>標籤為<titl>時,結尾標籤就自動改為<titl>,參考圖10所示。
圖 10:HTML標籤自動重新命名。
HTML編輯工具 – 自動縮排
在Visual Studio 2010編輯HTML標籤時,當你輸入開頭標籤然後按下鍵盤Enter鍵時,除了幫你產生結尾的</div>之外,會將游標停留在結尾的</div>標籤之前,如下圖紅色標記所示:
圖 11:Visual Studio 2010 HTML縮排功能。
而Visual Studio 11 Beta則會在開頭<div>和結尾的</div>標籤之間插入一個空白行,並讓開頭標籤和結尾自動縮排對齊,然後將游標停留在空白行開頭,參考圖12所示:
圖 12:Visual Studio 11 Beta HTML縮排功能。
HTML編輯工具 – IntelliSense清單過濾功能
在Visual Studio 2010編輯HTML標籤時工具會透過IntelliSense功能表列出可使用的清單供開發者選擇,底下範例輸入「<di」字串,但是清單中還包含了其它非「<di」字串開頭的選項,參考圖13所示:
圖 13:Visual Studio 2010 IntelliSense清單。
而Visual Studio 11 Beta會自動進行篩選,將符合查詢條件的項目列出,參考圖14所示:
圖 14:Visual Studio 11 Beta IntelliSense清單過濾功能。
強型別的資料控制項樣版
ASP.NET 4.5網頁控制項現在具備強型別的資料樣版功能,在設計資料存取網頁時,非常有幫助。我們先來看一個ASPX網頁,網頁中包含一個GridView控制項顯示以EntityDataSource控制項,透過ADO.NET Entity Data Model技術取回的AdventureWorks資料庫Contact資料表內容,GridView控制項利用BoundField來顯示ContactID、Title、FirstName與LastName欄位值,我們可以改用樣版資料行來自顯示的內容:
DataSourceID="EntityDataSource1">
<Columns>
<asp:BoundField DataField="ContactID" HeaderText="ContactID" ReadOnly="True" SortExpression="ContactID" />
<asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
</Columns>
</asp:GridView>
<asp:EntityDataSource ID="EntityDataSource1" runat="server" ConnectionString="name=AdventureWorksEntities"
DefaultContainerName="AdventureWorksEntities" EnableFlattening="False"
EntitySetName="Contact" EnableDelete="True" EnableInsert="True"
EnableUpdate="True">
</asp:EntityDataSource>
筆者利用GridView控制項的「Smart Task」選項,編輯這些欄位,將BoundField轉換成Template Field,參考圖15所示:
圖 15:編輯GridView欄位。
參考圖16所示,只要選取欄位,然後點選「Field」對話盒右下方的「Convert this Field into a Template Field」超連結,就可以轉換成樣板資料行:
圖 16:將Bound Field轉換成樣板資料行。
透過上述步驟,將Title、FirstName、LastName欄位都轉換為TemplateField,此時工具自動產生出的HTML如下:
DataSourceID="EntityDataSource1">
<Columns>
<asp:BoundField DataField="ContactID" HeaderText="ContactID" ReadOnly="True" SortExpression="ContactID" />
<asp:TemplateField HeaderText="Title" SortExpression="Title">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("Title") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("Title") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="FirstName" SortExpression="FirstName">
<EditItemTemplate>
<asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("FirstName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2" runat="server" Text='<%# Bind("FirstName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="LastName" SortExpression="LastName">
<EditItemTemplate>
<asp:TextBox ID="TextBox3" runat="server" Text='<%# Bind("LastName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label3" runat="server" Text='<%# Bind("LastName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
從中可以看出,我們利用ASP.NT 雙向的Bind語法進行資料繫結。不過若在HTML編輯工具中修改Bind語法中的內容,工具並不會提供任何提示,這致使程式出錯的機率變高。此外利用Bind語法進行繫結實際上是以晚期繫結(Late Binding)的方式處理,將字串傳入Bind方法後再行剖析,這樣就無法在設計階段善用工具提供輔助來撰寫程式碼(如IntelliSense功能)。
ASP.NET 4.5現在支援強型別的資料樣版(strongly-typed data template)來改善這個問題,大部分的資料繫結控制項可以利ItemType屬性來指明欲繫結的資料模型之型別,然後在樣版中使用Item (單向繫結)或BindItem(雙向繫結)兩個運算式來取代先前的Bind語法:(補充說明,在Visual Studio 11 Developer Preview版,稱為ModelType屬性。而Visual Studio 11 Beta改名為ItemType屬性)
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ContactID"
DataSourceID="EntityDataSource1"
ItemType = "AdventureWorksModel.Contact"
>
<Columns>
<asp:BoundField DataField="ContactID" HeaderText="ContactID" ReadOnly="True" SortExpression="ContactID" />
<asp:TemplateField HeaderText="Title" SortExpression="Title">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# BindItem.Title %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Item.Title %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="FirstName" SortExpression="FirstName">
<EditItemTemplate>
<asp:TextBox ID="TextBox2" runat="server" Text='<%# BindItem.FirstName %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2" runat="server" Text='<%# Item.FirstName %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="LastName" SortExpression="LastName">
<EditItemTemplate>
<asp:TextBox ID="TextBox3" runat="server" Text='<%# BindItem.LastName %>'></asp:TextBox>1
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label3" runat="server" Text='<%# Item.LastName %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:EntityDataSource ID="EntityDataSource1" runat="server" ConnectionString="name=AdventureWorksEntities"
DefaultContainerName="AdventureWorksEntities" EnableFlattening="False"
EntitySetName="Contact" EnableDelete="True" EnableInsert="True"
EnableUpdate="True">
</asp:EntityDataSource>
這樣的好處是,在編譯階段便會進行檢查,例如底下圖17顯示,ItemType屬性設定的AdventureWorksModel.Contact型別並沒有NameLast屬性,因此編譯時就會顯示錯誤訊息。
圖 19:在編譯階段便可以進行型別檢查。
在開發過程中,會提供IntelliSense的支援:
圖 18:設計階段的IntelliSense支援。
沒有留言:
張貼留言