Динамически добавленные элементы управления в Asp.Net - PullRequest
9 голосов
/ 22 сентября 2008

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

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

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

Я иду по неверному пути?

Ответы [ 9 ]

8 голосов
/ 22 сентября 2008

Я согласен с другими замечаниями, сделанными здесь: «Если вы можете отказаться от создания элементов управления динамически, тогда сделайте это ...» (@ Jesper Blad Jenson aka ), но вот уловка, с которой я работал с динамически созданными элементами управления в прошлом.

Проблема становится курицей и яйцом. Вам нужен ViewState для создания дерева элементов управления, и вам нужно, чтобы дерево элементов управления было создано для доступа к 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, где DataSet был сериализован в ViewState для хранения изменений во всей сетке данных, что позволяет пользователю вносить несколько изменений в PostBacks и, наконец, фиксировать все свои изменения в одном Операция «Сохранить».

3 голосов
/ 22 сентября 2008

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

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

2 голосов
/ 30 сентября 2008

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

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

TRULY Понимание ViewState необходимо прочитать.

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

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

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

1 голос
/ 22 сентября 2008

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

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

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

Прочтите о жизненном цикле страницы Asp.Net и особенно о том, как работает представление, и станет понятно.

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

0 голосов
/ 24 сентября 2008

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

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

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

0 голосов
/ 23 сентября 2008

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

0 голосов
/ 22 сентября 2008

Ах, это проблема утечки абстракции веб-форм ASP.NET.

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

0 голосов
/ 22 сентября 2008

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

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

0 голосов
/ 22 сентября 2008

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

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