2012年3月15日 星期四

Net Framework 4.5與Visual Studio 11- ASP.NET 4.5新功能(1)

 

原文刊於 .NET Magazine國際中文電子雜誌

此篇文章改寫原刊於 .NET Magazine的文章,原文是使用Visual Studio 11 Developer Preview版工具撰寫的,本文改用Visual Studio Beta工具測試,重新抓圖並修訂部分工具的差異。原文URL:

http://blogs.uuu.com.tw/Articles/post/2011/11/30/Net-Framework-45與Visual-Studio-11-ASPNET-45新功能(1).aspx

本文撰寫時使用的工具是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所示。

clip_image002

圖 1:透過Smart Task設定控制項屬性。

現在Visual Studio 11工具「Source View」編輯畫面也可以使用「Smart Task」,只要將滑鼠游標停留在控制項的開始標籤上方,就會自動顯示一條藍色的底線,只要點選它或按下「CTRL+ .」叫出「Smart Task」視窗,參考圖2所示。

clip_image004

圖 2:在「Source View」編輯畫面使用「Smart Task」。

在「Source View」編輯畫面也可以註冊事件,類似WPF應用程式的事件註冊動作。例如以下範例利用EntityDataSource透過ADO.NET Entity Data Model讀取AdventureWorks資料庫中Contacts資料表的ContactID、Title 與FirstName三個欄位的資料,透過資料繫結技術將資料呈現在GridView控制項中顯示。預設GridView控制項會使用BoundField來顯示資料:

 

<form id="form1" runat="server">
    <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所示:clip_image006

圖 5:註冊事件與建立事件處理常式。

這時只要按一次鍵盤的「Tab」鍵,就會自動產生事件處理常式,我在事件處理常式中,讀取目前伺服器的時間顯示在Label控制項上:

protected void EntityDataSource1_Selecting( object sender, EntityDataSourceSelectingEventArgs e )
    {
      Label1.Text = "Fetching Data : " + System.DateTime.Now.ToString();
    }

執行結果參考圖4所示:

clip_image008

圖 4:執行結果。

 

封裝使用者控制項

在設計網頁時,有時我們會將經常出現的HTML標籤封裝成利於重複使用的單位- 使用者控制項(User Control,附檔名為ASCX檔案),以便在網頁中重複地使用。Visual Studio 11 Beta提供一個小技巧,可以將網頁中的標籤封裝成ASCX檔案。例如,ASPX網頁中包含以下三個控制項:Label、TextBox與RequiredFieldValidator:

<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 的HTML編輯工具中,可以將這些HTML標籤選取,然後按滑鼠右鍵,從突顯式選單中選取「Extract to User Control」選項,參考圖5所示:

clip_image010

圖 5:Extract to User Control。

接著你就會看到「Save as」對話盒,你可以輸入想要使用的使用者控制項的檔案名稱,參考圖6所示:

clip_image012

圖 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控制項:

<%@ Page Language = "C#" AutoEventWireup = "true" CodeFile = "3_UCDemo.aspx.cs" Inherits = "_3_UCDemo" %>
<!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控制項上:

public partial class _3_UCDemo : System.Web.UI.Page
{
  
    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所示。

clip_image014

圖 7:HTML智慧型感知功能。

 

HTML編輯工具 - HTML 5程式碼片段功能

在Visual Studio 11 Beta中撰寫支援HTML5網頁的動作變的更簡單了,只要善用HTML 5程式碼片段功能,就可以很快達成任務。例如想要在HTML網頁中加入一個清單方塊,可以輸入部份的HTML標籤,Visual Studio 11 Beta會自動提醒可以使用程式碼片段功能,參考圖8所示:

clip_image016

圖 8:HTML 5程式碼片段功能。

這時只要按下Tab鍵兩次,程式碼片段功能就會自動填入<li>項目,參考圖9所示:

clip_image018

圖 9:HTML 5程式碼片段功能。

 

HTML編輯工具 - HTML標籤自動重新命名

在編輯HTML標籤方面,Visual Studio 11 Beta開發工具提供一個貼心的功能,只要你修改了開頭或結尾標籤,它就會自動將相符的結尾、開頭標籤的自動重新命名。例如以下範例,當修改開頭的<title>標籤為<titl>時,結尾標籤就自動改為<titl>,參考圖10所示。

clip_image020

圖 10:HTML標籤自動重新命名。

 

HTML編輯工具 – 自動縮排

在Visual Studio 2010編輯HTML標籤時,當你輸入開頭標籤然後按下鍵盤Enter鍵時,除了幫你產生結尾的</div>之外,會將游標停留在結尾的</div>標籤之前,如下圖紅色標記所示:

clip_image022

圖 11:Visual Studio 2010 HTML縮排功能。

而Visual Studio 11 Beta則會在開頭<div>和結尾的</div>標籤之間插入一個空白行,並讓開頭標籤和結尾自動縮排對齊,然後將游標停留在空白行開頭,參考圖12所示:

clip_image024

圖 12:Visual Studio 11 Beta HTML縮排功能。

 

HTML編輯工具 – IntelliSense清單過濾功能

在Visual Studio 2010編輯HTML標籤時工具會透過IntelliSense功能表列出可使用的清單供開發者選擇,底下範例輸入「<di」字串,但是清單中還包含了其它非「<di」字串開頭的選項,參考圖13所示:

clip_image026

圖 13:Visual Studio 2010 IntelliSense清單。

而Visual Studio 11 Beta會自動進行篩選,將符合查詢條件的項目列出,參考圖14所示:

clip_image028

圖 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欄位值,我們可以改用樣版資料行來自顯示的內容:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ContactID"
        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所示:

clip_image030

圖 15:編輯GridView欄位。

參考圖16所示,只要選取欄位,然後點選「Field」對話盒右下方的「Convert this Field into a Template Field」超連結,就可以轉換成樣板資料行:

clip_image032

圖 16:將Bound Field轉換成樣板資料行。

透過上述步驟,將Title、FirstName、LastName欄位都轉換為TemplateField,此時工具自動產生出的HTML如下:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ContactID"
        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屬性,因此編譯時就會顯示錯誤訊息。

clip_image034

圖 19:在編譯階段便可以進行型別檢查。

在開發過程中,會提供IntelliSense的支援:

clip_image036

圖 18:設計階段的IntelliSense支援。

沒有留言:

總網頁瀏覽量