Опубликован: 25.09.2008 | Доступ: свободный | Студентов: 3223 / 516 | Оценка: 4.32 / 3.98 | Длительность: 18:50:00
ISBN: 978-5-94774-991-5
Лекция 4:

Основы Web-программирования с использованием ASP.NET

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >

Коллекция ViewState, объекты Session и Application

Коллекция ViewState

Ранее указывались некоторые сложности, возникающие в процессе разработки Web-приложения. В частности, говорилось о том, что значения всех данных, введенных в элементы управления, после передачи клиенту уничтожаются, т.к. уничтожается сама страница, содержащая эти элементы управления. Для того чтобы сохранять значения элементов управления между обращениями к странице приложения, можно использовать несколько механизмов, рассматриваемых ниже.

Прежде всего, необходимо рассмотреть возможность применения состояния вида ( ViewState ). Его целесообразно использовать в том случае, когда необходимо организовать хранение данных в пределах одной страницы. Все элементы управления используют состояние вида по умолчанию для сохранения значений свойств между операциями обратной отсылки данных. Здесь же возможно организовать хранение своих собственных данных, состоящих из простых типов и специальных объектов.

Состояние вида организовано по принципу коллекции, которая, в свою очередь, имеет тип словаря. Это означает, что данные хранятся в формате "имя-значение". Каждый элемент при этом индексируется с помощью уникального строкового имени. Следующий пример добавляет в коллекцию ViewState элемент с именем Name и присваивает ему значение "Иван":

ViewState["Name"]="Иван";

При этом, если в коллекции до этого не существовало элемента с именем Name, то он добавляется, если же такой элемент был, его значение заменяется новым.

Для извлечения элемента из коллекции необходимо использовать имя элемента. Кроме того, т. к. коллекция ViewState позволяет сохранять не только данные, состоящие из простых типов, но и специальные объекты (в общем случае - любые объекты), во время извлечения значения элемента необходимо преобразовать его тип к тому, который будет извлекаться. Следующий пример позволяет извлечь значение элемента Name и преобразовать его в строку:

string name;
if (ViewState["Name"]!=null)
   name=(string)ViewState["Name"];

Проверка на наличие элемента коллекции необходима, т. к. при обращении к несуществующему элементу коллекции возникает исключение NullReferenceException.

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

Для демонстрации использования ViewState создадим пример на базе предыдущего, в котором после нажатия на кнопку "Отправить" данные текстовых полей сохраняются в состоянии вида, а поля очищаются. После нажатия на кнопку "Восстановить значения полей ввода" сохраненные значения полей считываются из состояния вида и помещаются в текстовые поля. Данный пример необходим только для демонстрации использования коллекции ViewState.

Для начала поместим на странице HTML-элемент "Таблица", который представляет собой описание обычной таблицы, и разместим в ее ячейках уже существующие элементы Label и TextBox. Кроме того, добавим на страницу кнопку. Присвоим вновь добавленной кнопке следующие параметры: ID=btn_RestoreTextBox, Text="Восстановить значения полей ввода".

Получившаяся в результате страница в режиме редактирования дизайна должна выглядеть следующим образом ( рис. 4.9).

Web-страница примера в режиме дизайна

Рис. 4.9. Web-страница примера в режиме дизайна

Внесем в исходный код страницы исправления в соответствии с рис. 4.10.

Исходный код страницы

увеличить изображение
Рис. 4.10. Исходный код страницы

Как видно из рис. 4.10, в стандартный элемент HTML Table были добавлены два элемента: идентификатор ID=Table и ключевое слово, позволяющее обращаться к нему на стороне сервера - runat="server". Это необходимо для того, чтобы во время выполнения приложения у нас была возможность обращения к данному элементу из программного кода.

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

ViewState["FirstName"]=tb_FirstName.Text;
ViewState["LastName"]=tb_LastName.Text;

Для восстановления значений, сохраненных в состояние вида, можно воспользоваться следующим фрагментом кода:

tb_FirstName.Text=(string)ViewState["FirstName"];
tb_LastName.Text=(string)ViewState["LastName"];

