为什么我的自定义用户控件的子项未被初始化?
更新:我一直在对我的控制进行一些实验,我想我已经接近了。请阅读更新信息。为什么我的自定义用户控件的子项未被初始化?
我有2个ASP.NET 2.0用户控件,其中一个放置在里面另一个是。在内部控件的内部,我有一个HtmlAnchor
标签控件,我试图从外部控件中设置一个URL。当我尝试从呈现页面的标记中设置HRef
属性时,HtmlAnchor
控件是null
并引发异常。
的URL set
属性被称为之前任一内部或外部的控制和主页的“OnPreInit
”事件之前的事件的OnInit。我假设这是因为我在页面上的父控件的标记中设置了子控件的URL,因此我在呈现控件时意味着该值在OnInit()
之前设置。下面是我使用的代码(精简)版本:
[ParseChildren(true)]// <- Setting this to false makes the
// page render without an exception
// but ignores anything in the markup.
[PersistChildren(false)]
public partial class OuterControl : System.Web.UI.UserControl
{
// The private '_Inner' control is declared
// in the .ascx markup of the control
[PersistenceMode(PersistenceMode.InnerProperty)]
public InnerControl Inner
{
get{ return _Inner; }
set{ _Inner = value; }
}
}
public partial class InnerControl : System.Web.UI.UserControl
{
// The private 'linkHref' control is declared
// in the .ascx markup of the control
public string Url
{
get { return linkHref.HRef; }
set { linkHref.HRef = value; }
}
}
的OuterControl是我Default.aspx页面上使用的是这样的:
<uc1:OuterControl ID="OuterCtrl1" runat="server">
<Inner Url="#" />
</uc1:OuterControl>
在标记上面的例子,如果我试图渲染这个页面抛出异常,因为linkHref
控件为空。使用我的调试器,我可以看到InnerControl中的每个控件都是null,但是当访问Url
属性时,InnerControl & OuterControl的OnInit()
事件还没有被触发。
UPDATE
我想添加属性 'ParseChildren
' 和 'PersistChildren
' 会有所帮助。我之前在服务器控件中使用了它们,但从未使用过用户控件,尽管效果看起来很相似。我不认为我正确解释了这两个属性的文档,但它可以阻止抛出异常。尽管页面标记会被忽略。
有没有人知道一种方法来完成这项工作。我不明白为什么这些控件在OnInit()
之前设置了值。当我尝试使用ASPX标记设置它们的值时,InnerControl
的构造函数被调用两次。一次设置基于标记的价值(我假设),并再次OnInit()
(我猜这是为什么标记值被忽略)。
这种努力是无望的,还是我只是从错误的角度接近它?
您是否在页面的OnInit方法上设置了HRef?如果是这样,请尝试将任务移出到Page_Load。
控件Init从最外层到最内层。这意味着如果您确实在页面的OnInit上分配了值,则控件尚未初始化。
这里是页面的生命周期一个体面的文件: http://www.codeproject.com/KB/aspnet/lifecycle.aspx
你说:
// The private 'linkHref' control is declared // in the .ascx markup of the control
它是否在改变什么,如果你让这个受保护的控制?
控制树建立在Init()之后;实际上,在视图状态被反序列化之前,Init()就是将你的控件添加到树中的地方。在构建控件树之前,您无法访问linkHref。
一个可能的解决方案是存储Url,直到您可以使用它。内部控制在内部,地址属性更改为一个简单的字符串:
public string Url { get; set; }
在内部控制的Load或PreRender事件处理程序,该字符串传播到(现在的初始化)linkHref对象:
linkHref.HRef = value;
问候Dan,
我之前遇到过类似的问题,因为嵌套控件混乱,所以我发现自己渴望提供帮助,而且我也将它标记为最喜欢的,因为我喜欢它。
我转载如下问题: -
创建了一个名为内的用户控件:
Inner.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Inner.ascx.cs" Inherits="Inner" %>
<a runat="server" id="linkHref">I'm inner</a>
Inner.ascx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Inner : System.Web.UI.UserControl
{
public string Url
{
get
{
return this.linkHref.HRef;
}
set
{
this.linkHref.HRef = value;
}
}
}
创建一个用户控制称为外层:
Outer.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Outer.ascx.cs" Inherits="Outer" %>
<%@ Register src="Inner.ascx" tagname="Inner" tagprefix="uc1" %>
<uc1:Inner ID="_Inner" runat="server" />
Outer.ascx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Outer : System.Web.UI.UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public Inner Inner
{
get
{
return this._Inner;
}
}
}
然后创建的页称为默认:
Default.aspx的
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register src="Outer.ascx" tagname="Outer" tagprefix="uc1" %>
<%@ Reference Control="~/Inner.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>
<uc1:Outer ID="Outer1" runat="server">
<Inner Url="http://google.com" />
</uc1:Outer>
</div>
</form>
</body>
</html>
所有这些,页面“默认”运行良好。
我发现在你的代码奇怪的是,这条线:
public InnerControl Inner
{
//...
set{ _Inner = value; }
}
什么是对内部控制建立一个二传手的意义呢?我无法理解它。内部控件实例应该从外部控件的标记中创建,并且它是这个创建的实例,它的html锚点应该被操纵。 如果我在Outer.ascx.cs
set
{
this._Inner = (ASP.inner_ascx)value;
}
这些行添加到内在属性我会得到一个空引用异常在原来如此。 我认为setter指示ASP.Net页面构建器创建另一个Inner控件实例并使用Inner属性进行设置。我不确定,但如果您有时间,可以通过检查由页面构建器生成的cs文件确切知道发生了什么,它们驻留在临时ASP.Net文件中。
如果OuterControl.ascx看起来像
<%@ Register TagPrefix="uc1" TagName="InnerControl" Src="InnerControl.ascx" %>
<uc1:InnerControl runat="server" ID="_Inner" />
那么问题是,OuterControl.Inner
酒店有set
访问。删除set
访问来解决这个问题:
[PersistenceMode(PersistenceMode.InnerProperty)]
public InnerControl Inner
{
get { return _Inner; }
}
说明:如果OuterControl.Inner
有set
访问...
- 首先,ASP.NET实例
ASP.outercontrol_ascx
(动态生成的类派生自OuterControl
),其依次实例化ASP.innercontrol_ascx
(从InnerControl
派生的动态生成的类)的实例。 - 接下来,因为
Inner
酒店有set
访问,ASP.NET创建的InnerControl
一个新实例(不ASP.innercontrol_ascx
,正如你所期望的那样),并尝试其Url
属性初始化为"#"
。当然,这会抛出NullReferenceException
,因为linkHref
是由ASP.innercontrol_ascx
创建的,而不是由InnerControl
创建的。 - 最后(如果没有异常被抛出),ASP.NET将
Inner
将其在步骤2中创建
如果OuterControl.Inner
没有set
访问,然后在步骤2中的InnerControl
的情况下, ASP.NET只需将OuterCtrl1.Inner.Url
设置为"#"
,并跳过步骤3。
注意:一些其他答案指出,在Init
中创建或初始化控件。这是不正确的;在标记中声明的控件在页面生命周期的早期创建并初始化,在FrameworkInitialize
(发生在PreInit
之前)。
我在页面的标记中设置了HRef,而不是OnInit方法。我知道这发生在Page的OnPreInit()事件之前。我希望能够使用标记来设置控制值,因为这意味着无需重新编译即可进行更改。 – 2009-01-09 19:21:55