Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Even if DropDownList has its viestate disabled, SelectedValue should still return a value

I think I understand ViewState pretty well, but the following is giving me some troubles:

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

Postback controls such as dropdownlist and textbox restore their posted state (the selected item of a dropdown ist 'posted') even when ViewState is disabled, because even with ViewState disabled the control is still able to post its value


Assuming DropDownList has EnableViewState set to false, then ( according to the above quote ) when user issues a postback by selecting an item in DropDownList, the following code should result in Label1.Text displaying a value of a selected item ( thus DropDownList.SelectedValue should return a value selected by user, even if viewstate is disabled ), but instead I get an empty string:

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
    }
}


The author of that article appears to be an expert on the subject, so I'm assuming I'm doing something wrong !?!


thanx

like image 679
SourceC Avatar asked Jun 07 '09 21:06

SourceC


2 Answers

There is no selected value because:

1) there are no items in the drop down list, because you are only binding the data to it the first time around. Normally this is good practice, but when you have ViewState turned off, you must explicitly re-create the data for the control every time.

2) You are binding the data after the point in the page lifecycle where the Request dictionary values are applied to controls (namely, during the restoration of ViewState to controls.) The posted value exists in the Request dictionary, but since there are no items in the dropdownlist, it can't really do much with it. Even though ViewState is turned off, your author is correct - the posted value will be applied, at the point in the lifecycle where ViewState would normally be applied.

If you were to re-create the data for the list in Init(), then the dropdown would be populated for the posted value to be applied to, it would be applied, and the selected value would be available by the time you got to Load(). Hopefully that's clear. Some working code is below:

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();
    }
}
like image 161
womp Avatar answered Oct 04 '22 21:10

womp


Here's a much smarter DropDownList implementation. Not to troll or anything, but I can't believe how limited (read: stupid) some of the ASP.Net controls are....

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
like image 45
Josh Mouch Avatar answered Oct 04 '22 19:10

Josh Mouch