ASP.NET / C #: DropDownList SelectedIndexChanged в серверном элементе управления не запускается

Я создаю серверный элемент управления, который в основном связывает два раскрывающихся списка, один для страны и один для штата, и обновляет раскрывающийся список состояния для события selectedindexchanged страны. Однако это не отправка обратно. Есть идеи, почему? Бонусные баллы за их упаковку в UpdatePanel (возникают проблемы с рендерингом; может быть, потому, что у меня нет страницы для ссылки?)

Вот что у меня есть (с удаленным лишним доступом к данным):

public class StateProv : WebControl
{
    public string SelectedCountry;
    public string SelectedState;

    private DropDownList ddlCountries = new DropDownList();
    private DropDownList ddlStates = new DropDownList();

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        IList<Country> countries = GetCountryList();
        IList<State> states = new List<State>();

        if (SelectedCountry != null && SelectedCountry != "")
        {
            states = GetStateList(GetCountryByShortName(SelectedCountry).CountryShortName);
        }
        else
        {
            states.Add(new State { CountryId = 0, Id = 0, StateLabelName = "No states available", StateLongName = "No states available", StateShortName = "" });
        }

        ddlCountries.DataSource = countries;
        ddlCountries.DataTextField = "CountryLongName";
        ddlCountries.DataValueField = "CountryShortName";
        ddlCountries.SelectedIndexChanged += new EventHandler(ddlCountry_SelectedIndexChanged);
        ddlCountries.AutoPostBack = true;

        ddlStates.DataSource = states;
        ddlStates.DataTextField = "StateLongName";
        ddlStates.DataTextField = "StateShortName";

        ddlCountries.DataBind();
        ddlStates.DataBind();

        if (!string.IsNullOrEmpty(SelectedCountry))
        {
            ddlCountries.SelectedValue = SelectedCountry;

            if (!string.IsNullOrEmpty(SelectedState))
            {
                ddlStates.SelectedValue = SelectedState;
            }
        }            
    }


    protected override void RenderContents(HtmlTextWriter output)
    {
        ddlCountries.RenderControl(output);
        ddlStates.RenderControl(output);
    }

    private IList<Country> GetCountryList()
    {
        //return stuff
    }

    private IList<State> GetStateList(Country country)
    {
        //return stuff
    }

    private IList<State> GetStateList(string countryAbbrev)
    {
        Country country = GetCountryByShortName(countryAbbrev);
        return GetStateList(country);
    }

    private Country GetCountryByShortName(string countryAbbrev)
    {
        IList<Country> list = dataAccess.RetrieveQuery<Country>();
        //return stuff
    }

    private IList<State> GetAllStates()
    {
        //return stuff
    }

    protected void ddlCountry_SelectedIndexChanged(object sender, EventArgs e)
    {
        IList<State> states = GetStateList(GetCountryList()[((DropDownList)sender).SelectedIndex]);
        ddlStates.DataSource = states;
        ddlStates.DataBind();
    }
}

Изменить: состояние просмотра находится на странице, и другие элементы управления на странице выполняют обратную передачу правильно, но не это.


person Jack Lawson    schedule 20.02.2009    source источник
comment
Вероятно, это не считается ответом, но Ajax Control Toolkit предоставляет то, что вы хотите, уже внутри панели обновлений: asp.net/AJAX/AjaxControlToolkit/Samples/CascadingDropDown/   -  person Sean    schedule 20.02.2009
comment
Ага; Однако я навсегда поклялся отказаться от ACT. Абсолютная фигня IMO; Я фактически создаю замену своему проекту, поскольку мы могли заставить управление CCD работать только с веб-службой, что имело другие последствия.   -  person Jack Lawson    schedule 20.02.2009


Ответы (5)


Viewstate включен?

Изменить. Возможно, вам стоит пересмотреть переопределение функции рендеринга.

  protected override void RenderContents(HtmlTextWriter output)
    {
        ddlCountries.RenderControl(output);
        ddlStates.RenderControl(output);
    }

и вместо этого добавьте раскрывающиеся списки к элементу управления и визуализируйте элемент управления с помощью RenderContents по умолчанию.

Изменить: см. ответ Денниса, на который я ссылался в своем предыдущем комментарии:

Controls.Add ( ddlCountries );
Controls.Add ( ddlStates );
person Chris Ballance    schedule 20.02.2009
comment
Это выглядит многообещающе. Если ViewState выключен (в раскрывающемся списке или в любом из его родительских элементов - вплоть до страницы), событие не срабатывает. (Он должен отправить обратно ...) - person teedyay; 20.02.2009
comment
Viewstate находится на странице, на которой находится элемент управления. Есть ли что-то особенное для этого элемента управления в этом CS-файле, что мне нужно сделать? - person Jack Lawson; 20.02.2009
comment
быстрый способ проверить - посмотреть исходный код и посмотреть, хранится ли что-нибудь в viewstate. - person Chris Ballance; 20.02.2009
comment
Ага; он включен для страницы, и другие элементы управления обратной передачей работают. - person Jack Lawson; 20.02.2009
comment
Ты спас мне день :) и бесплатное пиво от меня! - person Pinchy; 10.05.2012

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

Controls.Add ( ddlCountries );
Controls.Add ( ddlStates );

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

person baretta    schedule 20.02.2009
comment
Да - и сделайте это в случае, предшествующем загрузке (например, Init); в противном случае элементы управления не будут в нужном месте при перезагрузке ViewState. - person teedyay; 20.02.2009
comment
Да, или лучше переопределить CreateChildControls - person baretta; 20.02.2009
comment
Собирался сказать то же самое ... они должны быть созданы и добавлены в коллекцию Controls в CreateChildControls. Вы также можете отказаться от переопределения рендеринга. - person flatline; 20.02.2009
comment
Спасибо! Это определенно было так. - person Jack Lawson; 20.02.2009

Вам необходимо установить AutoPostBack в значение true для страны DropDownList.

protected override void OnLoad(EventArgs e)
{
    // base stuff

    ddlCountries.AutoPostBack = true;

    // other stuff
}

Изменить

Я скучал по твоему поступку. В этом случае вам нужно проверить, включен ли ViewState.

person Garry Shutler    schedule 20.02.2009
comment
Делает ли его строчка ddlCountries.AutoPostBack = true; не делать этого? - person Chris Ballance; 20.02.2009

У меня была такая же проблема, но я обошел ее, установив для AutoPostBack значение true, а на панели обновления установите триггер на идентификатор элемента управления выпадающего списка и имя события на SelectedIndexChanged, например.

    <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Always" enableViewState="true">
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="ddl1" EventName="SelectedIndexChanged" />
        </Triggers>
        <ContentTemplate>
            <asp:DropDownList ID="ddl1" runat="server" ClientIDMode="Static" OnSelectedIndexChanged="ddl1_SelectedIndexChanged" AutoPostBack="true" ViewStateMode="Enabled">
                <asp:ListItem Text="--Please select a item--" Value="0" />
            </asp:DropDownList>
        </ContentTemplate>
    </asp:UpdatePanel>
person Wolexie    schedule 14.11.2011

Сначала я хотел бы кое-что прояснить. Это сообщение (возврат на сервер) никогда не происходит, или это сообщение происходит, но оно никогда не попадает в обработчик событий ddlCountry_SelectedIndexChanged?

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

Во втором случае (обработчик событий никогда не запускается, даже если запрос сделан), вы можете попробовать следующие предложения:

  1. Запросите Request.Params [ddlCountries.UniqueID] и посмотрите, есть ли у него значение. Если да, запустите обработчик событий вручную.
  2. Пока состояние просмотра включено, привязывайте данные списка только в том случае, если это не обратная публикация.
  3. Если состояние просмотра должно быть отключено, то поместите привязку данных списка в OnInit вместо OnLoad.

Помните, что при вызове Control.DataBind () информация о состоянии и отправке данных больше не будет доступна из элемента управления. В случае, если состояние просмотра включено, между обратной отправкой значения DropDownList останутся нетронутыми (список не будет повторно привязан). Если вы запустите другой DataBind в OnLoad, он очистит данные о состоянии его представления, и событие SelectedIndexChanged никогда не будет запущено.

В случае, если состояние просмотра отключено, у вас нет другого выбора, кроме как каждый раз заново связывать список. Когда происходит обратная отправка, существуют внутренние вызовы ASP.NET для заполнения значения из Request.Params в соответствующие элементы управления, и я подозреваю, что это происходит в момент между OnInit и OnLoad. В этом случае восстановление значений списка в OnInit позволит системе правильно запускать события.

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

person TimeSpace Traveller    schedule 20.02.2009
comment
Когда я изменяю выбранный элемент списка, он вообще не попадает на сервер. Спасибо хоть; это еще одна проблема, которую мне пришлось исправить в других областях, и это хорошая информация. - person Jack Lawson; 20.02.2009
comment
Я понимаю; то я думаю, что ответ Денниса Майрена, вероятно, будет правильным: два DropDownList не находятся в дереве управления, поэтому, даже если они правильно отрисованы, механизмы обработки событий ASP.NET просто не могли видеть существование на уровне страницы, таким образом событие не запускается. - person TimeSpace Traveller; 20.02.2009