在ASP中使用其他项目中的用户控件

6
我想在其他项目中重复使用我的ASP用户控件,但遇到了问题。 我已经阅读了ScottGu关于http://weblogs.asp.net/scottgu/archive/2005/08/28/423888.aspx的文章,并尝试按照他的模式进行操作,但是在运行时,我的控件的子控件未被初始化。
我的设置: 我正在使用Visual Studio 2008 我创建了一个解决方案来保存我要分发到几个其他解决方案的控件。 这个解决方案包含: -库项目(用于模型代码等),让我们称之为“ClassLibrary” -一个WebApp项目(带有我的用户控件),让我们称之为“Innermost” -多个其他WebApp项目作为Innermost项目的外壳,让我们把其中一个称为“Outer”
这背后的想法是Innermost包含功能,而Outer包含使Innermost控件在特定框架中工作所需的任何特殊修改。

类库的代码如下(这是我制作的演示设置,以确保它是ASP问题,而不是我在做其他事情):

using System;

namespace ClassLibrary {
    public class LibraryClass {
        public long getLong() {
            return DateTime.Now.Ticks;
        }

        public string getString() {
            return DateTime.Now.ToString();
        }
    }
}

Innermost引用了库项目并且运行正常。这是该项目中一个UserControl的示例:

<%@ Control Language="C#" AutoEventWireup="true" 
    CodeBehind="WebUserControl1.ascx.cs" 
    Inherits="Innermost.UserControls.WebUserControl1" %>
<asp:Label ID="testLabel" runat="server"/>

带有代码后台:
using System;
using System.Web.UI;
using ClassLibrary;

namespace Innermost.UserControls {
    public partial class WebUserControl1 : UserControl {
        protected void Page_Load(object sender, EventArgs e) {
            LibraryClass c = new LibraryClass();
            testLabel.Text = "Your number is " + c.getLong();
        }
    }
}

我在Innermost项目中有一个测试页面,通过以下语法注册Innermost项目的用户控件来使用它们:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Test1.aspx.cs" 
    Inherits="Innermost.Test1" %>

<%@ Register TagPrefix="inner" TagName="Control1" 
    Src="~/UserControls/WebUserControl1.ascx" %>
<%@ Register TagPrefix="inner" TagName="Control2"
    Src="~/UserControls/WebUserControl2.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
    Control 1:
    <inner:Control1 ID="control1" runat="server" />
    <br />
    Control 2:
    <inner:Control2 ID="control2" runat="server" />
</div>
</form>
</body>
</html>

Outer项目引用了Innermost和ClassLibrary;并包含以下注册Innermost控件的UserControls:

<%@ Control Language="C#" AutoEventWireup="true" 
    CodeBehind="TopControl.ascx.cs" Inherits="Outer.Control.TopControl" %>
<%@ Register TagPrefix="inner" Assembly="Innermost"
    Namespace="Innermost.UserControls" %>
<inner:WebUserControl1 ID="Control1" runat="server"/>
<inner:WebUserControl2 ID="Control2" runat="server"/>

使用简单的代码后台: using System; using System.Web.UI;

namespace Outer.Control {
    public partial class TopControl : UserControl {
        public bool ShowType1 { get; set; }

        protected void Page_Load(object sender, EventArgs e) {
            Control1.Visible = ShowType1;
            Control2.Visible = !ShowType1;
        }
    }
}

当我在Innermost项目中运行测试页面时,没有错误,一切正常。但是当我在Outer项目中运行时,会出现NullReferenceException异常,告诉我Innermost.UserControls.WebUserControlX的子控件未被设置。
堆栈跟踪:
[NullReferenceException: Object reference not set to an instance of an object.]
   Innermost.UserControls.WebUserControl1.Page_Load(Object sender, EventArgs e) in c:\Test\ASP\Innermost\Innermost\UserControls\WebUserControl1.ascx.cs:9
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +50
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627

我可以提供测试设置作为解决方案,如果有人想更仔细地查看这个。
所以,最后,我的问题是:为什么控件的ChildControls没有按照预期设置?即使我在外部控件的Init中运行CreateChildControls(),它们也不会被创建。我需要以某种特定的方式编译Innermost项目才能在Outer项目中使用吗?
非常感谢任何帮助!
1个回答

7
我以前从未尝试过这种设置,但我可以猜测正在发生的事情。UserControls应该通过路径加载,而不是引用加载。您正试图通过引用创建它们。请注意您在内部项目中如何引用它们并且与外部项目不同的方式。我认为,要使其工作,您需要引用.ascx文件的路径位置。
快速搜索显示如何在VS 2005中执行此操作,但在VS 2008中概念应该是相同的。您可以在此处找到该信息。
另一种选择是不使用设计表面,而是使用LoadControl方法加载控件,传递.ascx文件的路径。
编辑 从我上面提到的链接中重要的是,您必须使.ascx文件可访问您的外部应用程序。以上链接通过使用预生成命令将.ascx文件复制到外部项目的子文件夹中来实现此目的。想象一下内部项目就像您要重新分发它一样。您必须不仅放弃程序集,还必须放弃.ascx文件。用户要消耗它们,他们必须引用.ascx文件并且他们的项目引用您的程序集。您也必须执行相同的操作。
希望这能更清楚一些。

1
如果控件存在于不同的应用程序中,就像它所展示的那样,LoadControl会抛出一个错误:虚拟路径...映射到另一个不允许的应用程序。 - Ruslan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接