2009-01-09 27 views
5

CẬP NHẬT:Tôi đã thử nghiệm các điều khiển của mình một số chi tiết và tôi nghĩ mình đã tiến gần hơn. Vui lòng đọc tiếp để biết thông tin cập nhật.Tại sao trẻ em của điều khiển người dùng tùy chỉnh của tôi không được khởi tạo?

Tôi có 2 điều khiển người dùng ASP.NET 2.0, một trong số đó được đặt bên trong của số khác. Bên trong của điều khiển bên trong tôi có một điều khiển thẻ HtmlAnchor mà tôi đang cố gắng thiết lập một URL cho từ điều khiển bên ngoài. Khi tôi cố gắng đặt thuộc tính HRef từ đánh dấu của trang kết xuất, kiểm soát HtmlAnchornull và ném ngoại lệ.

URL set thuộc tính đang được gọi là trước sự kiện OnInit của điều khiển bên trong hoặc bên ngoài và trước sự kiện 'OnPreInit' của Trang chính. Tôi giả định điều này là bởi vì tôi đang thiết lập URL của điều khiển con trong đánh dấu kiểm soát cha mẹ trên trang tôi đang hiển thị các điều khiển có nghĩa là giá trị được đặt trước OnInit(). Dưới đây là (rút gọn) phiên bản mã Tôi đang sử dụng:

[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; } 
    } 
} 

Các OuterControl được sử dụng trên trang Default.aspx của tôi như thế này:

<uc1:OuterControl ID="OuterCtrl1" runat="server"> 
    <Inner Url="#" /> 
</uc1:OuterControl> 

Trong ví dụ đánh dấu ở trên, nếu Tôi cố gắng hiển thị trang này một ngoại lệ bị ném vì điều khiển linkHref là không. Sử dụng trình gỡ rối của tôi, tôi có thể thấy rằng mọi điều khiển trong InnerControl là null, nhưng cả hai sự kiện của OuterControl là OnInit() chưa được kích hoạt khi thuộc tính Url được truy cập.

CẬP NHẬT
Tôi nghĩ thêm các thuộc tính 'ParseChildren' và 'PersistChildren' sẽ giúp đỡ. Tôi đã sử dụng chúng trong Server Controls trước nhưng không bao giờ trong User Controls, mặc dù hiệu ứng có vẻ là tương tự. Tôi không nghĩ rằng tôi đang giải thích tài liệu cho hai thuộc tính này một cách chính xác, nhưng nó có thể ngăn chặn các ngoại lệ khỏi bị ném. Đánh dấu trang bị bỏ qua mặc dù.

Có ai biết cách làm việc này không. Tôi không hiểu tại sao các điều khiển này nhận được giá trị được đặt trước OnInit(). Khi tôi cố gắng đặt giá trị của họ bằng cách sử dụng đánh dấu ASPX, hàm tạo cho số InnerControl đang được gọi hai lần. Một lần để thiết lập các giá trị dựa trên đánh dấu (tôi giả định) và một lần nữa trên OnInit() (mà tôi đoán là lý do tại sao các giá trị đánh dấu đang bị bỏ qua).

Nỗ lực này có vô vọng hay tôi đang tiếp cận nó từ góc độ sai?

Trả lời

0

Bạn có đặt HRef trên phương thức OnInit của Trang không? Nếu vậy hãy thử chuyển bài tập ra Page_Load.

Các điều khiển Init từ ngoài cùng đến bên trong nhất. Điều này có nghĩa là nếu bạn gán giá trị trên OnInit của trang thì các điều khiển chưa được khởi tạo.

Đây là một tài liệu phong nha trên vòng đời trang: http://www.codeproject.com/KB/aspnet/lifecycle.aspx

+0

Tôi đang đặt HRef trong đánh dấu của Trang, không phải là phương pháp OnInit. Tôi biết điều này xảy ra trước sự kiện OnPreInit() của Trang. Tôi muốn có thể sử dụng đánh dấu để thiết lập các giá trị điều khiển nếu có thể vì nó có nghĩa là không phải biên dịch lại để thực hiện thay đổi. –

0

Bạn nói:

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

Liệu nó thay đổi bất cứ điều gì nếu bạn thực hiện này một điều khiển được bảo vệ?

0

Cây điều khiển được xây dựng sau Init(); trong thực tế, Init() là nơi để thêm điều khiển của bạn vào cây, trước khi viewstate được deserialized. Bạn không thể truy cập linkHref trước khi cây điều khiển được xây dựng.

