簡體   English   中英

在基頁類中使用用戶控件

[英]Using a user control in a base page class

我有一個繼承自Page的基頁類。 我們稱之為SpiffyPage。

我還有一個名為SpiffyControl的用戶控件。

然后我有一個aspx頁面,ViewSpiffyStuff.aspx,繼承自SpiffyPage。

在頁面加載時,SpiffyPage類應該將SpiffyControl注入到aspx頁面中。

問題是SpiffyControl是一個用戶控件,並且實例化后面的代碼必須訪問ASP命名空間,類似於:

ASP.controls_spiffycontrol_aspx MyControl;

但是SpiffyPage不是aspx頁面,它只是一個基頁,因此我無法訪問ASP命名空間,因此我無法實例化SpiffyControl以便注入它。

我怎樣才能實現目標?

編輯:

一個重點是我必須引用實際的控件類型,以便我可以為某些自定義屬性賦值。 這就是為什么像LoadControl這樣返回類型Control的函數在這種情況下不起作用。

在SpiffyControl中添加一個基類,如:

public class SpiffyBase : UserControl
{
    public void DoIt()
    {
        Response.Write("DoIt");
    }
}

然后你讓你的SpiffyControl繼承那個基類,比如:

public partial class SpiffyControl : SpiffyBase

那么你應該能夠從一個Basepage類做​​到這一點:

public class BasePage : Page
{
    protected override void OnLoad(EventArgs e)
    {
        var c = Page.LoadControl("SpiffyControl.ascx") as SpiffyBase;

        Page.Controls.Add(c);

        c.DoIt();
    }
}

我將在單獨的ASP.NET服務器控件項目中實現SpiffyControl,並從Web應用程序引用該項目。 這樣,控件將不會駐留在ASP命名空間中,而是位於您選擇的命名空間中,並且行為與任何其他服務器控件一樣。

更新:將用戶控件放入單獨的項目中的一個很好的副作用是它們與Web應用程序本身變得更加分離,這反過來又使它們更加可重用,並且根據它們的設計,也更加可測試。

你們是在開玩笑吧,我知道ASP.NET webforms是一個痛苦的經歷,但沒有人聽說過ClassName屬性,即

<%@ Control ClassName="SpiffyControl" Language="C#" AutoEventWireup="true" CodeFile="SpiffyControl.ascx.cs" Inherits="Controls_SpiffyControl"  %>

因此,原始的例子:

SpiffyControl spiffy = (SpiffyControl)LoadControl("~spiffy.ascx");

我不確定這是否會對您有所幫助,但有一個名為LoadControl的方法可以使用usercontrol文件名或usercontrol的類型動態加載用戶控件。 該方法位於System.Web.UI.TemplateControl類中。

Control userControl= LoadControl("usercontrol.ascx");
panelControl.Controls.Add(userControl);

您可以將SpiffyControl移動到庫中 - 這將為其提供更精確的命名空間,並允許您在其他項目中使用它。 但這有點復雜 - 你已經制作了UserControl,但它不能在庫中工作。 UserControls使用代碼隱藏模型 - 它們由兩個文件組成,一個標記和一個代碼。 庫似乎不支持代碼隱藏模型,因此您無法使用UserControl。 您需要將該用戶控件轉換為Web控件。

創建一個新的類庫項目。 打開項目的屬性,並將AssemblyName和Default Namespace設置為SpiffyLibrary。

現在我們需要轉換你的UserControl。 首先,在新庫中創建一個類。 將其稱為SpiffyControl,就像您現有的用戶控件一樣,但要使其繼承自System.Web.UI.WebControls.CompositeControl。

其次,打開現有用戶控件的代碼並復制類中的所有內容。 然后返回到新類並將其全部粘貼到內部。 如果您正在使用任何標准控件事件,則可能需要重命名這些函數以覆蓋相應的事件。 例如,

protected void Page_Load(object sender, EventArgs e)
{
    ...
}

......應該成為......

protected override void OnLoad(EventArgs e)
{
    ...

    base.OnLoad(e);
}

第三個(這是復雜的部分)你需要重現你在SpiffyControl的標記文件中的所有標記。 您不能只復制它 - 而是需要覆蓋從CompositeControl繼承的CreateChildControls()函數。 標記中的每個標記都需要像變量一樣進行實例化,並添加到類的Controls集合中。 例如,如果您現有的標記文件如下所示:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="SpiffyControl.ascx.cs" Inherits="Controls_SpiffyControl" %>

<div id="Div1" runat="server">
    <asp:Label ID="TextOutput" runat="server" />
