【问题标题】:2 Dropdownlists for a Year Range2 年范围的下拉列表
【发布时间】:2012-10-01 17:41:00
【问题描述】:

我遇到了一个问题,我真的没想到会被耽搁这么多小时,这让我发疯了

如标题中所述,我需要两个 DropDownLists,其中 ToYears 列表的值从 FromYear 的选择开始:

从年份
2000
2001
2002
2003
2004

ToYear
2002
2003
2004

所以我尝试使用 2 asp:dropdownlist> 并在 FromYear 的 SelectedIndexEvent 期间更改选定的 ToYear 但这会触发选定的 FromYear 事件并且不知何故它不会再次触发。

现在我从 Ajax Control Toolkit 中找到了CascadingDropDown,并认为这可能是件好事。但我不想调用网络服务,而是想在实际页面后面的代码中使用方法。

还应在回发后记住选择 - 年份范围会根据后面代码中的属性而变化。

我在某处读到自动回发不适用于 CascadingDropDown。

您认为最优雅、最简单的解决方案是什么?

非常感谢您。

编辑:我将发布我的帖子的几个部分 - 希望对您有所帮助 标记:

    <asp:DropDownList AutoPostBack="True" ID="DropDownFromYear" runat="server"     OnSelectedIndexChanged="FromYearChanged" />
    <asp:Label ID="UntilLabel" runat="server" Text=" until " />
    <asp:UpdatePanel ID="ToYearUpdatePanel" runat="server" style="display: inline-block;">
        <ContentTemplate>
            <asp:DropDownList AutoPostBack="true" ID="DropDownToYear" runat="server" OnSelectedIndexChanged="ToYearChanged" />
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="DropDownFromYear" EventName="SelectedIndexChanged" />
        </Triggers>
    </asp:UpdatePanel>

CodeBehind(从 OnInit 调用):

    private void InitializeDropDownYears()
    {

        //Calculate the YearMin YearMax Properties
        CalculateYearMinMax();

        int adaptedFromYear = 0, adaptedToYear = 0;

        //get the previously selected Years
        if (DropDownToYear.SelectedItem != null) adaptedToYear = int.Parse(DropDownToYear.SelectedValue);
        if (DropDownFromYear.SelectedItem != null) adaptedFromYear = int.Parse(DropDownFromYear.SelectedValue);

        //check the minimum year constraints 2005 was selected but minYear is 2010 -> adpated is set to 2010
        if (YearMin > adaptedFromYear || adaptedFromYear == 0) adaptedFromYear = YearMin;
        if (YearMax < adaptedToYear || adaptedToYear == 0) adaptedToYear = YearMax;

        //check the 5 year range constraint
        if ((YearMax - YearMin) > 5)
        {
            adaptedFromYear = DateTime.Now.Year - 2;
            adaptedToYear = DateTime.Now.Year + 2;
        }

        Dictionary<string, string> toYears = new Dictionary<string, string>();
        Dictionary<string, string> fromYears = new Dictionary<string, string>();

        for (int tempYear = YearMin; tempYear <= YearMax; tempYear++)
        {
            fromYears.Add(tempYear.ToString(), tempYear.ToString());
            if (tempYear >= adaptedFromYear)
            {
                toYears.Add(tempYear.ToString(), tempYear.ToString());
            }
        }

        DropDownFromYear.DataSource = fromYears;
        DropDownFromYear.DataValueField = "Key";
        DropDownFromYear.DataTextField = "Value";
        DropDownFromYear.SelectedValue = adaptedFromYear.ToString();
        DropDownFromYear.DataBind();

        DropDownToYear.DataSource = toYears;
        DropDownToYear.DataValueField = "Key";
        DropDownToYear.DataTextField = "Value";
        DropDownToYear.SelectedValue = adaptedToYear.ToString();
        DropDownToYear.DataBind();
        if(!IsPostBack)
        {
            SelectedFromYear = adaptedFromYear;
            SelectedToYear = adaptedToYear;
        }
    }

    private void CalculateYearMinMax()
    {
        IList<Task> taskList = CurrentLicense.TaskList;

        List<DateTime> startDates = taskList.Select(task => task.StartDate).ToList();
        YearMin = startDates.Min(date => date).Year;

        List<DateTime> endDates = taskList.Select(task => task.EndDate).ToList();
        YearMax = endDates.Max(date => date).Year;
    }

事件处理程序:

    protected void FromYearChanged(object sender, EventArgs e)
    {
        SelectedFromYear = int.Parse(DropDownToYear.SelectedValue);
        SelectedToYear = int.Parse(DropDownFromYear.SelectedValue);
        if (SelectedFromYear > SelectedToYear)
        {
            SelectedToYear = SelectedFromYear;
        }
        UpdateGanttTables();
    }

    protected void ToYearChanged(object sender, EventArgs e)
    {
        SelectedFromYear = int.Parse(DropDownToYear.SelectedValue);
        SelectedToYear = int.Parse(DropDownFromYear.SelectedValue);
        UpdateGanttTables();
    }

