Почему субконтроли инициализируются раньше своих контейнеров? - PullRequest
5 голосов
/ 09 февраля 2011

Несмотря на многолетнюю работу с WebForms, я все еще время от времени путаюсь с жизненным циклом событий.Это не столько проблема, которую нужно решать, но и попытка лучше понять, почему все работает так, как они работают.

Предположим, у вас есть форма:

Default.aspx:

<form>
  <MyControls:UserControl1 runat="server">
</form>

UserControl1: ascx:

<MyControls:UserControl2 runat="server">

События OnInit происходят в следующем порядке:

UserControl2_OnInit
UserControl1_OnInit
Default_OnInit

Разве это не просто аккорды басов?Разве код Init не должен выполняться в порядке создания элементов управления?Разве родительский элемент управления не должен иметь возможность инициализировать свойства дочернего элемента до его запуска OnInit?То есть, хотя вы можете инициализировать свойства субконтролей в разметке, не существует прямого способа, чтобы родительский элемент управления мог динамически устанавливать свойства дочернего элемента управления, которые будут доступны его событию OnInit.

То, что я в итоге сделал, - это что-то вроде:

override void UserControl2_OnInit()
{
    NamingContainer.OnInit += new EvenHandler(UserControl1_ActualInit);
}
protected void UserControl2_ActualInit(..) {
  // do actual init code here, which will occur before OnLoad but after it's parent
  // OnInit
}

Так что это не непреодолимая проблема.Я просто не понимаю, почему это проблема в первую очередь.

Я понимаю, что, возможно, вы захотите, чтобы все ваши дочерние элементы управления были инициализированы в вашем коде OnInit.Итак, вы должны иметь возможность сначала вызывать base.OnInit, а не после, свой собственный код инициализации, который должен запускать все события OnInit дочернего элемента управления.Но жизненный цикл события не работает таким образом.События Init не связаны рекурсивно, кажется, что они независимо запускают родительские события, и самое внутреннее всегда запускается первым.Но кажется, что жизнь была бы намного проще, если бы они были просто рекурсивно связаны, так что вы могли бы вызвать базовое событие (или нет), прежде чем делать свое дело в любой конкретной ситуации.Я что-то упускаю, что делает эту, казалось бы, нелогичную ситуацию желательной или даже необходимой?

Ответы [ 2 ]

2 голосов
/ 01 мая 2012

Этот документ должен быть основным источником правды для ваших вопросов жизненного цикла.

В основном OnInit запускает после завершения внутренней инициализации элемента управления .Поскольку элемент управления страницей является первым инициализированным элементом управления, и во время его внутренней инициализации он инициализирует все вложенные элементы управления (возможно, в порядке, который дает файл Designer.cs), тогда имеет смысл, чтобы событие OnInit страницы было последним вызванным, поскольку он не завершил инициализацию до тех пор, пока не будут инициализированы все его подэлементы управления и не сработали их события OnInit.Графически это выглядит следующим образом:

Page internal init
    Sub-control1 internal init
        Sub-sub-control3 internal init
        Sub-sub-control3 init finished / OnInit fired
    Sub-control1 init finished / OnInit fired
    Sub-control2 internal init
    Sub-control2 init finished / OnInit fired
Page init finished / OnInit fired

Таким образом, порядок единиц в этом случае:

  1. Sub-sub-control3 OnInit
  2. Sub-control1 OnInit
  3. Sub-control2 OnInit
  4. Page OnInit

Загрузка также работает аналогично.В целом, вы должны обрабатывать большинство событий так, как если бы элемент управления сначала проходил через свой внутренний процесс (который включает в себя вызов одного и того же события на всех подэлементах управления), а затем запускал собственный код обработки событий.

Большинство примеров, которые вы обнаружите, используют Page_Load специально, потому что это должно быть последнее событие, вызываемое на этом этапе (и это после загрузки данных обратной передачи).Сначала будет вызван Page_Load не очень хорошо, и есть риск, что элементы управления не будут полностью загружены для вашего пользовательского кода обработки событий.

1 голос
/ 06 июля 2012

Мышление для родительских и дочерних элементов управления asp.net:

Родители знают все о своих детях, но дети ничего не знают об их родителях.

Это мышление имеет смысл для многократного использования серверных элементов управления. Для повторного использования необходим собственный дочерний элемент управления, не предполагающий использования страницы, на которой он используется.

Фрагмент, который вы даете, заставляет меня догадываться, что ваши дочерние пользовательские элементы управления не предназначены для повторного использования как такового; а точнее специализированные элементы управления, которые вы используете для устранения сложностей большого и хитрого пользовательского интерфейса?

В этом случае я бы все еще попытался бы работать с мышлением «дети ничего не знают о своих родителях». Подумайте http://www.google.co.uk/search?q=gof+mediator+pattern, где родительская страница 1016 * является посредником между вашими детьми (страница википедии хороша).

Но вашим детям все еще нужно что-то знать о родительских правах, потому что они выполняют сложные взаимодействия с пользовательским интерфейсом? Вы можете решить эту проблему с помощью интерфейсов. Каждый дочерний элемент зависит не от родителя, а от интерфейса, который точно определяет, к чему детям требуется доступ. Как говорит http://en.wikipedia.org/wiki/SOLID, «зависит от абстракций, а не от конкрементов». Делайте один интерфейс на дочерний элемент управления: «многие специфичные для клиента интерфейсы лучше, чем один универсальный интерфейс»

Но все это в конечном итоге выглядит чрезмерно спроектированным, не так ли? Оказывается, что компонентный пользовательский интерфейс, где компоненты должны взаимодействовать, просто является сложным, и компоненты могут оказаться большими и неуклюжими. Имхо, это была одна из причин того, что элементы управления ajax веб-форм MS проиграли jQuery & c. даже до MVC появился.

Добавьте к этому, что веб-интерфейс очень сложен для модульного тестирования; и ваша уверенность в качестве вашего программного обеспечения.

Я рекомендую: Если вы можете, переписать в MVC. Если вы не можете этого сделать, рассмотрите возможность отказа от серверных элементов управления, которые ведут себя на стороне клиента, и используйте вместо этого jQuery. Если вы не можете этого сделать, упростите упростите упростите пользовательский интерфейс. Даже если это делает его менее функциональным. Если вы этого не хотите, то ваш выбор: хорошо заплатить за разработку пользовательского интерфейса; или заплатите за то, что не спроектировали это хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...