Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 35:

Управление состоянием страниц на клиенте

Упражнение 3. Восстановление состояния вида элемента списка через коллекцию запроса

Иногда состояние вида в элементе полезно отключить, чтобы уменьшить нагрузку на каналы связи. Но для некоторых элементов это нарушает их нормальную работу. Возьмем, например, списки ListBox и DropDownList. Когда они заполнены большим количеством элементов, объем пересылаемой информации состояния вида очень большой и это свойство лучше отключить. Для восстановления состояния выделенного элемента списка в этом случае можно воспользоваться информацией из коллекции Request.Form страницы.

  • Добавьте к проекту страницу с именем ViewStateList.aspx без файла отделенного кода и назначьте ее стартовой
  • Оформите страницу так, чтобы код разметки был следующим
<%@ Page Language="C#" %>
  
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div style="text-align: center">
    <h2>Отключение состояния вида в списках</h2>
        <asp:ListBox ID="ListBox1" runat="server" Height="200px" Width="150px" />
        &nbsp; &nbsp; &nbsp; &nbsp;
        <asp:DropDownList ID="DropDownList1"
            runat="server" Width="150px">
        </asp:DropDownList><br />
        <br />
        <asp:Button ID="Button1" runat="server" Text="Отправить" /></div>
    </form>
</body>
</html>
Листинг 35.7. Код интерфейсной части страницы ViewStateList.aspx
  • Этому коду в режиме проектирования соответствует следующее представление


  • Двойным щелчком на свободном месте страницы в режиме Design создайте блок скриптов с заготовкой обработчика Page_Load()
  • Поместите в обработчик Page_Load() код заполнения списков видимым содержимым, который будет срабатывать при каждом запросе страницы
<script runat="server">
    
    // Поле класса страницы
    private const int maxCount = 100;
    
    protected void Page_Load(object sender, EventArgs e)
    {
        // Заполняем списки программной генерацией значений
        for (int i = 0; i < maxCount; i++)
        {
            ListBox1.Items.Add("Опция " + (i + 1).ToString());
            DropDownList1.Items.Add("Опция " + (i + 1).ToString());
        }
    }
</script>
Листинг 35.8. Обобработчик Page_Load() для заполнения списков
  • Выполните страницу и убедитесь, что при каждом новом запросе по щелчку на кнопке Submit отмеченные пользователем опции списков возвращаются сервером сохраненными
  • После нескольких обратных отсылок щелкните правой кнопкой мыши в клиентской области окна броузера и выполните команду View Source, чтобы просмотреть HTML-содержимое, присланное сервером

Мы видим большое количество пересылаемой информации в скрытых полях, а также последовательное увеличение содержимого списков. Это происходит потому, что каждое новое состояние списков направляется клиенту для хранения вместе с очередным откликом сервера. При возвращении на сервер последнее состояние списков восстанавливается и к нему добавляется генерация новых значений, выполненных методом Add() в обработчике Page_Load().

Работает механизм автоматического сохранения состояния вида ASP.NET. Чтобы посмотреть, какой при этом получается объем пересылаемой информации, именно касающийся работы этого механизма, нужно включить работу ASP.NET в режиме выдачи трассировки на индивидуальных страницах. Это можно сделать, если добавить атрибут Trace="true" в директиву @ Page страницы, либо через утилиту WAT, запустив ее командой Website/ASP.NET Configuration (или щелкнуть на пиктограмме в панели Solution Explorer ).

  • Запустите утилиту WAT, пойдите последовательно по ссылкам Application Configuration/Configure debugging and tracing и включите флажки " Capture tracing information " и " Display tracing information on ondividual pages "
  • Закройте утилиту WAT

В результате этих действий файл конфигурации примет вид

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <system.web>
        <trace enabled="true" pageOutput="true" />
        <compilation debug="true" />
    </system.web>
</configuration>
Листинг 35.9. Файл web.config после включения трассировки утилитой WAT
  • Вновь запустите страницу ViewStateList.aspx, поманипулируйте с интерфейсными элементами, выполните обратную отсылку и проанализируйте секцию Control Tree в результатах трассировки, которая будет, примерно, такой
Control Tree
Control UniqueID Type Render Size Bytes (including children) ViewState Size Bytes (excluding children) ControlState Size Bytes (excluding children)
__Page ASP.viewstatelist_aspx 910866 0 0
     ctl02 System.Web.UI.LiteralControl 50 0 0
     ctl00 System.Web.UI.HtmlControls.HtmlHead 46 0 0
         ctl01 System.Web.UI.HtmlControls.HtmlTitle 33 0 0
     ctl03 System.Web.UI.LiteralControl 14 0 0
     form1 System.Web.UI.HtmlControls.HtmlForm 910736 0 0
         ctl04 System.Web.UI.LiteralControl 129 0 0
         ListBox1 System.Web.UI.WebControls.ListBox 227258 196036 0
         ctl05 System.Web.UI.LiteralControl 47 0 0
         DropDownList1 System.Web.UI.WebControls.DropDownList 227246 196036 0
         ctl06 System.Web.UI.LiteralControl 32 0 0
         Button1 System.Web.UI.WebControls.Button 78 0 0
         ctl07 System.Web.UI.LiteralControl 12 0 0
     ctl08 System.Web.UI.LiteralControl 20 0 0

