2011-12-16 32 views
1

我的理解是,當使用<%Register%>標籤在aspx頁面中定義組件或自定義控件時,它會由編譯器在自動生成的designer.cs(C#)文件中聲明。如果這個自定義控件從未在aspx頁面中使用過,這是否仍然在designer.cs文件中發生?自定義控件在asp.net中如何實例化?

假設控件在aspx頁面中使用,那麼什麼機制實例化這個控件,它是如何在幕後新建的?設計器文件只聲明它。非常感謝,如果有很好的文章討論這個,我很樂意閱讀它們。

回答

1

這可能不會回答你所有的問題,但其中一些問題。裏克施特拉爾寫了一篇很好的文章而回上編譯和部署描述它是如何工作的:

Compilation and Deployment in ASP.NET 2.0

我補充說,我認爲涉及最下方你的問題的文章的一部分:

引用其他頁面和控件

請記住,頁面和控件編譯發生在每個目錄的基礎上!因此,引用其他頁面和控件對於ASP.NET 2.0來說變得更加棘手,因爲您不能再假設當前程序集中可以使用來自其他頁面或控件的CodeBeside類。最好的情況是,同一個目錄中的所有頁面和控件最終都在同一個程序集中,最壞的情況是每個頁面或控件都有自己的程序集,並且它們對彼此一無所知。

如果您需要從控件或其他頁面引用另一個頁面,則需要使用@Reference指令顯式地將其導入。這與ASP.NET 1.1不同,後者的所有CodeBehind類都可以立即用於整個Web應用程序。在ASP.NET 2.0中,需要顯式彙編引用來加載它。

假設你有DataEntry.aspx頁面我剛纔展示的一分鐘,你想創建第二個頁面使用相同的CodeBeside類,所以你可以重用頁面邏輯,但改變DataEntry2.aspx中的頁面佈局通過改變一些顏色並圍繞頁面的控件移動。實質上,你希望有兩個ASPX頁面引用相同的CodeBeside文件。

這裏是如何做到這一點:

<%@ Reference Page="~/DataEntry.aspx" %>  
<%@ Page Language="C#" AutoEventWireup="true" Inherits="DataEntry" %> 

我要離開了的CodeFile屬性引用CodeBeside類的DataEntry頁,而@Reference標籤添加到頁面迫使CodeBeside類是進口。

對於任何用戶控制定義也是如此。要導入用戶控件,您需要使用@Register標記,該標記導入控件所在的程序集。ASP.NET在編譯期間非常靈活,並根據項目的編譯方式精確計算相關程序集的位置。如果控件或頁面位於同一個程序集中,則實際上不會添加引用。但是,如果它是外部的 - 例如在另一個目錄中,則會添加程序集引用。

引用問題

如果你可以明確地引用您的標記網頁的其他頁面和控件,然後一切運作良好,並預期。但是,如果您在代碼中動態加載控件或引用頁面,事情會變得更加複雜。

我遇到的最常見的問題是動態加載控件。在ASP.NET 1.x中,你可能會像這樣運行的代碼動態加載控件到頁面:

public partial class DynamicControlLoading : System.Web.UI.Page  
{  
    protected CustomUserControl MessageDisplay = null; 

    protected void Page_Load(object sender, EventArgs e)  
    {  
     MessageDisplay = this.LoadControl("~/UserControls/CustomUserControl.ascx") as CustomUserControl; 

     this.Controls.Add(MessageDisplay); 

    } 

    protected void btnSay_Click(object sender, EventArgs e)  
    {  
     this.MessageDisplay.ShowMessage(this.txtMessage.Text); 

    } 

} 

CustomUserControl在這種情況下是一個簡單的用戶控制,生活在其他目錄,並在運行時動態加載。進一步假設你真的動態地想要加載這個控件,以便你可以選擇幾個控件,或者最終用戶甚至可以創建一個自定義控件來代替它。

如果你運行上面的ASP.NET 2.0中它很可能會失敗的代碼。我之所以說,可能是因爲有些不一致有時會自動獲取控件引用,例如,如果用戶控件位於同一個目錄中並被編譯爲與頁面相同的程序集,或者另一個頁面引用了該控件。

它應該並且通常會失敗。爲什麼?由於ASP.NET在目錄級別編譯,並且CustomUserControl位於單獨的目錄中,因此會進入單獨的程序集。頁面類不可見,以獲得強類型引用。對於MessageDisplay控件,Intellisense將顯示一個大而胖的紅色感嘆號或根本沒有。當你運行該頁面時,它將會彈出。

您可以參考的控制當然的控制類型,但如果你需要在無法控制屬性的用戶控件訪問任何自定義屬性,你不能,除非你採取反思。據我所知,沒有辦法以編程方式添加對其他用戶控件或頁面的引用,因爲在您的代碼運行之前,需要在編譯時更早提供引用。

替代物是不加載控件動態或至少提供了一些機制來在頁面上預先加載了任何用戶控制與適當@Register標籤。但這並不總是可能的。另一種選擇是在APP_CODE中創建用戶控件基類,並在其中公開該公共接口。主要的問題是這個基類將無法訪問用戶控件的任何內部控件,因此基類將不得不使用FindControl來引用任何嵌入式控件。所以這是低效的,而且很麻煩。

我遇到了類似的情況與繼承場景。例如,從另一個的CodeBeside類繼承一個母版頁。一切正常,但ASP.NET編譯器抱怨Profile對象被非法覆蓋(編譯器警告)。使用繼承的母版頁運行,但有怪癖。添加到母版頁的用戶控件通常會因類型衝突而失敗,因爲ASP.NET會將添加到基頁的用戶控件視爲與添加到第二頁的用戶控件不同的類型。

這些不一致之處引用了其他類型,這些類型導致我浪費了大量的時間,認爲我有一些問題只是爲了後來發現,當我更改完全不同的頁面時,它實際上並不一致。更糟糕的是,你必須真正理解這個模型才能解決可能出錯的問題。

底線:整體ASP.NET 2.0編譯模型是內部複雜。大多數時候你不需要理解它,但是當你遇到這些邊界情景時,你真的必須瞭解幕後發生的事情,以便能夠解決怪癖。

+0

你能總結一下這篇文章嗎?萬一鏈接爛了,所以人們不會有鏈接? – Oded 2011-12-16 17:53:30