c# - обзор - phpstorm conemu




Почему дети моего пользовательского элемента управления не инициализируются? (4)

ОБНОВЛЕНИЕ: Я уже несколько раз экспериментировал с моими элементами управления, и я думаю, что подошел ближе. Пожалуйста, прочтите информацию для получения более подробной информации.

У меня есть 2 пользовательских элемента управления ASP.NET 2.0, один из которых размещен внутри другого. Внутри внутреннего элемента управления у меня есть HtmlAnchor управления тегами HtmlAnchor который я пытаюсь установить для URL из внешнего HtmlAnchor управления. Когда я пытаюсь установить свойство HRef из разметки страницы рендеринга, HtmlAnchor управления HtmlAnchor имеет значение null и выдает исключение.

Свойство URL-адреса вызывается перед событием OnInit либо внутреннего, либо внешнего OnPreInit управления, и перед событием « OnPreInit » главной страницы. Я предполагаю, что это связано с тем, что я устанавливаю 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 управления linkHref имеет значение NULL. Используя мой отладчик, я вижу, что каждый элемент управления внутри InnerControl имеет значение NULL, но и событие OnInit() InnerControl и OuterControl еще не запущено, когда доступно свойство Url .

ОБНОВИТЬ
Я думал, что добавление атрибутов « ParseChildren » и « PersistChildren » поможет. Раньше я использовал их в Server Controls, но никогда в User Controls, хотя эффект кажется схожим. Я не думаю, что я правильно интерпретирую документацию для этих двух свойств, но это может остановить исключения. Однако разметка страницы игнорируется.

Кто-нибудь знает способ получить эту работу. Я не понимаю, почему эти элементы управления получают значения, установленные до OnInit() . Когда я пытаюсь установить свои значения с помощью разметки ASPX, конструктор для InnerControl вызывается дважды. Как только вы установите значения на основе разметки (я предполагаю) и снова на OnInit() (что я предполагаю, почему значения разметки игнорируются).

Неужели это усилие безнадежно или я просто приближаюсь к нему с неправильного угла?


Привет, Дэн,

Раньше я сталкивался с подобной проблемой с беспорядком вложенных элементов управления, поэтому я очень хотел помочь, и я отметил это как фаворита, потому что мне это нравилось.

Я воспроизвел проблему следующим образом:

Создал пользовательский элемент управления Inner:

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:

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:

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>

При всем этом страница «default» работает хорошо.

То, что я нахожу странным в вашем коде, - это строка:

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

Какой смысл создавать сеттер для внутреннего контроля? Я не могу этого понять. предполагается, что внутренний управляющий экземпляр создается из разметки во внешнем элементе управления, и именно этот созданный экземпляр, чья привязка html должна быть обработана. Если я добавлю эти строки в свойство Inner в Outer.ascx.cs

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

Я получаю исключение с нулевой ссылкой, как в исходном случае. Я думаю, что сеттер инструктирует компоновщика страниц ASP.Net создать другой экземпляр управления Inner и установить его с использованием свойства Inner. Я не уверен, но если у вас есть время, вы можете точно знать, как это происходит, изучая файлы cs, сгенерированные компоновщиком страниц, они находятся во временных файлах ASP.Net.


Ты сказал:

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

Что-то изменит, если вы сделаете это защищенным элементом управления?


Дерево управления создается после Init (); на самом деле Init () - это место, где вы добавляете свои элементы управления в дерево, прежде чем десериализовать viewstate. Вы не можете получить доступ к linkHref до того, как дерево управления будет создано.

Одним из возможных решений является сохранение Url, пока вы не сможете его использовать. Внутри внутреннего элемента управления измените свойство Url на простую строку:

public string Url { get; set; }

В обработчике событий Load или PreRender внутреннего элемента управления передайте строку в объект (now initialized) linkHref:

linkHref.HRef = value;

Если 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 аксессуаров ...

  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. Наконец (если исключение не было InnerControl ), ASP.NET устанавливает Inner в экземпляр InnerControl он создал на шаге 2.

Если OuterControl.Inner не имеет set доступа, то на шаге 2 ASP.NET просто устанавливает OuterCtrl1.Inner.Url в "#" , а шаг 3 пропускается.

Примечание. Еще пара ответов указывают, что элементы управления создаются или инициализируются в Init . Это неверно; элементы управления, объявленные в разметке, создаются и инициализируются очень рано в жизненном цикле страницы, в FrameworkInitialize (что происходит до PreInit ).





controls