【问题讨论】:

  • 这应该完全可以用 c# 来实现。你能展示你的 selectedIndexChanged 方法中发生了什么吗?基本上,如果我理解正确,您想在 FromYear 下拉列表中选择一个值,然后通过选择该值,您希望 DDL“ToYear”从 FromYear 中选择的值开始?
  • 就个人而言,如果我看到一个网站回发只是为了更新下拉列表,我会有点摇头。
  • 嗨千,感谢您的快速响应。实际上我可以在 FromYear 下拉列表中有一个从 1950 到 2050 的范围,如果用户选择 FromYear:1980 它应该显示在 ToYear 1980 到 2050 中。如果他之前在这个范围内选择了一个 ToYear(例如 1990)它应该仍然是选择。如果先前选择的范围较小,则应使用 FromYear 的值。另一件事是:如果在第一个 PageLoad DateTime.Now.Year-2 上选择的可能范围大于 5 年,则应在 FromYear 中选择 ToYear DateTime.Now.Year+2。
  • @LeeTaylor 通过下拉菜单只应立即刷新页面的一部分。我打算为此使用更新面板。

标签: c# asp.net webforms viewstate


【解决方案1】:

填充DropDownList 控件听起来很容易对吧?当您使用 ASP.NET WebForms 的默认行为时,情况就是如此。但是,当您想要获得特定功能时,您可能会遇到几个问题,例如,在 WebForms 中,尝试使用 AJAX 填充 DropDownLists(这真的很痛苦,我找到的唯一解决方案是禁用安全检查页面&lt;%@ Page EnableEventValidation="false")

供参考:

How to fill an asp:DropDown client side?

由于您使用的是 WebForms,因此最好的方法可能是使用总的UpdatePanel

例子:

结果

ASPX 标记

    <asp:ScriptManager runat="server" ID="sm" />
    <asp:UpdateProgress runat="server" AssociatedUpdatePanelID="updatePanel" DisplayAfter="0" DynamicLayout="true">
        <ProgressTemplate>
            Working...
        </ProgressTemplate>
    </asp:UpdateProgress>
    <asp:UpdatePanel runat="server" ID="updatePanel">
        <ContentTemplate>
            <div>
                <asp:Label ID="Label1" Text="From" runat="server" AssociatedControlID="from" />
            </div>
            <div>
                <asp:DropDownList runat="server" ID="from" AutoPostBack="true" CausesValidation="false" OnSelectedIndexChanged="from_SelectedIndexChanged">
                </asp:DropDownList>
            </div>
            <div>
                <asp:Label ID="Label2" Text="To" runat="server" AssociatedControlID="to" />
            </div>
            <div>
                <asp:DropDownList runat="server" ID="to" />
            </div>
        </ContentTemplate>
    </asp:UpdatePanel>

后面的页面代码

    private const int MaxYear = 2030;
    private const int MinYear = 1959;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!this.IsPostBack)
        {
            var fromRange = Enumerable.Range(MinYear, MaxYear - MinYear);

            this.from.DataSource = fromRange;
            this.from.DataBind();
        }
    }

    protected void from_SelectedIndexChanged(object sender, EventArgs e)
    {
        var selectedYear = Convert.ToInt32(this.from.SelectedValue);
        var toRange = Enumerable.Range(selectedYear, MaxYear - selectedYear);

        this.to.DataSource = toRange;
        this.to.DataBind();
    }

I just uploaded this sample to my GitHub for reference

【讨论】:

  • 嗨@Jupaol,谢谢!看起来很有希望。但有一件事仍然不起作用 - 我猜这是最困难的部分:我必须在第一次加载时为 From AND To 下拉列表预选某些年份。如果我在 if(!isPostBack) 下这样做,它将不再触发 selectedIndexChanged 事件......
  • 您是否认为可以使用绑定到具有键/值的字典的中继器,其中键是年份,值是表示选择哪个元素的布尔值?在代码隐藏中我会简单地使用列表?
  • 嗨 Jupaol 我将您的回复标记为答案,尽管我采用了不同的方法 - 但您让我走上了正确的道路:) 我现在将编辑我的初始帖子
【解决方案2】:

最后我想通了并且得到了——我认为这是一个不错的解决方案,因为它使我能够:

  • 最初用数据填充两个 DDL
  • 在两个 DDL 中预选项目
  • 仍然在页面上使用 EnableEventValidation="true"
  • 我可以通过简单地调用 DataBind() 来更新 DDL;在他们身上

与我之前的方法的主要区别在于,我在 DDL 的 OnDataBinding 事件期间填充了数据。因此,当我在 PageLoad 期间执行 DataBind() 时,它会自动发生。我首先要确保的唯一一件事是填写包含我的信息的字典。

如果我想从 FromYearsDDL 的 selectionChangeEvent 更新 ToYearsDDL,我只需更新 ToYearsDDL 的数据并调用 ToYearsDDL.DataBind();

希望这可以帮助遇到同一堵墙的其他人!

