Динамически создаваемые элементы управления ASP.NET и обратная передача
Я знаю, что этот вопрос задавали тысячи раз, и я боролся с ним раньше, но по какой-то причине я не могу выполнить то, что я хочу выполнить... У меня есть динамически добавленный LinkButton, который при нажатии будет динамически добавлять элемент управления (в этом примере, текстовое поле) к той же панели. Цель состоит в том, чтобы постоянно добавлять столько элементов управления, сколько раз, когда был нажат LinkButton (т.е. Я нажму один раз, один флажок, затем другой щелчок даст мне 2 поля, другой щелчок добавит третий). В приведенном ниже коде я использую текущую дату и время, сериализованные для создания уникального идентификатора для каждого элемента управления текстовыми полями.
Когда я запускаю код, нажатие "Добавить фильтр" создаст новое текстовое поле, но после его повторного нажатия создаст новый и удалит его перед ним. Вместо этого я хочу сохранить предыдущий текстовый блок, а также любые данные, представленные в нем.
Ваша помощь приветствуется.
В aspx:
<asp:Panel ID="pnlFilter" runat="server">
</asp:Panel>
В aspx.cs:
protected void Page_Init(object sender, EventArgs e)
{
LinkButton lb = new LinkButton();
lb.ID = "lbAddFilter";
pnlFilter.Controls.Add(lb);
lb.Text = "Add Filter";
lb.Click += new EventHandler(lbAddFilter_Click);
}
void lbAddFilter_Click(object sender, EventArgs e)
{
TextBox tb = new TextBox();
tb.ID = "tb" + DateTime.Now.ToBinary().ToString();
pnlFilter.Controls.Add(tb);
}
Ответы
Ответ 1
Для других, кто пытается сделать что-то вроде этого: не делайте этого. Вместо этого подумайте о потоке информации и поймите, что есть лучший способ сделать это. Элементы управления вводами не должны создаваться динамически. Они могут быть статическими, а после заполнения и отправки на них эта информация должна куда-то (база данных, кеш, сеанс, например). После того, как он там, при обратной передаче, просмотрите все элементы в вашем хранилище и создайте для них отображение.
Вот что я сделал, и это облегчило жизнь. Надеюсь, это поможет кому-то.
Ответ 2
void lbAddFilter_Click(object sender, EventArgs e)
{
TextBox tb = new TextBox();
tb.ID = "tb" + DateTime.Now.ToBinary().ToString();
pnlFilter.Controls.Add(tb);
}
Это не сработает - это проблема жизненного цикла, как вы предполагали в своем вопросе. Есть много способов, которыми вы можете работать с этим, но предложение Honus Wagner является самым гибким.
Что здесь происходит, так это то, что вы вызываете Controls.Add в обработчике событий, а элемент управления добавляется в список управления и в следующий запрос (будь то частичная обратная передача, полная обратная передача или новая страница), что контроль ушел, потому что вы его нигде не сохраняли.
Вот что происходит в жизненном цикле событий вашей страницы прямо сейчас:
- Страница вызывает OnInit и добавляет ваш LinkButton
- Пользователь нажимает кнопку LinkButton
- Страница вызывает OnInit, чтобы начать запрос обратной передачи. LinkButton воссоздан
- Вызывается обработчик событий, который динамически создает ваш TextBox и добавляет его в коллекцию управления.
- Пользователь снова нажимает кнопку LinkButton.
- Страница вызывает OnInit, чтобы снова добавить LinkButton. Коллекция pnlFilter.Controls пуста на этом этапе, за исключением тех элементов, которые вы указали статически в своей разметке.
- Вызывается обработчик событий и добавляется новый TextBox в список управления.
Я не уверен, что это лучшая практика, но у меня был успех с подобной ей моделью (обратите внимание, что я не тестировал этот код - может потребоваться настройка):
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
LinkButton lb = new LinkButton();
lb.ID = "lbAddFilter";
pnlFilter.Controls.Add(lb);
lb.Text = "Add Filter";
lb.Click += new EventHandler(lbAddFilter_Click);
// regenerate dynamically created controls
foreach ( var control in PersistedControls )
{
pnlFilter.Controls.Add(GenerateControl(control));
}
}
private IList<Control> _persistedControls;
private const string PersistedControlsSessionKey = "thispage_persistedcontrols";
private IList<Control> PersistedControls
{
if (_persistedControls == null)
{
if (Session[PersistedControlsSessionKey] == null)
Session[PersistedControlsSessionKey] = new List<Control>();
_persistedControls = Session[PersistedControlsSessionKey] as IList<Control>;
}
return _persistedControls;
}
void lbAddFilter_Click(object sender, EventArgs e)
{
TextBox tb = new TextBox();
tb.ID = "tb" + DateTime.Now.ToBinary().ToString();
PersistedControls.Add(tb);
pnlFilter.Controls.Add(tb);
}
Обратите внимание, что я не уверен в добавлении фактических объектов Control в хранилище сеансов. Я считаю, что есть проблемы с идентификаторами управления, которые будут вызывать ошибки при обратной передаче (может быть, элемент управления не сериализуем?). В решении, которое я разработал, я создал новый TextBox/Label/ComboBox/etc в моем эквиваленте метода GenerateControl и сохранил пользовательский класс контейнера в коллекции PersistedControls, который содержит различные свойства элемента управления пользовательского интерфейса, которые мне нужно будет генерировать это на каждой странице Init.
Ответ 3
Я считаю, что вам нужно будет воссоздать каждый элемент управления при каждой обратной передаче.
Я знаю, что контроллер Repeater хранит достаточную информацию о своих дочерних элементах, чтобы воссоздать их при привязке к базе данных... Возможно, вы сможете использовать его, чтобы сохранить небольшую работу.
Ответ 4
Попробуйте добавить
if(!Page.IsPostback)
--- your code that adds different controls.