Тем не менее на практике часто возникает необходимость сохранения в состояние вида значений сразу нескольких элементов управления, которых на странице может присутствовать достаточно много. Для того чтобы сделать программный код более гибким и не перечислять в нем наименования всех элементов управления, расположенных на форме, можно организовать сохранение данных путем последовательного обращения к каждому из них в цикле. Известно, что все элементы управления, размещенные на форме, помещаются в коллекцию элементов управления, обращение к которой возможно осуществить при помощи свойства Controls. Этот механизм можно применять и к другим элементам управления, т. к. многие из них сами могут содержать другие элементы управления, которые, в свою очередь, могут содержать внутри себя еще элементы и т. д. Таким образом, для того, чтобы обеспечить чтение значений, введенных во все необходимые элементы управления, необходимо выбрать первый элемент управления, перебрать все элементы, входящие в него, при этом перебирая все их вложенные элементы до тех пор, пока не будут перебраны все элементы управления. Проще всего это сделать с помощью рекурсивной функции, которая вызывает себя в случае, если внутри текущего элемента управления существуют еще элементы управления. Также необходимо учесть, что в данном случае нас интересуют только элементы управления типа TextBox. Реализация такой функции может выглядеть следующим образом:

private void SaveTextinTextBox(ControlCollection controls, bool
 SaveNested)
{
  foreach (Control control in controls)
  {
    if (control is TextBox)
    {
      //Сохранить текст
      ViewState[control.ID]=((TextBox)control).Text;
    }
    if (control.Controls != null && SaveNested)
    {
      SaveTextinTextBox(control.Controls, true);
    }
  }
}

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

Цикл foreach осуществляет перебор всех элементов управления, переданных с помощью первого аргумента. Условие if (control is TextBox) необходимо для определения типа элемента управления. В случае, если текущий элемент управления является текстовым полем, его значение сохраняется в состояние вида, причем идентификатором элемента в коллекции ViewState будет являться ID элемента управления.

Условие if (control.Controls != null && SaveNested) позволяет вызвать функцию SaveTextinTextBox в случае, если текущий элемент управления имеет внутри себя вложенные элементы. Таким образом, функция позволяет осуществить перебор всех элементов управления, которые расположены на странице либо внутри другого элемента, избранного отправной точкой. В нашем примере таковым может являться объект Table1.

Функция чтения значений ViewState и их записи в соответствующие элементы управления может выглядеть следующим образом:

private void RestoreTexttoTextBox(ControlCollection controls, bool
 saveNested)
{
  foreach (Control control in controls)
  {
    if (control is TextBox)
    {
      if (ViewState[control.ID]!=null)
        ((TextBox)control).Text=(string)ViewState[control.ID];
    }
    if (control.Controls !=null && saveNested)
    {
      RestoreTexttoTextBox(control.Controls,true);
    }
  }
}

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

protected void Button1_Click(object sender, EventArgs e)
{
  string sname=string.Empty;
  TextBox tbSname=(TextBox)Page.FindControl("tb_SName");
  if (tbSname!=null)
  {
    sname = tbSname.Text;
  }
  lbl_Result.Text = "Здравствуйте, "+tb_FirstName.Text+"
   "+sname+" "+
   tb_LastName.Text+"! Добро пожаловать в приложение ASP.NET";
  lbl_Result.ForeColor = Color.Red;
  //сохраняем значения полей ввода в коллекции ViewState
  SaveTextinTextBox(Table1.Controls, true);
  tb_FirstName.Text = "";
  tb_LastName.Text = "";
}

Создадим обработчик для события нажатия на кнопку "Восстановить значения полей ввода". Он выглядит следующим образом:

protected void btn_RestoreTextBox_Click(object sender, EventArgs e)
{
  RestoreTexttoTextBox(Table1.Controls,true);
}

Теперь можно запустить приложение. При вводе значений в поля ввода текста и нажатии на кнопку "Отправить" на экран выводится надпись приветствия, а текст внутри полей ввода уничтожается. После нажатия на кнопку "Восстановить значения полей ввода" поля вновь заполняются текстом, введенным ранее. Это становится возможным благодаря использованию коллекции ViewState.

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >