问题 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();
    }
}

编辑: Viewstate位于页面上,页面上的其他控件正确执行回发,而不是这样。


5886
2018-02-20 16:42


起源

可能不算作答案,但Ajax Control Toolkit在更新面板中提供了您想要的内容: asp.net/AJAX/AjaxControlToolkit/Samples/CascadingDropDown/... - Sean
是啊;不过,我已经永远宣誓了ACT。绝对垃圾IMO;我实际上正在为我的项目建立一个替代品,因为我们只能让CCD控件与Web服务一起工作,这有其他含义。 - Jack Lawson


答案:


Viewstate是否已启用?

编辑: 也许您应该重新考虑覆盖渲染功能

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

而是将下拉列表添加到控件并使用默认的RenderContents呈现控件。

编辑: 请参阅我在之前的评论中提到的Dennis的答案:

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

5
2018-02-20 16:45



这很有希望。如果ViewState处于关闭状态(在下拉列表或其任何父项上 - 一直到页面),则事件将不会触发。 (虽然应该回复......) - teedyay
Viewstate位于控件所在的页面上。在这个.cs文件中是否有特定于此控件的东西,我需要做什么? - Jack Lawson
快速检查方法是查看源代码并查看是否有任何内容存储在viewstate中 - Chris Ballance
是啊;它正在页面和其他回发控件正在工作。 - Jack Lawson
谢谢!就是这样。 - Jack Lawson


我无法看到您将这些控件添加到控件层次结构中。 尝试:

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

除非控件是控件层次结构的一部分,否则不会调用事件。


4
2018-02-20 17:30



是 - 并且在比Load更早的事件中执行此操作(例如Init);否则,当重新加载ViewState时,控件将不在正确的位置。 - teedyay
是的,或者最好是覆盖CreateChildControls - baretta
即将说同样的事情......应该创建它们并将它们添加到CreateChildControls中的Controls集合中。您也可以删除渲染覆盖。 - flatline
谢谢!这绝对是它。 - Jack Lawson


你需要设置 AutoPostBack 对国家来说是真实的 DropDownList

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

    ddlCountries.AutoPostBack = true;

    // other stuff
}

编辑

我错过了你做过这件事。在这种情况下,您需要检查ViewState是否已启用。


3
2018-02-20 16:45



他的行“ddlCountries.AutoPostBack = true;”不这样做? - Chris Ballance


我遇到了同样的问题,但是通过将AutoPostBack设置为true来绕过它,并且在更新面板中将触发器设置为下拉列表控件ID和事件名称到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>

1
2017-11-14 12:48





首先,我想澄清一些事情。这是一个回发(回到服务器)永远不会发生,或者是回发后,但它永远不会进入ddlCountry_SelectedIndexChanged事件处理程序?

我不确定你遇到了哪种情况,但如果是第二种情况,我可以提供一些建议。如果是第一种情况,那么以下是FYI。

对于第二种情况(即使请求发生,事件处理程序也不会触发),您可能需要尝试以下建议:

  1. 查询Request.Params [ddlCountries.UniqueID]并查看它是否有值。如果有,则手动触发事件处理程序。
  2. 只要视图状态为on,则仅在列表数据不是回发时绑定。
  3. 如果必须关闭视图状态,则将列表数据绑定放在OnInit而不是OnLoad。

请注意,在调用Control.DataBind()时,控件将不再提供查看状态和回发信息。在视图状态为on的情况下,在post back之间,DropDownList的值将保持不变(列表不会被反弹)。如果在OnLoad中发出另一个DataBind,它将清除其视图状态数据,并且永远不会触发SelectedIndexChanged事件。

在视图状态关闭的情况下,您别无选择,只能每次重新绑定列表。当回发发生时,有内部ASP.NET调用将值从Request.Params填充到适当的控件,我怀疑发生在OnInit和OnLoad之间。在这种情况下,在OnInit中恢复列表值将使系统能够正确触发事件。

感谢您抽出时间阅读本文,如果我错了,欢迎大家纠正。


0
2018-02-20 17:14



当我更改所选列表项时,它根本没有命中服务器。谢谢,但是;这是我必须在其他领域解决的另一个问题,这是很好的信息。 - Jack Lawson
我懂了;然后我认为Dennis Myren的答案可能是正确的:两个DropDownList不在控制树中,所以即使它们被正确渲染,ASP.NET事件处理机制也根本看不到页面级别的存在,因此没有事件被解雇。 - TimeSpace Traveller