代码之家  ›  专栏  ›  技术社区  ›  Pete Michaud

在基页类中使用用户控件

  •  7
  • Pete Michaud  · 技术社区  · 17 年前

    我还有一个名为SpiffyControl的用户控件。

    然后我有一个aspx页面ViewSpiffyStuff.aspx,它继承自SpiffyPage。

    在页面加载时,SpiffyPage类应该将一个SpiffyControl注入到aspx页面中。

    问题在于SpiffyControl是一个用户控件,要在代码中实例化它,必须访问ASP命名空间,类似于:

    ASP.controls_spiffycontrol_aspx MyControl;
    

    但是SpiffyPage不是一个aspx页面,它只是一个基本页面,因此我无法访问ASP命名空间,因此我无法实例化SpiffyControl来注入它。

    我怎样才能实现我的目标?

    11 回复  |  直到 17 年前
        1
  •  10
  •   Johan Leino    17 年前

    向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();
        }
    }
    
        2
  •  4
  •   Fredrik Mörk    17 年前

    更新:将用户控件放到单独的项目中的一个很好的副作用是,它们与web应用程序本身更加解耦,这反过来又会使它们更加可重用,并且根据它们的设计,也更加可测试。

        3
  •  2
  •   pkaeding    17 年前

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

    因此,原始示例:

    SpiffyControl spiffy = (SpiffyControl)LoadControl("~spiffy.ascx");
    
        4
  •  1
  •   CSharpAtl    17 年前

    Control userControl= LoadControl("usercontrol.ascx");
    panelControl.Controls.Add(userControl);
    
        5
  •  1
  •   The Digital Gabeg    17 年前

    您可以将SpiffyControl移动到库中—这将为它提供更精确的命名空间,并允许您在其他项目中使用它。虽然这有点复杂-您已经创建了一个UserControl,但它在库中不起作用。UserControls使用codebehind模型-它们由两个文件组成,一个标记和一个代码。库似乎不支持codebehind模型,因此不能使用UserControl。您需要将该用户控件转换为web控件。

    创建一个新的类库项目。打开项目的属性,并将AssemblyName和默认命名空间设置为SpiffyLibrary。

    现在我们需要转换你的用户控件。首先,在新库中创建一个类。将其称为SpiffyControl,就像您现有的用户控件一样,但要使其继承自System.Web.UI.WebControl.CompositeControl。

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

    ... 应该成为。。。

    protected override void OnLoad(EventArgs e)
    {
        ...
    
        base.OnLoad(e);
    }
    

    <%@ 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();
    }
    

    注意,控件被声明为类字段;这样,所有类方法都可以看到它们。

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

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

    现在,您可以在站点中的任何位置输入如下标记:

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

    ... 这将从自定义库加载web控件。

        6
  •  0
  •   Geoff    17 年前

    public abstract class MyBasePage : System.Web.UI.Page
    {
    
    }
    
        7
  •  0
  •   Tyler    17 年前

    假设SpiffyControl和SpiffyPage位于同一命名空间中:

     Control spiffyControl = LoadControl("SpiffyControl.ascx");
     (control as SpiffyControl).SpiffyControlProp1 = true;
     (control as SpiffyControl).SpiffyControlProp2 = "Hello, World!";
    
        8
  •  0
  •   The Digital Gabeg    17 年前

    您也可以手动定义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" %>
    
        9
  •  0
  •   Sean Lynch    17 年前

    假设您将在支持反射的环境中运行,则可以使用这些方法。

    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);
    

    如果它被多次调用,您可能需要缓存类型信息。

        10
  •  0
  •   ironsam    17 年前

    它已经被提到了,但是一个界面应该可以工作。使用任何成员/方法创建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
    
        11
  •  0
  •   InteractiveLogic    17 年前

    如果我没看错的话,原来的海报有一个问题

    在我的例子中,我的项目中的所有页面都继承自同一个基类,因此我不担心我的用户控件知道页面的基类这一事实。向建筑师道歉。

    但是,我解决了这个问题,1)使用基类作为用户控件,2)使用公共名称空间。这启用了我需要的可见性,因为出于某种原因,用户控件的基类仍然无法看到页面基类的基类类型。

    嗯。