DropDownList OnSelectedIndexChange для 0-го индекса без ViewState - PullRequest
6 голосов
/ 23 января 2009

Я следил за статьей TRULLY Понимание ViewState (отличная статья между прочим) и заполнение моего выпадающего списка работает отлично. Я даже настроил событие OnSelectedIndexChange, которое срабатывает почти так же хорошо.

Проблема, которую я обнаружил, заключается в том, что событие SelectedIndexChanged не будет срабатывать при выборе 0-го индекса. Это делает все остальное время однако.

Вот код:

<asp:DropDownList runat="server" ID="DropDownList1" EnableViewState="false" 
AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />

1010 *
*

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 ]

8 голосов
/ 23 января 2009

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

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

5 голосов
/ 24 января 2009

Моя цель с отключением 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;
  }

Поскольку текущее значение совпадает с измененным значением, событие не вызывается.

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