Что вы делаете, когда вы не можете использовать ViewState? - PullRequest
7 голосов
/ 05 сентября 2008

У меня довольно сложная страница, которая динамически создает пользовательские элементы управления внутри повторителя. Этот повторитель должен быть связан во время события страницы Init до инициализации ViewState, иначе динамически созданные пользовательские элементы управления не сохранят свое состояние.

Это создает интересный Catch-22, потому что объект, с которым я связываю повторитель, должен быть создан при начальной загрузке страницы, а затем сохраняться в памяти до тех пор, пока пользователь не решит покинуть или сохранить.

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

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

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

Редактировать: Несколько хороших советов по использованию LoadViewState, но у меня все еще есть проблемы с состоянием, которое не восстанавливается, когда я это делаю.

Вот несколько, если структура страницы

Страница -> UserControl -> Repeater -> N элементов UserControls, динамически создаваемых.

Я поместил переопределенный LoadViewState в родительский UserControl, так как он предназначен для полной инкапсуляции и не зависит от страницы, на которой он находится. Мне интересно, в этом ли проблема?

Ответы [ 10 ]

4 голосов
/ 09 ноября 2008

Метод LoadViewState на странице, безусловно, ответ. Вот общая идея:

protected override void LoadViewState( object savedState ) {
  var savedStateArray = (object[])savedState;

  // Get repeaterData from view state before the normal view state restoration occurs.
  repeaterData = savedStateArray[ 0 ];

  // Bind your repeater control to repeaterData here.

  // Instruct ASP.NET to perform the normal restoration of view state.
  // This will restore state to your dynamically created controls.
  base.LoadViewState( savedStateArray[ 1 ] );
}

SaveViewState необходимо создать массив saveState, который мы используем выше:

protected override object SaveViewState() {
  var stateToSave = new List<object> { repeaterData, base.SaveViewState() };
  return stateToSave.ToArray();
}

Не забудьте также привязать ретранслятор в Init или Load, используя такой код:

if( !IsPostBack ) {
  // Bind your repeater here.
}
1 голос
/ 05 сентября 2008

Я всегда воссоздаю свои динамические элементы управления в событии LoadViewState. Вы можете сохранить количество элементов управления, которое необходимо создать в viewstate, а затем динамически создать их, используя метод LoadControl внутри события LoadViewState. В этом случае у вас есть доступ к ViewState, но он еще не был восстановлен в элементах управления на странице.

1 голос
/ 05 сентября 2008

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

Почему у вас есть для явного обнуления значения (кроме управления памятью и т. Д.)? Разве это не вариант для проверки Page.IsPostback и что-то делать с переменной Session или нет?

0 голосов
/ 07 сентября 2008

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

0 голосов
/ 07 сентября 2008

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

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

  1. При первой загрузке привязывайте ваш верхний пользовательский элемент управления к объекту во время OnPreInit. Сохраните объект в сеансе. Viewstate будет автоматически сохранено для этих элементов управления. Если вам нужно в первый раз связать элемент управления на Page_Load, это нормально, но в итоге вы получите два события, которые вызывают связывание, если вы выполните следующий шаг.
  2. При обратной передаче повторно свяжите верхний пользовательский элемент управления в методе OnPreInit с объектом, который вы сохранили в сеансе. Все ваши элементы управления должны быть воссозданы до загрузки viewstate. Затем, когда viewstate будет восстановлено, значения будут установлены на то, что находится в viewstate. Единственное предостережение здесь заключается в том, что при повторном связывании с обратной передачей вы должны быть на 100% уверены, что такое же количество элементов управления будет создано снова. Ключ к использованию Repeaters, Gridviews и т. Д. С динамическими элементами управления внутри них заключается в том, что они имеют , который необходимо восстанавливать при каждой обратной передаче перед загрузкой состояния представления. OnPreInit обычно является лучшим местом для этого. В платформе нет технических ограничений, предписывающих, что вы должны выполнять всю свою работу в Page_Load при первой загрузке.

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

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

РЕДАКТИРОВАТЬ: я изменил все ссылки на OnInit на OnPreInit в этом решении. Я забыл, что MS представила это новое событие в ASP.NET 2.0. В соответствии с их документацией по жизненному циклу страницы , OnPreInit - это место, где динамические элементы управления должны создаваться / создаваться заново.

0 голосов
/ 05 сентября 2008
protected override void LoadViewState(object savedState)
{
   // Put your code here before base is called
   base.LoadViewState(savedState);
}

Это то, что вы имели в виду? Или вы имели в виду, в каком порядке обрабатываются элементы управления? Я думаю, что ответ на это квазислучайный.

Кроме того, почему вы не можете загрузить объекты, к которым привязаны, до Page_Load? Можно вызывать бизнес-уровень в любое время в течение жизненного цикла страницы, если необходимо, за исключением предварительного рендеринга и чего-либо после.

0 голосов
/ 05 сентября 2008

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

В каком порядке вызывается LoadViewState? Я добавил переопределенную сигнатуру метода, и она, похоже, не вступает в нее.

0 голосов
/ 05 сентября 2008

@ Джонатан:

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

0 голосов
/ 05 сентября 2008

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

2) Если вы не можете понять это, может быть, вы можете отключить режим просмотра для страницы отверстия и затем полагаться только на строку запроса для изменений состояния? Любая ссылка, которая ранее была постбэком, будет ссылкой на другой URL (или редирект постбэка).

Это действительно может уменьшить вес страницы и упростить предотвращение проблем с ViewState.

0 голосов
/ 05 сентября 2008

@ DancesWithBamboo:

Если я буду динамически связывать элементы управления, будет ли ASP.NET автоматически обрабатывать их состояние? Проблема с выполнением этого в Page_Load заключается в том, что viewstate уже загружено и не добавляет динамические элементы управления в повторитель. Я думаю, что это будет делать то же самое в LoadViewState?

...