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 будет поддерживать данные для вас, а также выбранный индекс, поэтому при повторной публикации выпадающий список будет сравнивать новый индекс с индексом, который вы видели в клиенте.

Другие вопросы по тегам