Объем пересылаемой по каналам связи в оба конца информации получается огромным до неприличия. Причем с каждой новой отсылкой он катастрофически нарастает, добавляя к прежним сохраненным значениям сгенерированные в коде новые значения списков. Отключим сохранение состояния вида в списках.

  • Перейдите в режим Design редактора страницы ViewStateList.aspx, выделите одновременно оба списка и через панель Properties сбросьте их свойства EnableViewState в значение False
  • Запустите страницу ViewStateList.aspx и убедитесь, что объем сохраняемого состояния вида для списков стал нулевым
  • Вновь включите сброшенные свойства EnableViewState для списков
  • Добавьте в директиву @Page общие для всех элементов страницы атрибуты EnableViewState = "false" и EnableEventValidation = "false"

Замечание. Если количество запросов превысит заданное параметром трассировки requestLimit значение (по умолчанию 10), то ASP.NET при исполнении не будет включать результаты трассировки в страницу. В этом случае нужно при очередном запуске тестового броузера вызвать через строку адреса страницу trace.axd и щелкнуть на ссылке " clear current trace " этой страницы. Включить безлимитную трассировку можно более просто - добавить в директиву @ Page страницы параметр Trace=true

  • Удалите из файла Web.config строку включения трассировки

<trace enabled="true" pageOutput="true" />

и добавьте в директиву @Page страницы атрибут Trace = "true", чтобы включить индивидуальную трассировку страницы

Мы видим, что при отключении сохранения состояния вида уменьшился и общий объем страницы. Но зато сервер в своих откликах не стал сохранять выбранные клиентом опции списков. Исправим этот недостаток программно, воспользовавшись тем фактом, что с каждым запросом выбранные значения передаются на сервер в словарь Request.Form объекта страницы.

  • Добавьте к странице в конец обработчика Page_Load() код восстановления выбора пользователя в списках
<script runat="server">
    
    // Поле класса страницы
    private const int maxCount = 100;
    
    protected void Page_Load(object sender, EventArgs e)
    {
        // Заполняем списки программной генерацией значений
        for (int i = 0; i < maxCount; i++)
        {
            ListBox1.Items.Add("Опция " + (i + 1).ToString());
            DropDownList1.Items.Add("Опция " + (i + 1).ToString());
        }
        
        // Отслеживание выделенных пользователем опций списков 
        if (this.IsPostBack)
        {
            string text = this.Request.Form["ListBox1"];
            ListBox1.Items.FindByText(text).Selected = true;
            text = this.Request.Form["DropDownList1"];
            DropDownList1.Items.FindByText(text).Selected = true;
        }
        else
            ListBox1.SelectedIndex = DropDownList1.SelectedIndex = 0;
    }
</script>
Листинг 35.10. Код восстанавления состояния списков

Броузер с обратной отсылкой присылает на сервер значения выделенных элементов списка, собираемых дескриптором <form> из HTML-кода, представленного примерно таким фрагментом

<select size="4" name="ListBox1" id="ListBox1" style="height:200px;width:150px;">
<option selected="selected" value="Опция 1">Опция1</option>
<option value="Опция 2">Опция 2</option>
<option value="Опция 3">Опция 3</option> 
..................................................
</select>

Фактически броузер посылает пару ListBox1=Опция 1, которая попадает в словарь Request.Form, доступный для извлечения и использования в коде страницы на стороне сервера. Мы находим это значение в сгенерированной коллекции значений списка и настраиваем этот элемент коллекции как выделенный. После таких настроек список сгенерирует в текущем отклике сервера нужный HTML-код, соответствующий состоянию списка на клиенте перед обратной отсылкой.

  • Запустите страницу ViewStateList.aspx с включенной трассировкой и убедитесь, что выбранные опции списков сохраняют свои позиции и ASP.NET генерирует небольшой объем клиентского кода

Таким образом мы выяснили, что состояние вида элементов управления, которое включено по умолчанию, не всегда является полезным либо просто не используется, и тогда его лучше отключать. Отключить состояние вида можно следующим образом:

  1. На уровне приложения для всех страниц в файле web.config текущего узла web-дерева сайта
    <?xml version="1.0" encoding="utf-8"?>
    <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
        <system.web>
            <compilation debug="true" />
            <pages enableViewState="false" />
        </system.web>
    </configuration>
  2. На уровне страницы, добавив в директиву @ Page параметр EnableViewState="false" (в коде свойство Page.EnableViewState  =  false или this.EnableViewState  =  false )
  3. На уровне элемента управления, добавив в дескриптор элемента атрибут EnableViewState = "false" (в коде свойство Элемент .EnableViewState = false )

Если более общая настройка сохранения состояния вида выключена, а для каких-то страниц или элементов управления ее нужно включить, то в соответствующее место следует добавить атрибут EnableViewState = "true".

Александр Очеретяный
Александр Очеретяный
Украина, Киев
Анастасия Балыбердина
Анастасия Балыбердина
Украина, Киев, НТУУ КПИ