DropDownList OnSelectedIndexChange для 0-го индекса без ViewState
Я следовал за статьей TRULLY Понимание ViewState (отличная статья), и заполнение моего выпадающего списка работает отлично. Я даже настроил событие OnSelectedIndexChange, которое срабатывает почти так же хорошо.
Проблема, которую я обнаружил, заключается в том, что событие SelectedIndexChanged не будет срабатывать при выборе 0-го индекса. Это делает все другие времена однако.
Вот некоторый код:
<asp:DropDownList runat="server" ID="DropDownList1" EnableViewState="false"
AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />
protected override void OnInit(EventArgs e)
{
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
base.OnInit(e);
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
OnSelectedQueueChanged(e);
}
public void OnSelectedQueueChanged(EventArgs e)
{
// Do stuff.
}
public event EventHandler queueNamesChangedEvent;
public void OnSelectedQueueChanged(EventArgs e)
{
if (queueNamesChangedEvent != null)
queueNamesChangedEvent(this, e);
}
Я полагаю, что я могу сделать некоторые проверки в методе Page_Load:
if(ViewState["selectedIndexChangedFlag"] != 1)
// raise OnSelectedChange event
Или я могу что-то настроить в методе OnInit(), где я перепривязываю эти данные каждый раз, когда могу это сделать?
Видите, мой пользовательский EventHander вызывает событие, которое перехватывается родительской страницей, на которой находится этот элемент управления, чтобы родитель мог выполнить какое-то действие, используя только что выбранное значение. И это в настоящее время работает для всех случаев, когда выбранный индекс> 0.
Я создаю свойство в этом элементе управления, которое содержит последний выбранный индекс, и в этом случае моя родительская страница может воздействовать на значение этого свойства для каждого Page_Load... dunno.
Открыт для предложений. Или как заставить это событие SelectedIndexChanged сработать для этого выбора 0-го индекса.
2 ответа
Моя цель с отключением ViewState в этом раскрывающемся списке - минимизировать размер ViewState для страницы.
Проблема, с которой я столкнулся только при выполнении if(!Page.IsPostBack){...DataBind()...}, заключается в том, что при первом выборе элемента и перезагрузке страницы мой раскрывающийся список становится пустым,
В итоге я создал еще одно свойство для этого элемента управления, LastIndex. Когда происходит событие OnSelectedIndexChanged, я обновляю значение LastIndex. В Page_Load я сравниваю значения индекса Current и Last, если они разные, а затем запускаю событие изменения индекса.
public int SelectedValue{
get { return this.DropDownList1.SelectedItem.Value; }
}
public int LastIndex{
get { return this.ViewState["lastIndex"] == null ? -1 : (int)this.ViewState["lastIndex"]; }
set { this.ViewState["lastIndex"] = value; }
}
protected override void OnInit(EventArgs e){
base.OnInit(e);
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
}
protected void Page_Load(object sender, EventArgs e){
if (this.LastIndex != this.SelectedValue)
this.OnSelectedQueueChanged(new EventArgs());
}
private ListItemCollection fillQueueDropDown(){...}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e){
OnSelectedQueueChanged(e);
this.LastIndex = this.SelectedValue;
}
public event EventHandler queueNamesChangedEvent;
public void OnSelectedQueueChanged(EventArgs e){
if (queueNamesChangedEvent != null)
queueNamesChangedEvent(this, e);
}
Вы правы, хотя. Данные повторно загружаются и связываются в фазе OnInit. Затем ViewState восстанавливается (и когда восстанавливается 0-й индекс), когда мы, наконец, переходим к фазе Events, элемент управления не обнаруживает изменения.
Не уверен, что это самый элегантный маршрут, но пока он работает хорошо.
Затем я нашел это в документации MSDN для IPostBackDataHandler:
public virtual bool LoadPostData(string postDataKey,
NameValueCollection postCollection) {
String presentValue = Text;
String postedValue = postCollection[postDataKey];
if (presentValue == null || !presentValue.Equals(postedValue)) {
Text = postedValue;
return true;
}
return false;
}
Поскольку текущее значение совпадает с измененным значением, событие не вызывается.
Проблема в том, что вы загружаете данные каждый раз, и это сбрасывает выбранный индекс. Представьте, что это ваш выпадающий список:
zero [selected]
one
two
Затем в клиенте вы меняете выбранный индекс:
zero
one [selected]
two
Это заполняет скрытый ввод __EVENTARGUMENT
с вашим новым индексом (1) и скрытым вводом __EVENTTARGET
с id
вашего выпадающего. Теперь серверный код запускается и перезагружает ваши данные:
zero [selected]
one
two
"ноль" - это выбранное значение, потому что это значение по умолчанию при загрузке данных. Затем ASP.NET ищет __EVENTTARGET
а также __EVENTARGUMENT
в Request
и находит ваш выпадающий id
и находит новый индекс (1). Теперь ваш выпадающий список выглядит так:
zero
one [selected]
two
Поскольку индекс изменился, раскрывающийся SelectedIndexChanged
событие, указывающее, что индекс изменился. Очевидно, что эта часть работает, теперь давайте посмотрим, почему выбор первого элемента в списке не вызывает событие.
Теперь допустим, что у нас все еще есть раскрывающийся список в том состоянии, в котором он находился (с выбранной единицей и индексом 1). Что происходит, когда мы выбираем первый элемент в списке на клиенте?
__EVENTTARGET
а также __EVENTARGUMENT
населены id
раскрывающегося списка и нового индекса (0). Затем сервер загружает данные в раскрывающийся список, и теперь раскрывающийся список снова выглядит следующим образом:
zero [selected]
one
two
Обратите внимание, что поскольку вы перезагрузили данные до того, как сработали события, индекс уже установлен на 0, потому что это значение по умолчанию. Теперь, когда ваше событие запускается, а выбранный индекс выпадающего меню устанавливается на 0, выпадающий список не видит это как изменение, поскольку выбранный индекс (насколько он знает) не изменился.
Вот как можно решить проблему:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!Page.IsPostBack)
{
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
}
}
То, что это будет делать, это загружать данные в раскрывающийся список, только если страница не является обратной передачей. Это означает, что ViewState будет поддерживать данные для вас, а также выбранный индекс, поэтому при повторной публикации выпадающий список будет сравнивать новый индекс с индексом, который вы видели в клиенте.