2009-01-09 39 views
5

更新:我一直在对我的控制进行一些实验,我想我已经接近了。请阅读更新信息。为什么我的自定义用户控件的子项未被初始化?

我有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()(我猜这是为什么标记值被忽略)。

这种努力是无望的,还是我只是从错误的角度接近它?

回答

0

您是否在页面的OnInit方法上设置了HRef?如果是这样,请尝试将任务移出到Page_Load。

控件Init从最外层到最内层。这意味着如果您确实在页面的OnInit上分配了值,则控件尚未初始化。

这里是页面的生命周期一个体面的文件: http://www.codeproject.com/KB/aspnet/lifecycle.aspx

+0

我在页面的标记中设置了HRef,而不是OnInit方法。我知道这发生在Page的OnPreInit()事件之前。我希望能够使用标记来设置控制值,因为这意味着无需重新编译即可进行更改。 – 2009-01-09 19:21:55

0

你说:

// The private 'linkHref' control is declared 
// in the .ascx markup of the control 

它是否在改变什么,如果你让这个受保护的控制?

0

控制树建立在Init()之后;实际上,在视图状态被反序列化之前,Init()就是将你的控件添加到树中的地方。在构建控件树之前,您无法访问linkHref。

一个可能的解决方案是存储Url,直到您可以使用它。内部控制在内部,地址属性更改为一个简单的字符串:

public string Url { get; set; } 

在内部控制的Load或PreRender事件处理程序,该字符串传播到(现在的初始化)linkHref对象:

linkHref.HRef = value; 
2

问候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文件中。

1

如果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.Innerset访问...

  1. 首先,ASP.NET实例ASP.outercontrol_ascx(动态生成的类派生自OuterControl),其依次实例化ASP.innercontrol_ascx(从InnerControl派生的动态生成的类)的实例。
  2. 接下来,因为Inner酒店有set访问,ASP.NET创建的InnerControl一个新实例(ASP.innercontrol_ascx,正如你所期望的那样),并尝试其Url属性初始化为"#"。当然,这会抛出NullReferenceException,因为linkHref是由ASP.innercontrol_ascx创建的,而不是由InnerControl创建的。
  3. 最后(如果没有异常被抛出),ASP.NET将Inner将其在步骤2中创建

如果OuterControl.Inner没有set访问,然后在步骤2中的InnerControl的情况下, ASP.NET只需将OuterCtrl1.Inner.Url设置为"#",并跳过步骤3。

注意:一些其他答案指出,在Init中创建或初始化控件。这是不正确的;在标记中声明的控件在页面生命周期的早期创建并初始化,在FrameworkInitialize(发生在PreInit之前)。

相关问题