ASP.NET Динамически добавленный LinkButton — обработчик OnClick не вызывается

Я динамически добавляю элемент управления LinkButton в PlaceHolder. Если я добавлю новый экземпляр LinkButton в каждый OnInit(), то обработчик OnClick для этого LinkButton будет работать.

Однако, если я сохраню экземпляр LinkButton в сеансе, а затем добавлю его в коллекцию элементов управления PlaceHolder, LinkButton.OnClick не сработает.

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

Как примечание - это унаследованное приложение в 1.1, которое я только что перенес в 3.5. Похоже, что «сломанный» подход работал в версии 1.1.

Спасибо за ответы на все вопросы.

public static void Clicked(object sender, EventArgs e) {
    Debugger.Break();
}

protected override void OnPreInit(EventArgs e) {
    base.OnPreInit(e);
    InitLinkButton();
}

private void InitLinkButton() {    
    var lb = new LinkButton();
    plOne.Controls.Add(lb);
    lb.ID = "lb";
    lb.Text = "I will work.";
    lb.Click += Clicked;
    plOne.Controls.Add(lb);

    LinkButton lb2 = null;
    if (Session["lb2"] == null) {
        lb2 = new LinkButton();
        lb2.ID = "lb2";
        lb2.Text = "I won't work.";
        lb2.Click += Clicked;
        Session["lb2"] = lb2;
    } else {
        lb2 = (LinkButton)Session["lb2"];
    }
    plOne.Controls.Add(lb2);
}

person Art    schedule 12.05.2009    source источник


Ответы (4)


Пара вещей:

1) Никогда, никогда не сохраняйте экземпляр WebControl в Session. Каждый WebControl имеет ссылку на объект Page, который, конечно же, ссылается на каждый другой WebControl. Как только вы помещаете WebControl в сеанс, вы в основном сохраняете всю страницу и все, что она содержит. Вы находитесь на шоссе в город утечки памяти.

2) Каждый элемент управления воссоздается при каждой обратной передаче. Я думаю, вы можете подумать, что повторное создание ваших LinkButtons каждый раз — это медленно, но это не так.

3) Почему нельзя воссоздать ваши динамические элементы управления при обратной передаче? Это то, что вы должны делать с динамическими элементами управления. Вся идея заключается в том, что вы настраиваете страницу так же, как и раньше, чтобы ViewState можно было автоматически подключить к вашим элементам управления на основе их идентификаторов. Если вы попытаетесь добавить элементы управления на свою страницу динамически в любом месте после Init(), вы не сможете использовать ViewState для обработки ваших данных управления, и вам придется реализовать свой собственный механизм.

Я рекомендую воссоздать ваши динамические элементы управления в Init() — это лучшая практика.

person womp    schedule 12.05.2009
comment
Элементы управления в вашем .aspx воссоздаются при каждой обратной передаче. Динамические элементы управления должны создаваться заново при каждой обратной передаче. - person Dave Swersky; 13.05.2009

Чтобы ответить на ваш вопрос, как заставить работать OnClick, вам нужно подключить событие к методу;

lb2.Click += new EventHandler(Clicked);

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

person Jesper Haug Karsrud    schedule 13.05.2009

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

person lomaxx    schedule 12.05.2009

Хранить LinkButton в сеансе действительно ужасная идея. Я даже не могу представить, какие проблемы могут возникнуть. По крайней мере, LinkButton имеет ссылку (через обработчик Clicked) на страницу, которая на самом деле больше не должна существовать (страница была обработана и отправлена ​​клиенту). Но ссылка сохранит его, поэтому он не будет GC'ed.

При этом возможно вам просто нужно перемонтировать обработчик Clicked:

if (Session["lb2"] == null) {
    /* ... */
} else {
    lb2 = (LinkButton)Session["lb2"];
    lb2.Click += Clicked;
}

Поскольку событие LinkButton.Click связано с другим экземпляром класса Page (тот, который использовался ранее), его срабатывание не будет иметь видимого эффекта (поскольку эта страница была уже отрисовано). Конечно, как я уже сказал выше, это просто полное сумасшествие, так что я не проверял это.

Если вы используете это, вам также следует отказаться от подписки на Page_PreRender или что-то еще, чтобы избежать проблемы с GC.

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

person Mark Brackett    schedule 12.05.2009