Проблема с динамическими элементами управления в .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