[英]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.