主版頁面與 ASP.NET AJAX (VB)

作者 :Scott Mitchell

討論使用 AJAX 和主版頁面 ASP.NET 選項。 查看使用 ScriptManagerProxy 類別;討論如何根據 ScriptManager 在主版頁面或內容頁面中使用 ScriptManager 來載入各種 JS 檔案。

簡介

過去數年,更多開發人員已建置已啟用AJAX的Web應用程式。 啟用 AJAX 的網站會使用許多相關的 Web 技術來提供更具回應性的用戶體驗。 由於 Microsoft 的 AJAX 架構 ASP.NET AJAX 架構,建立已啟用 AJAX 的 ASP.NET 應用程式十分容易。 ASP.NET AJAX 內建於 ASP.NET 3.5 和 Visual Studio 2008;它也可作為 ASP.NET 2.0 應用程式的個別下載。

使用 ASP.NET AJAX 架建構置已啟用 AJAX 的網頁時,您必須將精確一個 ScriptManager 控制項新增至使用架構的每個頁面和每個頁面。 如同其名稱,ScriptManager 會管理啟用 AJAX 之網頁中使用的用戶端腳本。 ScriptManager 至少會發出 HTML,指示瀏覽器下載可讓 ASP.NET AJAX 用戶端連結庫的 JavaScript 檔案。 它也可以用來註冊自定義 JavaScript 檔案、已啟用腳本的 Web 服務和自定義應用程式服務功能。

如果您的網站使用主版頁面 (,因為它應該) ,您不一定需要在每一個內容頁面中新增 ScriptManager 控件;相反地,您可以將 ScriptManager 控制項新增至主版頁面。 本教學課程說明如何將 ScriptManager 控件新增至主版頁面。 它也會查看如何使用 ScriptManagerProxy 控件,在特定內容頁面中註冊自定義腳本和腳本服務。

注意

本教學課程不會探索使用 ASP.NET AJAX 架構來設計或建置已啟用 AJAX 的 Web 應用程式。 如需使用 AJAX 的詳細資訊,請參閱 ASP.NET AJAX 影片和教學課程,以及本教學課程結尾一節中所列的資源。

檢查 ScriptManager 控件發出的標記

ScriptManager 控件會發出標記,指示瀏覽器下載 ASP.NET AJAX 用戶端連結庫的 JavaScript 檔案。 它也會將一些內嵌 JavaScript 新增至初始化此連結庫的頁面。 下列標記顯示新增至包含 ScriptManager 控件之頁面轉譯輸出的內容:

<script src="/ASPNET_MasterPages_Tutorial_08_CS/WebResource.axd?d=T8EVk6SsA8mgPKu7_sBX5w2 t=633363040378379010" type="text/javascript"></script>

<script src="/ASPNET_MasterPages_Tutorial_08_CS/ScriptResource.axd?d=SCE1TCh8B24VkQIU5a8iJFizuPBIqs6Lka7GEkxo-6ROKNw5LVPCpF_pmLFR-R-p_Uf42Ahmr_SKd8lwgZUWb2uPJmfX0X_H6oLA50bniyQ1 t=633465688673751480" type="text/javascript"></script>

<script type="text/javascript">
//<![CDATA[
if (typeof(Sys) === 'undefined') throw new Error('ASP.NET Ajax client-side framework failed to load.');
//]]>
</script>

<script src="/ASPNET_MasterPages_Tutorial_08_CS/ScriptResource.axd?d=SCE1TCh8B24VkQIU5a8iJFizuPBIqs6Lka7GEkxo-6ROKNw5LVPCpF_pmLFR-R-phT96yZPngppiP_VXlN4Vz2RuVtvwDiQzF9xt42dUCiYjL0UylAJoyYzStwvObx0U0 t=633465688673751480" type="text/javascript"></script>