Một giải pháp có thể là lưu trữ Url cho đến khi bạn có thể sử dụng nó. Bên trong sự kiểm soát bên trong, thay đổi thuộc tính Url thành một chuỗi đơn giản:

public string Url { get; set; } 

Trong Load hoặc PreRender xử lý sự kiện của điều khiển bên trong, tuyên truyền chuỗi đến (nay là khởi tạo) đối tượng linkHref:

linkHref.HRef = value; 
2

Chúc mừng Dan,

Tôi phải đối mặt với một vấn đề tương tự trước khi lộn xộn các điều khiển lồng nhau, vì vậy tôi thấy mình háo hức giúp đỡ, và tôi đánh dấu nó là yêu thích vì tôi thích nó.

tôi sao chép các vấn đề như sau: -

Tạo một điều khiển người dùng gọi là Nội:

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

Đã tạo điều khiển người dùng gọi Outer:

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

Sau đó, tạo ra một trang gọi là mặc định:

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> 

Với tất cả những điều này, trang "mặc định" chạy tốt.

public InnerControl Inner 
    { 
     //... 
     set{ _Inner = value; } 
    } 

điểm của việc tạo ra một setter cho sự kiểm soát bên trong là gì:

dòng này gì tôi thấy lạ trong mã của bạn là? Tôi không thể hiểu được. thể hiện kiểm soát bên trong được cho là được tạo ra từ đánh dấu trong điều khiển bên ngoài, và nó là trường hợp được tạo ra có neo html cần được thao tác. Nếu tôi thêm những dòng này vào thuộc tính Inner trong Outer.ascx.cs

set 
{ 
    this._Inner = (ASP.inner_ascx)value; 
} 

tôi sẽ nhận được một ngoại lệ tham chiếu null như trong trường hợp ban đầu. Tôi nghĩ rằng setter chỉ thị trình xây dựng trang ASP.Net để tạo một thể hiện kiểm soát bên trong khác và đặt nó bằng cách sử dụng thuộc tính Inner. Tôi không chắc chắn, nhưng nếu bạn có thời gian, bạn có thể biết chính xác điều này xảy ra như thế nào bằng cách kiểm tra các tệp cs được tạo bởi trình tạo trang, chúng nằm trong các tệp ASP.Net tạm thời.

1

Nếu OuterControl.ascx trông giống như

<%@ Register TagPrefix="uc1" TagName="InnerControl" Src="InnerControl.ascx" %> 
<uc1:InnerControl runat="server" ID="_Inner" /> 

sau đó vấn đề là các OuterControl.Inner tài sản có một accessor set. Xóa set accessor để sửa chữa các vấn đề:

[PersistenceMode(PersistenceMode.InnerProperty)] 
public InnerControl Inner 
{ 
    get { return _Inner; } 
} 

Giải thích: Nếu OuterControl.Inner có accessor set ...

  1. Thứ nhất, ASP.NET instantiates ASP.outercontrol_ascx (lớp tạo động đó xuất phát từ OuterControl,) lần lượt tạo ra một thể hiện của ASP.innercontrol_ascx (lớp được tạo động có nguồn gốc từ InnerControl).
  2. Tiếp theo, vì Inner tài sản có một accessor set, ASP.NET tạo ra một thể hiện mới của InnerControl (khôngASP.innercontrol_ascx, như bạn có thể mong đợi) và cố gắng để khởi tạo tài sản Url của nó để "#". Tất nhiên, điều này ném NullReferenceExceptionlinkHref được tạo bởi ASP.innercontrol_ascx, không phải bởi InnerControl.
  3. Cuối cùng (nếu không có ngoại lệ đã được ném), ASP.NET đặt Inner đến trường hợp của InnerControl nó tạo ở bước 2.

Nếu OuterControl.Inner không có một accessor set, sau đó trong bước 2, ASP.NET chỉ cần đặt OuterCtrl1.Inner.Url thành "#" và bước 3 bị bỏ qua.

Lưu ý: Một vài câu trả lời khác cho biết các điều khiển được tạo hoặc được khởi tạo trong Init. Điều này là không chính xác; các điều khiển được khai báo trong đánh dấu được tạo và khởi tạo rất sớm trong vòng đời trang, trong FrameworkInitialize (xảy ra trước PreInit).

Các vấn đề liên quan