即使DropDownList禁用了viestate,SelectedValue仍应返回一个值

时间:2009-06-07 21:40:41

标签: c# asp.net viewstate

我认为我很了解ViewState,但以下是给我一些麻烦:

来自 http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/truly-understanding-viewstate.aspx

  

即使禁用ViewState,回退控件(如下拉列表和文本框)也会恢复其发布状态(下拉列表的选定项目已发布),因为即使禁用了ViewState,控件仍然可以发布其值


假设 DropDownList EnableViewState 设置为false,那么(根据上面的引用)当用户通过选择 DropDownList ,以下代码应导致 Label1.Text 显示所选项的值(因此 DropDownList.SelectedValue 应返回用户选择的值,即使viewstate已禁用),但我得到一个空字符串:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        string[] number = {"first","second","third"};
        DropDownList1.DataSource = number;
        this.DataBind();

    }
    if (IsPostBack)
    {
       Label1.Text = DropDownList1.SelectedValue; // displays empty string
       // Label1.Text = DropDownList1.SelectedItem.Text; // causes an exception           
       // Label1.Text = DropDownList1.SelectedIndex.ToString(); // displays empty string
    }
}


该文章的作者似乎是这方面的专家,所以我假设我做错了什么!?!


感谢名单

2 个答案:

答案 0 :(得分:17)

没有选定的值,因为:

1)下拉列表中没有项目,因为您只是第一次将数据绑定到它。通常这是一种很好的做法,但是当您关闭ViewState时,您必须每次都为控件显式重新创建数据。

2)您正在页面生命周期中将请求字典值应用于控件的点之后(即,在将ViewState恢复到控件期间)绑定数据。发布的值存在于Request字典中,但是从那里开始在下拉列表中没有任何项目,它无法真正做到这一点。即使ViewState已关闭,您的作者也是正确的 - 将在生命周期中通常应用ViewState的点处应用已发布的值

如果您要在Init()中重新创建列表的数据,那么将填充下拉列表以显示要应用的已发布值,它将被应用,并且所选值将在时间可用你得Load()。希望这很清楚。一些工作代码如下:

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            Label1.Text = DropDownList1.SelectedValue;
        }
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        string[] number = { "first", "second", "third" };
        DropDownList1.DataSource = number;
        DropDownList1.DataBind();
    }
}

答案 1 :(得分:1)

这是一个更智能的DropDownList实现。不是巨魔或任何东西,但我不敢相信有些限制(阅读:愚蠢)一些ASP.Net控件....

Public Class DropDownList
    Inherits System.Web.UI.WebControls.DropDownList

    Private _SelectedIndex As Integer? = -1
    Private _SelectedValue As String = Nothing
    Private _StateFromClient As Boolean = False
    Private _StateFromLocal As Boolean = False

    Protected Overrides Sub OnInit(ByVal e As EventArgs)
        MyBase.OnInit(e)
        Page.RegisterRequiresControlState(Me)
    End Sub

    Public Overrides Property SelectedIndex() As Integer
        Get
            If Not _StateFromLocal Then
                Me.LoadStateFromClient()

                If _StateFromClient Then
                    Return _SelectedIndex
                End If
            End If

            Return MyBase.SelectedIndex
        End Get
        Set(ByVal value As Integer)
            _StateFromLocal = True
            MyBase.SelectedIndex = value
        End Set
    End Property

    Public Overrides Property SelectedValue() As String
        Get
            If Not _StateFromLocal Then
                LoadStateFromClient()

                If _StateFromClient Then
                    Return _SelectedValue
                End If
            End If

            Return MyBase.SelectedValue
        End Get
        Set(ByVal value As String)
            _StateFromLocal = True
            MyBase.SelectedValue = value
        End Set
    End Property

    Private Sub LoadStateFromClient()
        If _StateFromClient Then Return
        If _StateFromLocal Then Return
        If Me.IsViewStateEnabled Then Return
        If Not Me.Page.IsPostBack Then Return

        If Not _SelectedIndex.HasValue Then
            Throw New Exception("ControlState has not yet been loaded and so state does not exist.")
        End If
        _SelectedValue = Me.Page.Request.Form(Me.UniqueID)
        _StateFromClient = True
    End Sub

    Protected Overrides Sub PerformSelect()
        ' Called when DataBound() is called, which can affect the Selected* property values
        _StateFromLocal = True
        MyBase.PerformSelect()
    End Sub

    Protected Overrides Function SaveControlState() As Object
        Dim state As Object = MyBase.SaveControlState()

        If Me.SelectedIndex >= 0 Then
            If state IsNot Nothing Then
                Return New Pair(state, Me.SelectedIndex)
            Else
                Return Me.SelectedIndex
            End If
        Else
            Return state
        End If
    End Function

    Protected Overrides Sub LoadControlState(ByVal state As Object)
        If state IsNot Nothing Then
            Dim p As Pair = TryCast(state, Pair)
            If p IsNot Nothing Then
                MyBase.LoadControlState(p.First)
                _SelectedIndex = CInt(p.Second)
            Else
                If (TypeOf (state) Is Integer) Then
                    _SelectedIndex = CInt(state)
                Else
                    MyBase.LoadControlState(state)
                End If
            End If
        End If
        MyBase.SelectedIndex = _SelectedIndex
    End Sub

End Class