Проблема с динамическими элементами управления в .NET.
Проблема с динамическими элементами управления
Привет всем,
Я хочу создать некоторые динамические элементы управления и удержать их в представлении на разных страницах. Легко, правда? Все, что мне нужно сделать, это воссоздать элементы управления при каждой загрузке страницы, используя те же идентификаторы. ОДНАКО, вот уловка в моем событии PreRender, я хочу очистить коллекцию элементов управления, а затем воссоздать динамические элементы управления с новыми значениями. Причины этого сложны, и, вероятно, мне понадобится страница или около того, чтобы объяснить, почему я хочу это сделать. Поэтому, в интересах краткости, позвольте предположить, что я абсолютно должен это сделать, и что нет другого пути.
Проблема возникает после того, как я снова создаю элементы управления в своем событии PreRender. Повторно созданные элементы управления никогда не привязаны к представлению, и их значения не сохраняются при загрузке страниц. Я не понимаю, почему это происходит. Я уже создаю элементы управления в своем событии OnLoad. Когда я это делаю, вновь созданные элементы управления привязываются к ViewState просто отлично, при условии, что я использую одинаковые идентификаторы каждый раз. Однако, когда я пытаюсь сделать то же самое в событии PreRender, он терпит неудачу.
В любом случае, вот мой пример кода:
пространство имен TestFramework.WebControls
{
public class ValueLinkButton : LinkButton
{
public string Value
{
get
{
return (string)ViewState[ID + "vlbValue"];
}
set
{
ViewState[ID + "vlbValue"] = value;
}
}
}
public class TestControl : WebControl
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Controls.Clear();
ValueLinkButton tempLink = null;
tempLink = new ValueLinkButton();
tempLink.ID = "valueLinkButton";
tempLink.Click += new EventHandler(Value_Click);
if (!Page.IsPostBack)
{
tempLink.Value = "old value";
}
Controls.Add(tempLink);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
ValueLinkButton tempLink = ((ValueLinkButton)FindControl("valueLinkButton")); //[CASE 1]
//ValueLinkButton tempLink = new ValueLinkButton(); [CASE 2]
tempLink.ID = "valueLinkButton";
tempLink.Value = "new value";
tempLink.Text = "Click";
Controls.Clear();
Controls.Add(tempLink);
}
void Value_Click(object sender, EventArgs e)
{
Page.Response.Write("[" + ((ValueLinkButton)sender).Value + "]");
}
}
}
Итак, рассмотрим случай 1, где строка рядом с [CASE 1] не закомментирована, но строка рядом с [CASE 2] закомментирована. Здесь все работает отлично. Когда я помещаю этот элемент управления на страницу и загружаю страницу, я вижу ссылку, которая говорит "Click". Когда я нажимаю ссылку, страница выводит текст "[новое значение]", а на следующей строке мы видим знакомую ссылку "Click". Каждое подчиненное время, которое я нажимаю на ссылку "Click", мы видим одно и то же. Пока что так хорошо.
Но теперь рассмотрим случай 2, где строка рядом с [CASE 1] закомментирована, но строка рядом с [CASE 2] не закомментирована. Здесь мы сталкиваемся с проблемами. Когда мы загружаем страницу, мы видим ссылку "Click". Однако, когда я нажимаю на ссылку, страница выводит текст "[]" вместо "[новое значение]". Событие клика срабатывает нормально. Однако текст "нового значения", который я присвоил атрибуту Value элемента управления, не сохраняется. Еще раз, это немного загадка для меня. Почему, когда я воссоздаю элемент управления в OnLoad, все отлично и денди, но когда я воссоздаю элемент управления в PreRender, значение не сохраняется?
Я чувствую, что просто должен быть способ сделать это. Когда я снова создаю элемент управления в PreRender, есть ли способ связать вновь созданный элемент управления с ViewState?
Я боролся с этим в течение нескольких дней. Любая помощь, которую вы можете дать мне, будет оценена.
Спасибо.
Ответы
Ответ 1
Свойства ViewState поддерживаются только ViewState, если элемент управления в настоящее время отслеживает ViewState. Это по дизайну, чтобы держать ViewState как можно меньше: он должен содержать только данные, которые действительно динамичны. Результатом этого является то, что:
Представления ShowState, установленные во время события Init, не привязаны к ViewState (поскольку страница еще не начала отслеживать ViewState). Таким образом, Init является хорошим местом для добавления элементов управления и установки (a) свойств, которые не будут меняться между обратными передачами (ID, CssClass...), а также начальными значениями для динамических свойств (которые затем могут быть изменены кодом в остальной части жизненный цикл страницы - загрузка, обработчики событий, PreRender).
При динамическом добавлении элементов управления в Load или PreRender отслеживается ViewState. Затем разработчик может контролировать, какие пропозиции сохраняются для динамически добавленных элементов управления, как показано ниже:
-
Свойства, установленные до того, как элемент управления добавлен в дерево управления страницей, не сохраняются в ViewState. Обычно вы устанавливаете свойства, которые не являются динамическими (ID и т.д.), Перед добавлением элемента управления в дерево управления.
-
Свойства, установленные после добавления элемента управления в дерево управления страницей, сохраняются в ViewState (отслеживание ViewState включено до загрузки события после события PreRender).
В вашем случае обработчик PreRender устанавливает свойства перед добавлением элемента управления в дерево управления страницей. Чтобы получить желаемый результат, установите динамические свойства после добавления элемента управления в дерево управления:
.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
ValueLinkButton tempLink = new ValueLinkButton(); // [CASE 2]
tempLink.ID = "valueLinkButton"; // Not persisted to ViewState
Controls.Clear();
Controls.Add(tempLink);
tempLink.Value = "new value"; // Persisted to ViewState
tempLink.Text = "Click"; // Persisted to ViewState
}
Ответ 2
Как и в других случаях, вам необходимо убедиться, что вы создаете с помощью метода Init. Чтобы узнать больше о жизненном цикле страницы ASP.NET, просмотрите эту статью: http://msdn.microsoft.com/en-us/library/ms178472.aspx
Ответ 3
Я уже создаю элементы управления в своем событии OnLoad.
Это ваша проблема. OnLoad слишком поздно. Вместо этого используйте Init.
Ответ 4
Спасибо за вашу помощь, но я попробовал это, и это не изменило ситуацию. Кроме того, OnLoad работает так же хорошо для динамических элементов управления, как OnInit, если вы каждый раз даете своим элементам управления одинаковые идентификаторы.
Ответ 5
Я считаю, что после добавления динамических элементов управления на страницу в PageLoad, ViewState привязан к элементам управления, а флажок "ViewState по-прежнему должен быть связан" (в концепции, а не в фактическом флаге) очищается. Затем, когда вы воссоздаете элементы управления, существующее ViewState больше не связано.
В прошлом году я столкнулся с чем-то подобным, только в моем случае я не хотел, чтобы ViewState перестраивалась. Моя проблема заключается в том, что я не воссоздавал предыдущие элементы управления, поэтому я считаю, что применяется понятие псевдо-флага.
Ответ 6
Попробуйте позвонить Page.RegisterRequiresControlState()
. Вы также можете использовать RequiresControlState()
, чтобы проверить, уже ли он зарегистрирован.
Ответ 7
ViewState работает на странице и ее дочерних объектах. Новый элемент управления в [Вариант 2] не был добавлен на страницу (или любой из ее дочерних элементов). Фактически, в случае вышеприведенного кода объект будет недоступен, как только метод OnPreRender завершится и будет собран мусором.
Если вам абсолютно необходимо поменять элемент управления, вам нужно будет удалить старый элемент управления из его родителя с помощью метода Remove() и добавить новый элемент управления в нужном месте с помощью AddAt().
Если элемент управления был единственным дочерним элементом родителя, код будет выглядеть следующим образом.
ValueLinkButton tempLink = new ValueLinkButton();
Control parent = FindControl("valueLinkButton").Parent;
parent.Remove(FindControl("valueLinkButton"));
parent.AddAt(0, tempLink);
Ответ 8
Элемент управления, добавленный до метода SaveViewState, вызываемого в жизненном цикле управления, должен сохранять свои значения. Я соглашусь с Джо ответить. Проверьте это изображение
http://emanish.googlepages.com/Asp.Net2.0Lifecycle.PNG
Ответ 9
Вчера я понял, что вы действительно можете заставить свое приложение работать нормально, загрузив дерево управления сразу после запуска loadviewstateevent. если вы переопределите событие loadviewstate, вызовите mybase.loadviewstate, а затем поместите свой собственный код для регенерации элементов управления сразу после него, значения для этих элементов управления будут доступны при загрузке страницы. В одном из моих приложений я использую поле viewstate для хранения идентификатора или информации о массиве, которые можно использовать для воссоздания этих элементов управления.
Protected Overrides Sub LoadViewState(ByVal savedState As Object)
MyBase.LoadViewState(savedState)
If IsPostBack Then
CreateMyControls()
End If
End Sub