</div>

...然后你的新CreateChildControls函數應如下所示:

HtmlGenericControl Div1;
Label TextLabel;

protected override void CreateChildControls()
{
    Div1 = new HtmlGenericControl("div");
    this.Controls.Add(Div1);

    TextLabel = new Label();
    Div1.Controls.Add(TextLabel);

    base.CreateChildControls();
}

請注意,控件聲明為類字段; 這樣,它們對所有類方法都可見。

轉換標記后,編譯庫項目並將其添加到網站項目的引用中。 然后打開您網站的web.config文件並找到system.web / pages / controls部分。 此部分應該已經有這樣的標記:

<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

該標記允許您使用ASP核心庫中的控件。 所以我們要為我們的庫添加一個就像它一樣:

<add tagPrefix="spiffy" namespace="SpiffyLibrary" assembly="SpiffyLibrary" />

現在,您網站中的任何位置都可以添加如下標記:

<spiffy:SpiffyControl ID="SpiffyInstance" runat="server" />

...這將從您的自定義庫加載您的Web控件。

如果我正確地讀到這個,那么原始海報就會遇到這樣的問題,即他無法訪問父網頁在其UserControl中派生的基類的類型 ,而不是相反。 碰巧我遇到了同樣的問題。

在我的情況下,我的項目中的所有頁面都從相同的基礎繼承,所以我不擔心我的用戶控件知道頁面的基類。 向建築師道歉。

但是,我通過以下方法解決了這個問題:1)使用基類進行用戶控制,2)使用公共名稱空間。 這啟用了我需要的可見性,因為由於某種原因,用戶控件的基類仍然無法看到頁面基類的基類類型。

無論如何,我只是想我會分享我的結果,以防他們將來幫助別人。

HTH。

即使您的基礎不是ASPX頁面,您也可以從相同的框架類繼承它,就好像它是:

public abstract class MyBasePage : System.Web.UI.Page
{

}

假設SpiffyControl和SpiffyPage在同一名稱空間中:

 Control spiffyControl = LoadControl("SpiffyControl.ascx");
 (control as SpiffyControl).SpiffyControlProp1 = true;
 (control as SpiffyControl).SpiffyControlProp2 = "Hello, World!";

您也可以手動定義SpiffyControl的命名空間。 為此,您需要更改代碼隱藏和標記。

在代碼隱藏中,將您的類包裝在命名空間塊中。 所以,如果你的課程是

public partial class Controls_SpiffyControl : System.Web.UI.UserControl
{
    ...
}

......然后把它改成......

namespace Spiffy
{
    public partial class Controls_SpiffyControl : System.Web.UI.UserControl
    {
        ...
    }
}

然后在標記中調整@Control標頭。 所以如果你的@Control標題是

<%@ Control
    Language="C#"
    AutoEventWireup="true"
    CodeFile="SpiffyControl.ascx.cs"
    Inherits="Controls_SpiffyControl" %>

......然后把它改成......

<%@ Control
    Language="C#"
    AutoEventWireup="true"
    CodeFile="SpiffyControl.ascx.cs"
    Inherits="Spiffy.SpiffyControl" %>

假設您將在支持反射的環境中運行,您可以使用這些方法。

private void SetValue(Control control, string propertyName, object value)
{
    Type type = control.GetType();
    PropertyInfo property = type.GetProperty(propertyName);
    property.SetValue(control, value, null);
}
private object GetValue(Control control, string propertyName)
{
    Type type = control.GetType();
    PropertyInfo property = type.GetProperty(propertyName);
    return property.GetValue(control, null);
}

並稱之為:

     Control control = this.LoadControl("~/SpiffyControl.ascx");
    string propertyName = "Custom1";
    object value = "Value";

    SetValue(control, propertyName, value);

如果它被調用很多,你可能想要緩存Type信息。

您還可以考慮在SpiffyPage所在的程序集中創建一個ISpiffyControl接口,然后讓您的用戶控件實現它。

它已被觸及,但界面應該有效。 使用任何成員/方法創建ISpiffyControl,在SpiffyControl.ascx.vb中實現它並在SpiffyPage中執行此操作:

Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
    MyBase.OnLoad(e)
    Dim page As New Page
    Dim path As String = request.ApplicationPath
    Dim control as UI.Control = page.LoadControl(String.Format _
        ("{0}/pathToUserControl/{1}.ascx", path, controlName))
    Dim sc As ISpiffyControl = CType(control, ISpiffyControl)
    sc.DoSomethingSpecial()
    Me.Controls.Add(sc)
End Sub

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM