Динамически добавляемые элементы управления в Asp.Net

Я пытаюсь обернуть голову вокруг asp.net - ... У меня есть фон как разработчик php долгое время, но теперь передо мной стоит задача обучения asp.net и у меня с этим проблемы. Это может быть очень хорошо, потому что я пытаюсь заставить структуру в то, для чего она не предназначена, поэтому я хотел бы научиться делать это "правильно". :-)

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

простой сценарий может быть формой с выпадающим элементом управления, добавленным в конструктор. Раскрывающийся список настроен на AutoPostBack. Когда происходит обратная передача, мне нужно отобразить один или несколько элементов управления, определяющих выбранное значение из раскрывающегося списка, и желательно иметь их элементы управления действуют так, как если бы они были добавлены дизайном (например, "при отправке назад, ведите себя "правильно").

Я иду по неправильному пути здесь?

9 ответов


Я согласен с другими пунктами, сделанными здесь "Если вы можете выйти из создания элементов управления динамически, то сделайте это...(by @Йеспер Блэд Дженсон ака) но вот трюк, который я разработал с динамически созданными элементами управления в прошлом.

проблема становится курица и яйцо. Вам нужен ViewState в, чтобы создать дерево элементов управления и дерево управления, созданной на состояние вида. Ну, это почти верно. Существует способ получить значения ViewState перед остальная часть дерева заполнена. Это путем переопределения LoadViewState(...) и SaveViewState(...).

в SaveViewState хранить элемент управления, который вы хотите создать:

protected override object SaveViewState()
{
    object[] myState = new object[2];
    myState[0] = base.SaveViewState();
    myState[1] = controlPickerDropDown.SelectedValue;

    return myState
}

когда платформа вызывает переопределение" LoadViewState", вы получите точный объект, который вы вернули из"SaveViewState":

protected override void LoadViewState(object savedState) 
{
    object[] myState = (object[])savedState;

    // Here is the trick, use the value you saved here to create your control tree.
    CreateControlBasedOnDropDownValue(myState[1]);

    // Call the base method to ensure everything works correctly.
    base.LoadViewState(myState[0]);
}

Я успешно использовал это для создания ASP.Net страницы, на которых набор данных был сериализован в ViewState храните изменения во всей сетке данных, позволяя пользователю делать несколько изменений с обратными ссылками и, наконец, фиксировать все их изменения в одной операции "сохранить".


вы должны добавить свой элемент управления внутри события OnInit и viewstate будет сохранен. Не используйте if (ispostback), потому что элементы управления должны быть добавлены каждый раз, событие в обратной передаче!
(De)сериализация viewstate происходит после OnInit и до OnLoad, поэтому поставщик сохраняемости viewstate будет видеть динамически добавляемые элементы управления, если они добавлены в OnInit.

но в сценарии, который вы описываете, вероятно, multiview или simple hide/show (visible свойство) будет лучше решение.
Это потому, что в событии OnInit, когда вы должны прочитать раскрывающийся список и добавить новые элементы управления, viewstate еще не прочитан (десериализован), и вы не знаете, что выбрал пользователь! (вы можете сделать запрос.form (), но это кажется неправильным)


после борьбы с этой проблемой в то время как я придумал эти groundrules, которые, кажется, работают, но YMMV.

  • используйте декларативные элементы управления, когда это возможно
  • использовать привязку данных, где это возможно
  • понять, как работает ViewState
  • свойство Visibilty может пройти долгий путь
  • Если необходимо использовать элементы управления add в обработчике событий, используйте подсказку Aydsman и воссоздайте элементы управления в переопределенном LoadViewState.

по-настоящему понимание ViewState нужно прочитать.

Понимание Динамических Элементов Управления На Примере показывает некоторые методы использования привязки данных вместо динамических элементов управления.

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

надеюсь, это поможет другим с теми же проблемами.


Если вам действительно нужно использовать динамические элементы управления, должно работать следующее:

  • в OnInit воссоздайте точно такую же иерархию элементов управления, которая была на странице при выполнении предыдущего запроса. (Если это не первоначальный запрос, конечно)
  • после OnInit платформа загрузит viewstate из предыдущего запроса,и все ваши элементы управления должны быть в стабильном состоянии.
  • в OnLoad удалите элементы управления, которые не требуются, и добавьте необходимые. Вам также придется каким-то образом сохранить текущее дерево элементов управления на этом этапе, чтобы использовать его на первом шаге во время следующего запроса. Можно использовать переменную сеанса, которая определяет способ создания динамического дерева управления. Я даже сохранил всю коллекцию элементов управления в сеансе один раз (отложите вилы, это было только для демонстрации).

повторное добавление" устаревших " элементов управления, которые вам не понадобятся и будут удалены при загрузке в любом случае немного странно, но Asp.Net на самом деле не был разработан с учетом создания динамического управления. Если точно такая же иерархия элементов управления не сохраняется во время загрузки viewstate, на странице начинают скрываться все виды труднодоступных ошибок, поскольку состояния старых элементов управления загружаются во вновь добавленные.

читайте дальше Asp.Net жизненный цикл страницы и особенно о том, как работает viewstate, и это станет ясно.

Edit: это очень хорошая статья о том, как viewstate ведет себя и что вы должны учитывать при работе с динамическими элементами управления:http://geekswithblogs.net/FrostRed/archive/2007/02/17/106547.aspx


хорошо. Если вы можете выйти из создания элементов управления динамично, то сделайте это - в противном случае, что я должен сделать, это использовать Page_Load вместо Page_Init, но вместо размещения вещей внутри If Not IsPostBack, а затем установить i непосредственно в методе.


Ах, вот в чем проблема с дырявой абстракцией ASP.NET веб-формы.

возможно, Вам будет интересно посмотреть на ASP.NET MVC, который использовался для создания этого stackoverflow.com веб-сайт? Это должно быть проще подходит для вас, исходя из PHP (таким образом, педаль к металлу, когда дело доходит до HTML и Javascript) фона.


Я думаю, что ответ здесь находится в MultiView control, так что, например, раскрывающийся список переключается между различными представлениями в мульти-представлении.

вы, вероятно, даже можете привязать текущее свойство представления multiview к значению раскрывающегося списка!


единственный правильный ответ был дан Айдсманом. LoadViewState является единственным местом для добавления динамических элементов управления, где их значения viewstate будут восстановлены при воссоздании, и вы можете получить доступ к viewstate, чтобы определить, какие элементы управления добавить.


я наткнулся на это в книге "Pro ASP.NET 3.5 В C# 2008" В разделе Создание динамического управления:

Если вам нужно повторно создать элемент управления несколько раз, вы должны выполнить создание элемента управления на странице.Загрузить обработчик событий. Это имеет дополнительное преимущество, позволяя использовать состояние представления с динамическим управлением. Даже если состояние просмотра обычно восстанавливается перед страницей.Событие Load, если вы создаете элемент управления в обработчике для страницы.событие Load, ASP.NET будет применяться любая информация о состоянии представления, имеющаяся после страницы.Заканчивается обработчик событий загрузки. Этот процесс происходит автоматически.

Я не тестировал это, но вы можете посмотреть в него.