<script type="text/javascript">
//<![CDATA[
Sys.WebForms.PageRequestManager._initialize('ScriptManager1', document.getElementById('form1'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls([], [], [], 90);
//]]>
</script>

<script type="text/javascript">
//<![CDATA[
Sys.Application.initialize();
//]]>
</script>

標記 <script src="url"></script> 會指示瀏覽器在 url下載並執行JavaScript檔案。 ScriptManager 會發出三個這類標記;其中一個參考檔案 WebResource.axd,另一個則參考檔案 ScriptResource.axd。 這些檔案實際上不存在於您的網站中的檔案。 相反地,當其中一個檔案的要求抵達網頁伺服器時,ASP.NET 引擎會檢查查詢字串,並傳回適當的 JavaScript 內容。 這三個外部 JavaScript 檔案所提供的腳本會構成 AJAX 架構用戶端連結庫 ASP.NET。 ScriptManager 所發出的其他 <script> 標記包含初始化此連結庫的內嵌腳本。

對於使用 ASP.NET AJAX 架構的頁面而言,外部腳本參考和 ScriptManager 所發出的內嵌腳本是不可或缺的,但不需要用於不使用架構的頁面。 因此,您可能會認為只將 ScriptManager 新增至使用 ASP.NET AJAX 架構的頁面是理想的原因。 這已足夠,但如果您有許多使用架構的頁面,您最後會將 ScriptManager 控件新增至所有頁面,也就是重複的工作,以至少說出。 或者,您可以將 ScriptManager 新增至主版頁面,然後將這個必要的腳本插入所有內容頁面。 使用此方法時,您不需要記得將 ScriptManager 新增至使用 ASP.NET AJAX 架構的新頁面,因為它已經包含在主版頁面。 步驟 1 逐步解說如何將 ScriptManager 新增至主版頁面。

注意

如果您打算在主版頁面的使用者介面中包含 AJAX 功能,則您不需選擇, 您必須在主版頁面中包含 ScriptManager。

將 ScriptManager 新增至主版頁面的一個缺點是,不論其是否需要,上述腳本 都會在每個頁面中 發出。 這顯然會導致透過主版頁面 (包含 ScriptManager 的頁面浪費頻寬,) 尚未使用 ASP.NET AJAX 架構的任何功能。 但只會浪費多少頻寬?

  • ScriptManager 所發出的實際內容 (顯示於上述) 總計超過 1KB。
  • 不過,元素所 <script> 參考的三個外部腳本檔案包含大約 450 KB 的數據未壓縮;在使用 gzip 壓縮的網站中,此總頻寬可減少到接近 100KB。 不過,這些腳本檔案是由瀏覽器快取一年,這表示它們只需要下載一次,然後可以在網站上的其他頁面中重複使用。

在最佳情況下,當快取腳本檔案時,總成本為 1KB,這可忽略。 不過,在最糟的情況下,這是腳本檔案尚未下載且網頁伺服器未使用任何形式的壓縮時 , 帶寬點擊大約為 450KB,可透過寬頻連線將任何位置新增到超過撥號調製解調器的使用者最多一分鐘。 好消息是,因為瀏覽器會快取外部腳本檔案,所以這種最差的情況不常發生。

注意

如果您仍然覺得將 ScriptManager 控制件放在主版頁面中,請考慮 Web Form (<form runat="server"> 主版頁面中的標記) 。 使用回傳模型的每個 ASP.NET 頁面都必須精確包含一個 Web 窗體。 新增 Web 窗體會新增其他內容:一些隱藏的表單域、 <form> 標籤本身,並視需要從腳本起始回傳的 JavaScript 函式。 對於沒有回傳的頁面而言,不需要此標記。 從主版頁面移除 Web 窗體,並手動將它新增至需要 Web 窗體的每個內容頁面,即可消除這個多餘的標記。 不過,在主版頁面中擁有 Web 窗體的優點,大於將網頁窗體新增至特定內容頁面的缺點。

步驟 1:將 ScriptManager 控件新增至主版頁面

使用 ASP.NET AJAX 架構的每個網頁都必須包含一個 ScriptManager 控制件。 基於這項需求,在主版頁面上放置單一 ScriptManager 控件通常很合理,因此所有內容頁面都會自動包含 ScriptManager 控件。 此外,ScriptManager 必須位於任何 ASP.NET AJAX 伺服器控件之前,例如 UpdatePanel 和 UpdateProgress 控件。 因此,最好將 ScriptManager 放在 Web Form 中的任何 ContentPlaceHolder 控件之前。

Site.master開啟主版頁面,並將 ScriptManager 控件新增至 Web Form 中的頁面,但在元素之前 <div id="topContent"> (請參閱圖 1) 。 如果您使用 Visual Web Developer 2008 或 Visual Studio 2008,ScriptManager 控件位於 [AJAX 延伸模組] 索引卷標的 [工具箱] 中。如果您使用 Visual Studio 2005,您必須先安裝 ASP.NET AJAX 架構,並將控件新增至 [工具箱]。 請流覽 ASP.NET AJAX 下載頁面,以取得 ASP.NET 2.0 的架構。

將 ScriptManager 新增至頁面之後,將其 IDScriptManager1 變更為 MyManager

將 ScriptManager 新增至主版頁面

圖 01:將 ScriptManager 新增至主版頁面 (按兩下即可檢視完整大小的影像)

步驟 2:從內容頁面使用 ASP.NET AJAX Framework

將 ScriptManager 控制項新增至主版頁面後,我們現在可以將 AJAX 架構功能新增至任何內容頁面 ASP.NET。 讓我們建立新的 ASP.NET 頁面,以顯示 Northwind 資料庫中隨機選取的產品。 我們將使用 AJAX 架構的定時器控件 ASP.NET 每隔 15 秒更新此顯示,以顯示新產品。

首先,在名為 ShowRandomProduct.aspx的根目錄中建立新頁面。 別忘了將此新頁面系結至 Site.master 主版頁面。

將新的 ASP.NET 頁面新增至網站

圖 02:將新的 ASP.NET 頁面新增至網站 (按兩下即可檢視完整大小的影像)

回想一下,在主版頁面[SKM1] 中指定標題、中繼標籤和其他 HTML 標頭教學課程中,我們建立了名為 BasePage 的自定義基頁類別,並在未明確設定時產生頁面標題。 移至 ShowRandomProduct.aspx 頁面的程式代碼後置類別,並讓它衍生自 (,而不是衍生自 BasePageSystem.Web.UI.Page) 。

最後,更新 Web.sitemap 檔案以包含本課程的專案。 將下列標記新增至主版至內容頁面互動課程的 下方 <siteMapNode>

<siteMapNode url="~/ShowRandomProduct.aspx" title="Master Pages and ASP.NET AJAX" />

新增此 <siteMapNode> 元素會反映在 Lessons 清單中, (請參閱圖 5) 。

顯示隨機選取的產品

ShowRandomProduct.aspx傳回 。 從 Designer,將 UpdatePanel 控件從 [工具箱] 拖曳至 [內容] 控制項,MainContent並將其 ID 屬性設定為 ProductPanel。 UpdatePanel 代表螢幕上可透過部分頁面回傳以異步方式更新的區域。

我們的第一項工作是在UpdatePanel 中顯示隨機選取產品的相關信息。 首先,將 DetailsView 控件拖曳至 UpdatePanel。 將 DetailsView 控件的 ID 屬性設定為 ProductInfo ,並清除其 HeightWidth 屬性。 展開 DetailsView 的智慧標記,然後從 [選擇數據源] 下拉式清單中,選擇將 DetailsView 系結至名為 RandomProductDataSource的新 SqlDataSource 控件。

將 DetailsView 系結至新的 SqlDataSource 控件

圖 03:將 DetailsView 系結至新的 SqlDataSource 控件 (按兩下即可檢視大小完整的影像)

設定 SqlDataSource 控制件,以透過 NorthwindConnectionString 我們在內容頁面[SKM2] 教學課程中建立的 (連線到 Northwind 資料庫) 。 設定 select 語句時,選擇指定自訂 SQL 語句,然後輸入下列查詢:

SELECT TOP 1 ProductName, UnitPrice
FROM Products
ORDER BY NEWID()

TOP 1子句中的 SELECT 關鍵詞只會傳回查詢傳回的第一筆記錄。 函 NEWID() 式會產生新的全域唯一標識符值 (GUID) ,而且可用於 子句, ORDER BY 以隨機順序傳回數據表的記錄。

設定 SqlDataSource 以傳回單一隨機選取的記錄

圖 04:將 SqlDataSource 設定為傳回單一隨機選取的記錄 (按兩下即可檢視完整大小的影像)

完成精靈之後,Visual Studio 會為上述查詢所傳回的兩個數據行建立 BoundField。 此時,頁面的宣告式標記看起來應該如下所示:

<asp:UpdatePanel ID="ProductPanel" runat="server">
 <ContentTemplate>
 <asp:DetailsView ID="ProductInfo" runat="server" AutoGenerateRows="False" 
 DataSourceID="RandomProductDataSource">
 <Fields>
 <asp:BoundField DataField="ProductName" HeaderText="ProductName" 
 SortExpression="ProductName" />
 <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" 
 SortExpression="UnitPrice" />
 </Fields>
 </asp:DetailsView>
 <asp:SqlDataSource ID="RandomProductDataSource" runat="server" 
 ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT TOP 1 ProductName, UnitPrice FROM Products ORDER BY NEWID()"></asp:SqlDataSource>
 </ContentTemplate>
</asp:UpdatePanel>

圖 5 顯示 ShowRandomProduct.aspx 透過瀏覽器檢視時的頁面。 按兩下瀏覽器的 [重新整理] 按鈕以重載頁面;您應該會看到新隨機選取記錄的 ProductNameUnitPrice 值。

隨機產品名稱和價格隨即顯示

圖 05:隨機產品名稱和價格隨即顯示, (按兩下即可檢視大小完整的影像)

每隔 15 秒自動顯示新產品

ASP.NET AJAX 架構包含定時器控制項,可在指定時間執行回傳;在回傳時,會引發定時器的 Tick 事件。 如果 Timer 控件放在 UpdatePanel 內,則會觸發部分頁面回傳,在此期間,我們可以將數據重新繫結至 DetailsView 以顯示新的隨機選取的產品。

若要達成此目的,請將定時器從 [工具箱] 拖曳到 UpdatePanel 中。 將 Timer 的 IDTimer1 變更為 ProductTimer ,並將其 Interval 屬性從 60000 變更為 15000。 屬性 Interval 指出回傳之間的毫秒數;將它設定為15000會導致定時器每隔15秒觸發部分頁面回傳。 此時,定時器的宣告式標記看起來應該類似下列內容:

<asp:UpdatePanel ID="ProductPanel" runat="server" onload="ProductPanel_Load">
 <ContentTemplate>
 ...

 <asp:Timer ID="ProductTimer" runat="server" Interval="15000">
 </asp:Timer>
 </ContentTemplate>
</asp:UpdatePanel>

建立定時器 Tick 事件的事件處理程式。 在此事件處理程式中,我們需要呼叫 DetailsView 的 DataBind 方法,將數據重新系結至 DetailsView。 這麼做會指示 DetailsView 從數據源控件重新擷取數據,這會選取並顯示新的隨機選取的記錄 (,就像單擊瀏覽器的 [重新整理] 按鈕) 重載頁面一樣。

Protected Sub ProductTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ProductTimer.Tick
 ProductInfo.DataBind()
End Sub

就是這麼簡單! 透過瀏覽器重新瀏覽頁面。 一開始會顯示隨機產品的資訊。 如果您耐心 watch 畫面,您會注意到,在15秒後,新產品的相關信息會以令人驚奇的方式取代現有的顯示器。

為了更清楚地瞭解此處發生的情況,讓我們將 Label 控件新增至 UpdatePanel,以顯示顯示上次更新顯示的時間。 在 UpdatePanel 中新增標籤 Web 控件、將其 ID 設定為 LastUpdateTime,並清除其 Text 屬性。 接下來,建立 UpdatePanel 事件的事件處理程式, Load 並在 Label 中顯示目前的時間。 (UpdatePanel 的事件 Load 會在每次完整或部分頁面回傳時引發。)

Protected Sub ProductPanel_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles ProductPanel.Load
 LastUpdateTime.Text = "Last updated at " & DateTime.Now.ToLongTimeString()
End Sub

完成這項變更后,頁面會包含載入目前顯示產品的時間。 圖 6 顯示第一次瀏覽時的頁面。 圖 7 顯示定時器控件「刻度」之後的頁面 15 秒,並已重新整理 UpdatePanel 以顯示新產品的相關信息。

隨機選取的產品會顯示在頁面載入時

圖 06:隨機選取的產品會顯示在頁面載入 (按一下以檢視大小完整的影像)

每15秒會顯示新的隨機選取產品

圖 07:每 15 秒會顯示新的隨機選取產品 (按兩下即可檢視大小完整的影像)

步驟 3:使用 ScriptManagerProxy 控件

除了包含 ASP.NET AJAX 架構用戶端連結庫的必要腳本之外,ScriptManager 也可以註冊自定義 JavaScript 檔案、啟用腳本的 Web 服務參考,以及自定義驗證、授權和配置檔服務。 這類自定義通常是特定頁面特有的。 不過,如果自定義腳本檔案、Web 服務參考或驗證、授權或配置檔服務是在主版頁面中的 ScriptManager 中參考,則會將它們包含在網站的所有頁面中。

若要逐頁新增 ScriptManager 相關自定義,請使用 ScriptManagerProxy 控制件。 您可以將 ScriptManagerProxy 新增至內容頁面,然後從 ScriptManagerProxy 註冊自定義 JavaScript 檔案、Web 服務參考或驗證、授權或配置檔服務;這會影響針對特定內容頁面註冊這些服務。

注意

ASP.NET 頁面只能有一個以上的 ScriptManager 控件。 因此,如果主版頁面中已經定義 ScriptManager 控件,則您無法將 ScriptManager 控制項新增至內容頁面。 ScriptManagerProxy 的唯一目的是要讓開發人員在主版頁面中定義 ScriptManager,但仍能夠逐頁新增 ScriptManager 自定義。

若要查看 ScriptManagerProxy 控件的運作情形,讓我們增強中的 ShowRandomProduct.aspx UpdatePanel,以包含使用用戶端腳本暫停或繼續定時器控件的按鈕。 定時器控制件有三種用戶端方法,可用來達成此所需功能:

  • _startTimer() - 啟動定時器控制件
  • _raiseTick() - 導致定時器控件「刻度」,藉此在伺服器上回傳並引發其 Tick 事件
  • _stopTimer() - 停止定時器控制件

讓我們建立名為的變數和名為的函 timerEnabled 式的 ToggleTimerJavaScript 檔案。 timerEnabled變數會指出定時器控件目前是否已啟用或停用;它預設為 true。 函 ToggleTimer 式接受兩個輸入參數:暫停/繼續按鈕的參考,以及定時器控件的用戶端 id 值。 此函式會切換 的值 timerEnabled、取得定時器控件的參考、根據) 的值 timerEnabled 啟動或停止 Timer (,並將按鈕的顯示文字更新為 “Pause” 或 “Resume”。 每當按兩下 [暫停/繼續] 按鈕時,就會呼叫此函式。

首先,在名為 Scripts的網站中建立新的資料夾。 接下來,將新檔案新增至類型為 JScript 檔案的 Scripts 資料夾 TimerScript.js

將新的 JavaScript 檔案新增至腳本資料夾

圖 08:將新的 JavaScript 檔案新增至 Scripts 資料夾 (按兩下以檢視大小完整的映像)

已將新的 JavaScript 檔案新增至網站

圖 09:已將新的 JavaScript 檔案新增至網站 (按兩下即可檢視完整大小的影像)

接下來,將下列 Scrip 新增至 TimerScript.js 檔案:

var timerEnabled = true;
function ToggleTimer(btn, timerID)
{
    // Toggle the timer enabled state
    timerEnabled = !timerEnabled;

    // Get a reference to the Timer
    var timer = $find(timerID);

    if (timerEnabled)
    {
        // Start timer
        timer._startTimer();

        // Immediately raise a tick
        timer._raiseTick();

        btn.value = 'Pause';
    }
    else
    {
        // Stop timer
        timer._stopTimer();

        btn.value = 'Resume';
    }
}

我們現在需要在 中 ShowRandomProduct.aspx註冊這個自定義JavaScript檔案。 ShowRandomProduct.aspx傳回 ,並將 ScriptManagerProxy 控制項新增至頁面;將其ID設定為 MyManagerProxy。 若要註冊自定義 JavaScript 檔案,請選取 Designer 中的 ScriptManagerProxy 控件,然後移至 屬性視窗。 其中一個屬性標題為腳本。 選取此屬性會顯示圖 10 中顯示的 ScriptReference 集合 編輯器。 按兩下 [新增] 按鈕以包含新的腳本參考,然後在Path屬性中輸入腳本檔案的路徑: ~/Scripts/TimerScript.js

將腳本參考新增至 ScriptManagerProxy 控制件

圖 10:將腳本參考新增至 ScriptManagerProxy 控件 (按兩下即可檢視大小完整的映像)

新增腳本參考之後,ScriptManagerProxy 控件的宣告式標記會更新為包含 <Scripts> 具有單 ScriptReference 一專案的集合,如下列標記代碼段所示:

<asp:ScriptManagerProxy ID="MyManagerProxy" runat="server">
 <Scripts>
 <asp:ScriptReference Path="~/Scripts/TimerScript.js" />
 </Scripts>
</asp:ScriptManagerProxy>

ScriptReference 專案會指示 ScriptManagerProxy 在其轉譯標記中包含 JavaScript 檔案的參考。 也就是說,藉由在 ScriptManagerProxy 中註冊自定義腳本, ShowRandomProduct.aspx 頁面的轉譯輸出現在會包含另一個 <script src="url"></script> 標籤: <script src="Scripts/TimerScript.js" type="text/javascript"></script>

我們現在可以從頁面的用戶端腳本呼叫 ToggleTimerTimerScript.jsShowRandomProduct.aspx定義的函式。 在 UpdatePanel 中新增下列 HTML:

<input type="button" id="PauseResumeButton" 
    value="Pause" 
    onclick="ToggleTimer(this, '<%=ProductTimer.ClientID %>');" />

這會顯示含有「暫停」文字的按鈕。 每當按兩下時,就會呼叫 JavaScript 函式 ToggleTimer ,並傳入按鈕的參考,以及 id 定時器控件的值 (ProductTimer) 。 請注意取得 id Timer 控件值的語法。 <%=ProductTimer.ClientID%>ProductTimer會發出 Timer 控件ClientID的 屬性值。 在內容頁面的控件識別碼命名[SKM3] 教學課程中,我們討論伺服器端ID值與產生的用戶端值之間的差異,以及如何ClientID傳回用戶端 idid

圖 11 會在第一次瀏覽瀏覽器時顯示此頁面。 定時器目前正在執行,並每隔 15 秒更新顯示的產品資訊。 圖 12 顯示按兩下 [暫停] 按鈕之後的畫面。 按兩下 [暫停] 按鈕會停止定時器,並將按鈕的文字更新為 「繼續」。 當使用者按兩下 [繼續] 後,產品資訊會重新整理 (,並每隔15秒繼續重新整理一次) 。

按兩下 [暫停] 按鈕以停止定時器控制件

圖 11:按兩下 [暫停] 按鈕以停止定時器控件 (按兩下以檢視大小完整的影像)

按兩下 [繼續] 按鈕以重新啟動定時器

圖 12:按兩下 [繼續] 按鈕以重新啟動定時器 (按兩下以檢視大小完整的映像)

摘要

使用 ASP.NET AJAX 架構建置已啟用 AJAX 的 Web 應用程式時,每個已啟用 AJAX 的網頁都包含 ScriptManager 控件是不可或缺的。 為了方便進行此程式,我們可以將 ScriptManager 新增至主版頁面,而不需要記得將 ScriptManager 新增至每個和每個內容頁面。 步驟 1 示範如何在內容頁面中實作 AJAX 功能時,將 ScriptManager 新增至主版頁面。

如果您需要將自定義腳本、啟用腳本的 Web 服務參考,或自定義的驗證、授權或設定檔服務新增至特定內容頁面,請將 ScriptManagerProxy 控件新增至內容頁面,然後在該處設定自定義。 步驟 3 已檢查如何使用 ScriptManagerProxy 在特定內容頁面中註冊自定義 JavaScript 檔案。

快樂的程序設計!

深入閱讀

如需本教學課程中討論之主題的詳細資訊,請參閱下列資源:

關於作者

Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,且 4GuysFromRolla.com 的作者,自 1998 年以來,已與 Microsoft Web 技術合作。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 3.5。 Scott 可以透過 mitchell@4GuysFromRolla.com 在 上的部落格或透過 http://ScottOnWriting.NET其部落格來連線。

特別感謝

本教學課程系列是由許多實用的檢閱者所檢閱。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com