【问题标题】:Why does DropDownList.SelectedValue is relied on viewstate?为什么 DropDownList.SelectedValue 依赖于 viewstate?
【发布时间】:2013-08-06 10:30:59
【问题描述】:

如果我在我的页面上设置:EnableViewState="true" ViewStateMode="Disabled" - 那么 - 页面的 Viewstate 被禁用(除非覆盖...

然后,尝试读取(假设控件已在上次转储中填充到屏幕并选择了一个值):

MyDDL.SelectedValue 将产生""

这是因为禁用了视图状态:

但我的问题是更高层次的:

  • 如果是关于表单值(我仍然可以从 Request.Form[MyDDL.UniqueID] 获得) - 我们谈论的是不需要任何东西来保存其值的输入。

    李>
  • 为什么名为 (SelectedValue) 的 DropDownList 属性依赖于 ViewState ?

附言TextBox onchangeevent 确实依赖于视图状态,尽管控件是一个输入(不需要视图状态) - 它保存文本的值,然后在回发时进行比较。但它只依赖于视图状态设置 onchange 事件(和自动回发)

【问题讨论】:

  • 那么文本框的值不依赖于视图状态,你可以禁用视图状态,你仍然会得到文本框的值,它的值来自 IPostBackDataHandler 。 Request.Form[""] 仅在您使用 POST 方法提交数据时有效,考虑到用户由于验证错误或任何错误导致您的表单无法在该事件中发布而无法提交从 Request.Form[""] 获取您的值。
  • @surajsingh 我已经知道了。我的问题仍然存在。
  • 希望我现在走在正确的轨道上,我刚刚使用 listitems 创建了一个下拉列表,即使在禁用 ViewState 后它也会保留状态。我仍然需要检查通过数据库表限制的下拉列表,让我们看看它们是否保留了它们的状态,我能得到任何答案。
  • @surajsingh 不,你不是。你没有使用 !IsPostBack
  • 即使在之前的试验中,我也不必使用 IsPostBack,因为我使用 listitems 使用硬编码值。

标签: asp.net forms viewstate


【解决方案1】:

SelectedValue 依赖于 ViewState,因为在 PostBack 上它会从 ViewState 重建其 ListItems,然后从 Request 对象设置 DropDownList 上的选定值。

它不会直接将Request 值作为SelectedValue。这又是因为,ASP.Net 可以检查发布的DropDownList 是否在客户端未被篡改。它首先对ViewState 中的原始项目进行反序列化。然后它在项目中找到Request 值并将其Selected 属性设置为true。只有现在,SelectedValue 属性才可用。 (或SelectedIndex)。它现在应该可以触发SelectedIndexChanged 事件了。

这也是不需要在PageLoad中再次绑定DropDownList的原因。列表项会自动从ViewState 检索。

如果ViewState 被禁用,那么ViewState 中将没有原始列表项并且将为空。因此,它将无法将任何项目标记为选中。因此 SelectedValue 将为 0 或 SelectedItem 将为空。我认为SelectedIndexChanged 事件也不会触发。在这种情况下,需要进行数据绑定,最好是在init

不过,有一些解决方法。

完整参考:http://msdn.microsoft.com/en-us/library/ms972976.aspx

编辑:(在 Op 的 cmets 之后)

跟踪页面生命周期,看看SelectedValue在哪里依赖ViewState

Stage 1 Init:控制层次结构已建立。如果此处绑定了 DropDownList 或已以声明方式添加了 ListItems,则在此处填充 List。

第 2 阶段加载 ViewState:在 PostBack 中,ViewState 在此处验证并加载到 DropDownList 中。这里没有SelectedValue

第 3 阶段加载 PostBack 数据:此处获取 Request 值(来自表单请求),然后将其应用于控件。在这种DropDownList 的情况下,它现在从收到的Request 对象值中设置 SelectedValue,内部实现是这样的:

string selectedValue = HttpContext.Current.Request.Form[DropDownList_Id];
Items.FindByValue(selectedValue).Selected = true;

这里重要的是,如果 ViewState 不存在且 DropDownList 未绑定数据,则 ListItem 集合将为空,因此 SelectedValue 属性为 0。这与属性的内部实现无关。

如果 ViewState 不存在(禁用)并且 DropDownList 是数据绑定的,则 ListItem 集合将存在并且相应的项目将被标记为选中,因此SelectedValue 属性将返回正确的值。

如果项目集合是新的(通过重新绑定不同的数据集或 ViewState 无效),则在项目集合中将找不到 Request 表单值,并且再次 SelectedValue 将无效。

第 4 阶段页面加载:此时 ViewState(或数据绑定)和 PostBack 数据已经加载完毕。

第 5 阶段引发 PostBack 事件:在此阶段,如果在第 3 阶段更改了索引,则会触发 DropDownList 的 OnSelectedIndexChanged 事件。

因此,SelectedValue 在第 3 阶段依赖于 ViewState。当然,如果控件是适当的数据绑定,那么它就不会依赖 ViewState 作为推论。

SelectedValue 依赖 ViewState 来确保在设置项目集合之前已填充它。数据绑定/重新绑定只是确保填充项目集合的另一种方法。

希望澄清。

【讨论】:

  • 使用validationMAc检查被篡改的问题。与selectedvalue无关。
  • _ 它将无法将任何项目标记为 selected_ ,对。但它应该有一个像 request.form 一样的值(恕我直言)
  • "it has nothing to do with selectedvalue",在 ViewState 验证后设置 SelectedValue。查看页面生命周期事件。一段时间后我会更新答案以使其更清楚。
  • 查看那个参考中的属性的内部实现,这里不再赘述。
【解决方案2】:

总结:如果您希望控件在没有 ViewState 的情况下工作,您需要在每次回发时填充/绑定 Items 集合。我建议在 Page_Init 事件中执行此操作(即 OnInit 方法)。

首先,我总是推荐这篇很棒的文章:TRULY Understanding ViewState.

SelectedValue 不需要 ViewState。查看 DropDownList 继承自 ListControl 的代码,我们看到代码:

public virtual string SelectedValue
{
  get
  {
    int selectedIndex = this.SelectedIndex;
    if (selectedIndex >= 0)
      return this.Items[selectedIndex].Value;
    else
      return string.Empty;
  }

从这段代码中得到的重要一点是,必须填充 Items 列表才能获得 SelectedValue。

如果您使用 ViewState,Items 集合持久保存到 ViewState 或从 ViewState 加载,这允许 SelectedValue 属性在不重新绑定控件的情况下工作。

【讨论】:

  • 这就是它的工作原理。 (SelectedValue 的实现......)cool。 (因为如果我只需要值,那么依赖视图状态会很奇怪......)
【解决方案3】:
      protected void Page_Load(object sender, EventArgs e)
            {
                (!Page.IsPostBack)
                {
                    string qry = "SELECT TOP(5)xxx, xxxx FROM dbo.xxxxxx ";
                    DataSet ds = new DataSet();
                    ds = SqlHelper.ExecInDS(qry);
                    drpDwn.DataSource = ds.Tables[0];
                    drpDwn.DataValueField = Convert.ToString(ds.Tables[0].Columns["xxx"]);
                    drpDwn.DataTextField = Convert.ToString(ds.Tables[0].Columns["xxx"]);                   
                    drpDwn.DataBind();
                }
               //Here You will get selected value from dropdown
               string sss= Request.Form["drpDwn"];
    }

【讨论】:

    【解决方案4】:

    如果您希望 DropDownList 在没有 ViewState 的情况下工作,您可以将 page_load 中的控件绑定一次,如下所示:

         protected void Page_Load(object sender, EventArgs e)
                {        
         //whatever you use declarative binding (in aspx page), or define data source  here
                    if (!IsPostBack)
                    {
                      ddl.DataBind(); //fire databinding events and fill items, and selectedvalue has a value.
                    }
    
                    //you can get the selectedvalue
                    var sv=ddl.SelectedValue ; //
                }           
    
    • 在这种情况下(ViewState 被禁用),Asp.net FrameWork 使用每个 PostBack 从后端检索项目。

    • 在这种情况下(ViewState 已启用),Asp.net FrameWork 从 ViewState 中检索项目,而不用每次 PostBack 访问后端

    通常,Asp.net FrameWork 在 PreRender 事件中触发数据绑定事件:Read ASP.NET Page Life Cycle Overview

    您可以通过启用 Trace 来确认该行为。

    SelectedValue 不直接依赖于来自 source code of ListControl 的 ViewState,而是依赖于上述项目。

    【讨论】:

      猜你喜欢
      • 2016-05-05
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-12
      • 2020-05-29
      • 1970-01-01
      相关资源
      最近更新 更多