标记来了:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="LinkedDropDownsBound.aspx.cs"
    Inherits="ASP.Net_Spielwiese.LinkedDropDownsBound"  EnableEventValidation="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
        <asp:UpdatePanel runat="server" ID="updatePanel">
            <ContentTemplate>
                <div>
                    <asp:Label ID="FromLabel" Text="From" Enabled="false" runat="server"  />
                </div>
                <div>
                    <asp:DropDownList runat="server" ID="FromYearsDDL" AutoPostBack="true" CausesValidation="false" OnDataBinding="DDLFromDataBind"
                        OnSelectedIndexChanged="DDLFromSelectedIndexChanged">
                    </asp:DropDownList>
                </div>
                <div>
                    <asp:Label ID="ToLabel" Text="To" Enabled="false" runat="server" />
                </div>
                <div>
                    <asp:DropDownList runat="server" ID="ToYearsDDL" AutoPostBack="true" CausesValidation="false" OnDataBinding="DDLToDataBind"
                        OnSelectedIndexChanged="DDLToSelectedIndexChanged"/>
                </div>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>

下面是代码:

public partial class LinkedDropDownsBound : System.Web.UI.Page
{
    public Dictionary<String, Boolean> FromYears
    {
        get
        {
            if (ViewState["FromYears"] == null)
            {
                ViewState["FromYears"] = new Dictionary<String, Boolean>();
            }
            return ViewState["FromYears"] as Dictionary<String, Boolean>;
        }
        set
        {
            ViewState["FromYears"] = value;
        }
    }
    public Dictionary<String, Boolean> ToYears
    {
        get
        {
            if (ViewState["ToYears"] == null)
            {
                ViewState["ToYears"] = new Dictionary<String, Boolean>();
            }
            return ViewState["ToYears"] as Dictionary<String, Boolean>;
        }
        set
        {
            ViewState["ToYears"] = value;
        }
    }

    public int MinYear = 1975;
    public int MaxYear = 2015;


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            InitFromYears();
            InitToYears();
            DataBind();
        }
    }

    private void InitFromYears()
    {
        FromYears = new Dictionary<string, bool>();
        IEnumerable<int> fromRange = Enumerable.Range(MinYear, MaxYear - MinYear);

        foreach (var fromYear in fromRange)
        {
            FromYears.Add(fromYear.ToString(), fromYear == (DateTime.Now.Year - 2));
        }
    }

    private void InitToYears()
    {
        ToYears = new Dictionary<string, bool>();
        //get the selected FromYear Value
        int minToYear = Convert.ToInt32(FromYears.FirstOrDefault(dict => dict.Value).Key);
        //make sure ToYears is at least FromYears
        if (minToYear < Convert.ToInt32(FromYears.Min(k => k.Key)))
        {
            minToYear = Convert.ToInt32(FromYears.Min(k => k.Key));
        }
        IEnumerable<int> toRange = Enumerable.Range(minToYear, MaxYear - minToYear);
        foreach (var toYear in toRange)
        {
            ToYears.Add(toYear.ToString(), toYear == (DateTime.Now.Year + 2));
        }
    }

    protected void DDLFromDataBind(object sender, EventArgs e)
    {
        FromYearsDDL.DataSource = FromYears;
        FromYearsDDL.DataValueField = "Key";
        FromYearsDDL.DataTextField = "Key";
        FromYearsDDL.SelectedValue = FromYears.FirstOrDefault(y => y.Value).Key;
    }

    protected void DDLFromSelectedIndexChanged(object sender, EventArgs e)
    {
        //update the FromYear Dictionary
        var tempDictionary = FromYears.ToDictionary(fromYear => fromYear.Key, fromYear => fromYear.Key.Equals(FromYearsDDL.SelectedValue));
        FromYears = tempDictionary;

        //Call Bind on the ToYear DDL
        ToYearsDDL.DataBind();

        //do my other update stuff here
        FromLabel.Text = FromYearsDDL.SelectedValue;
        ToLabel.Text = ToYearsDDL.SelectedValue;
    }

    protected void DDLToSelectedIndexChanged(object sender, EventArgs e)
    {
        //do my other update stuff here
        FromLabel.Text = FromYearsDDL.SelectedValue;
        ToLabel.Text = ToYearsDDL.SelectedValue;
    }

    protected void DDLToDataBind(object sender, EventArgs e)
    {
        InitToYears();
        ToYearsDDL.DataSource = ToYears;
        ToYearsDDL.DataValueField = "Key";
        ToYearsDDL.DataTextField = "Key";
        ToYearsDDL.SelectedValue = ToYears.FirstOrDefault(y => y.Value).Key;
    }
}

【讨论】:

    【解决方案3】:

    这是 HTML 页面

    在c#页面后面的代码中

    private void BindYearDropdown()
            {
                int year;
    
                for (year = DateTime.Now.Year; year >= 2010 ; year--)
                {
                    DDLYear.Items.Add(year.ToString());
                }
            }
    

    上面的代码是多年前的代码

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-01
      • 2021-06-27
      • 2014-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多