Элементы ListBox, переставленные с помощью JavaScript, вызывают ошибку проверки события при обратной передаче
Я создал элемент управления заменой элементов, состоящий из двух списков и нескольких кнопок, которые позволяют мне менять элементы между двумя списками. Обмен осуществляется с помощью JavaScript. Я также перемещаю элементы вверх и вниз в списке. Обычно, когда я перемещаю элементы в поле списка справа, я храню ключи данных элементов (GUID) в скрытом поле. При обратной передаче я просто читаю GUID с поля. Все отлично работает, но при обратной передаче я получаю следующее исключение:
Неверный аргумент обратной передачи или обратного вызова. Проверка события включена с использованием в конфигурации или <% @ Page EnableEventValidation = "true"%> на странице. В целях безопасности эта функция проверяет, что аргументы для событий обратной передачи или обратного вызова исходят от серверного элемента управления, который первоначально их представил. Если данные действительны и ожидаемы, используйте метод ClientScriptManager.RegisterForEventValidation, чтобы зарегистрировать данные обратной передачи или обратного вызова для проверки.
Я подготовил тестовое приложение. Все, что вам нужно сделать, это загрузить архив и запустить проект. На веб-странице выберите 3 элемента, нажмите Добавить все, затем переместите третий элемент на один уровень вверх и нажмите "Кнопка". Ошибка появится. Отключение валидации событий ни в коем случае не допустимо. Может кто-нибудь помочь мне, я провел уже два дня, не находя решения.
7 ответов
Первый вариант принесет значительные накладные расходы. Я определил свой собственный элемент управления listbox, полученный из класса listbox, и выполнил переопределение данных loadpostback:
public class CustomListBox : ListBox
{
protected override bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
return true;
}
}
Использование этого вместо обычного списка в моем пользовательском контроле решило проблему, однако есть ли риски, связанные с моим подходом?
Проблема в том, что сохраненное состояние просмотра списка и данные, полученные при обратной передаче, не совпадают. Проблема проверки события, скорее всего, является лишь одной из возможных проблем, которые могут возникнуть из-за этого подхода. Архитектура веб-форм не допускает такого рода использования, и, скорее всего, с этим подходом будет больше проблем, даже если вам удастся избежать проблемы проверки события. У вас есть несколько вариантов:
1) Самое простое - это сделать логику обмена на сервере вместо использования JavaScript. Таким образом, состояние представления будет сохраняться между обратными передачами, и дополнительные издержки нескольких обращений к серверу могут не быть проблемой.
2) Если проблема заключается в нескольких обращениях к серверу, напишите серверный элемент управления, который обрабатывает свое собственное состояние просмотра. Это, конечно, очень интересный подход.
3) Средним подходом может быть использование двух простых html-списков (просто напишите html-тэги без использования элементов управления asp.net) и сохранение на стороне клиента из javascript списка идентификаторов в скрытом поле. При обратной записи просто проанализируйте скрытое поле и извлеките идентификатор, игнорирующий HTML-списки.
Я бы пошел с 1, если нет серьезных аргументов против этого.
Несколько возможных вариантов:
Если возможно, отключите ViewState в двух списках. Без ViewState сервер не будет знать, какие были исходные значения, и, следовательно, не будет ошибки. При таком подходе вам нужно будет заново заполнить списки (из-за отсутствия ViewState) и, возможно, потребуется отслеживать выбор вручную - или вам нужно будет заполнить списки на этапе OnInit.
Отключите проверку события (если можете)
Заполните оба списка полностью на стороне сервера и используйте клиентский сценарий (javascript) для удаления записей из двух списков по мере необходимости.
Это жалуется, потому что выбранного элемента в списке не было в списке, когда он был представлен. Подумайте об использовании PageMethods через AJAX, чтобы вернуть ваши данные в форму вместо PostBack. Или используйте элементы управления без ввода для хранения данных - как неупорядоченные списки, между которыми вы перемещаете элементы списка. Вы можете поместить GUID в скрытые области внутри элемента списка, где вы можете получить их в случае необходимости.
Вы можете переопределить событие Render, чтобы зарегистрировать все возможные элементы списка в обоих списках. Таким образом, независимо от того, какие элементы перемещены куда, проверка ожидает их.
protected override void Render(HtmlTextWriter writer)
{
foreach (DictionaryEntry entry in ColumnConfig) {
Page.ClientScript.RegisterForEventValidation(lstbxColumnsToExport.UniqueID,(string)entry.Key);
Page.ClientScript.RegisterForEventValidation(lstbxNonExportColumns.UniqueID,(string)entry.Key);
}
base.Render(writer);
}
В качестве альтернативы вы можете использовать серверный HtmlSelect вместо ListBox, чтобы обойти проблему проверки события. Лучше всего то, что вы можете оставить большую часть своего кода в неизменном виде (т.е. логика заполнения списка такая же, как ListBox).
<select runat="server" id="myList" multiple="true" />
Случайно, вы уже пробовали это? Делайте это всякий раз, когда вы гадите со списком любым способом.
document.getElementById("listbox").selectedIndex = -1;