在回发后保持动态表

时间:2014-12-12 15:23:29

标签: asp.net vb.net postback

我有一个在后面的代码中创建的表。在vb代码中,当选择组合框值时,基于查询返回的数据填充表。该代码创建一行,其中两个单元格用于标签,另一个用于数据中每行的下拉列表。我在保留在回发后为每一行创建的选定下拉列表值时遇到问题。

最初填充表时,我将数据存储在ViewState值中,并根据PageLoad中的这些设置重新创建表。问题是每次我更改下拉列表的值,然后通过单击保存设置导致回发,所有设置都被错误保存,因为它们在甚至调用保存之前被还原。

我希望在回发后维护这些值,但在选择新帐户时仍会更新数据库中的值。我已经尝试了几种方法来实现这一点,并且在我的代码中遇到了两个问题:

当我在标记中的表上有EnableViewState =“true”时: 当我从组合框中选择一个项目以选择一个新帐户时,下拉列表中的选定值将在此时清除并使用新数据库值时保留。

当我在标记中的表上有EnableViewState =“false”时: 任何回发都会将下拉列表重置为其数据库值。即使单击“保存”立即回发以将值保存到数据库,也只会重新保存其当前数据库值并忽略所选值。

代码背后的代码:

Imports System.Data.SqlClient

Imports Telerik.Web.UI

Public Class AccountSettings2
    Inherits Page

    Private _selectedAccountID As Integer
    Protected _truckPermissions As List(Of PermissionData2)

    Private Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init

        _truckPermissions = New List(Of PermissionData2)

        If Not IsNothing(Session("SelectedAccountID")) Then
            _selectedAccountID = Session("SelectedAccountID")
        End If

        If Not IsPostBack Then

            Dim dtAccounts As New DataTable("Accounts")
            Dim col1 As DataColumn = New DataColumn()
            col1.DataType = System.Type.GetType("System.Int32")
            col1.ColumnName = "AccountID"
            dtAccounts.Columns.Add(col1)
            Dim col2 As DataColumn = New DataColumn()
            col2.DataType = System.Type.GetType("System.String")
            col2.ColumnName = "Name"
            dtAccounts.Columns.Add(col2)

            Dim row1 As DataRow
            Dim row2 As DataRow
            Dim row3 As DataRow
            Dim row4 As DataRow
            row1 = dtAccounts.NewRow()
            row1("AccountID") = 1
            row1("Name") = "Account 1"
            dtAccounts.Rows.Add(row1)
            row2 = dtAccounts.NewRow()
            row2("AccountID") = 2
            row2("Name") = "Account 2"
            dtAccounts.Rows.Add(row2)
            row3 = dtAccounts.NewRow()
            row3("AccountID") = 3
            row3("Name") = "Account 3"
            dtAccounts.Rows.Add(row3)
            row4 = dtAccounts.NewRow()
            row4("AccountID") = 4
            row4("Name") = "Account 4"
            dtAccounts.Rows.Add(row4)

            rcbAccounts.DataValueField = "AccountID"
            rcbAccounts.DataTextField = "Name"
            rcbAccounts.DataSource = dtAccounts
            rcbAccounts.DataBind()

        End If

    End Sub

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not IsPostBack Then
            If _selectedAccountID > 0 Then
                rcbAccounts.SelectedValue = _selectedAccountID
                SelectAccount(_selectedAccountID)
            End If
        End If

    End Sub

#Region "UI Updates"

    Private Sub SelectAccount(accountID As Integer)

        _selectedAccountID = accountID
        Session("SelectedAccountID") = accountID
        CreateTruckPermissionsData(accountID)

    End Sub

    Private Sub CreateTruckPermissionsData(accessTypeID As Integer)

        tblTruckPermissions.Rows.Clear()

        _truckPermissions.Add(New PermissionData2(1, "Permission 1", "Permission 1", accessTypeID))
        _truckPermissions.Add(New PermissionData2(2, "Permission 2", "Permission 2", accessTypeID))
        _truckPermissions.Add(New PermissionData2(3, "Permission 3", "Permission 3", accessTypeID))
        _truckPermissions.Add(New PermissionData2(4, "Permission 4", "Permission 4", accessTypeID))
        ViewState("_truckPermissions") = _truckPermissions

        Dim dtAccessTypes As New DataTable("AccessTypes")
        Dim col1 As DataColumn = New DataColumn()
        col1.DataType = System.Type.GetType("System.Int32")
        col1.ColumnName = "AccessTypeID"
        dtAccessTypes.Columns.Add(col1)
        Dim col2 As DataColumn = New DataColumn()
        col2.DataType = System.Type.GetType("System.String")
        col2.ColumnName = "Description"
        dtAccessTypes.Columns.Add(col2)

        Dim row1 As DataRow
        Dim row2 As DataRow
        Dim row3 As DataRow
        Dim row4 As DataRow
        row1 = dtAccessTypes.NewRow()
        row1("AccessTypeID") = 1
        row1("Description") = "Type 1"
        dtAccessTypes.Rows.Add(row1)

        row2 = dtAccessTypes.NewRow()
        row2("AccessTypeID") = 2
        row2("Description") = "Type 2"
        dtAccessTypes.Rows.Add(row2)
        row3 = dtAccessTypes.NewRow()
        row3("AccessTypeID") = 3
        row3("Description") = "Type 3"
        dtAccessTypes.Rows.Add(row3)
        row4 = dtAccessTypes.NewRow()
        row4("AccessTypeID") = 4
        row4("Description") = "Type 4"
        dtAccessTypes.Rows.Add(row4)

        For Each pd As PermissionData2 In _truckPermissions
            Dim tr As New TableRow()
            Dim td As New TableCell()
            Dim td2 As New TableCell()
            Dim l As New Label()
            Dim ddl As New RadDropDownList()

            l.Text = pd.Name
            ddl.ID = "ddlTruckPermission" + pd.ID.ToString()
            ddl.DataTextField = "Description"
            ddl.DataValueField = "AccessTypeID"
            ddl.DataSource = dtAccessTypes
            ddl.DataBind()
            ddl.SelectedValue = pd.HasAccess

            td.Controls.Add(l)
            td2.Controls.Add(ddl)
            tr.Cells.Add(td)
            tr.Cells.Add(td2)

            tblTruckPermissions.Rows.Add(tr)
        Next

    End Sub

    Private Sub RefreshTruckSettings()

        If _selectedAccountID = 0 Then
            Return
        End If

        For Each r As TableRow In tblTruckPermissions.Rows
            For Each c As Control In r.Cells(1).Controls
                If c.ID.Contains("ddlTruckPermission") Then
                    Dim ddl As RadDropDownList = DirectCast(c, RadDropDownList)

                    Dim pd As PermissionData2 = _truckPermissions.Find(Function(x) x.ID = Integer.Parse(ddl.ID.Substring(0 + "ddlTruckPermission".Length, ddl.ID.Length - "ddlTruckPermission".Length)))

                    If Not IsNothing(pd) Then
                        ddl.SelectedValue = pd.HasAccess
                    End If
                End If
            Next
        Next

    End Sub

#End Region

#Region "Events"

    Protected Sub btnSavePermissions_Click(sender As Object, e As EventArgs)

        If _selectedAccountID > 0 Then

            Dim permissionUpdates As List(Of PermissionUpdate) = New List(Of PermissionUpdate)()

            For Each r As TableRow In tblTruckPermissions.Rows
                For Each c As Control In r.Cells(1).Controls
                    If c.ID.Contains("ddlTruckPermission") Then
                        Dim ddl As RadDropDownList = DirectCast(c, RadDropDownList)
                        permissionUpdates.Add(New PermissionUpdate(Integer.Parse(ddl.ID.LastIndexOf("ddlTruckPermission")), False, ddl.SelectedValue))
                    End If
                Next
            Next

            ' Code to save permissions to database

        End If

    End Sub

    Protected Sub rcbAccounts_SelectedIndexChanged(sender As Object, e As RadComboBoxSelectedIndexChangedEventArgs)

        Dim newIndex As Integer

        If (Integer.TryParse(e.Value, newIndex)) Then
            SelectAccount(newIndex)
        End If

    End Sub

#End Region

End Class


<Serializable>
Public Class PermissionData2

    Private _id As Integer
    Private _name As String
    Private _description As String
    Private _hasAccess As Integer

    Public Property ID() As Integer

        Get
            Return _id
        End Get
        Set(value As Integer)
            _id = value
        End Set

    End Property

    Public Property Name() As String

        Get
            Return _name
        End Get
        Set(value As String)
            _name = value
        End Set

    End Property

    Public Property Description() As String

        Get
            Return _description
        End Get
        Set(value As String)
            _description = value
        End Set

    End Property

    Public Property HasAccess() As Integer

        Get
            Return _hasAccess
        End Get
        Set(value As Integer)
            _hasAccess = value
        End Set

    End Property

    Public Sub New()

        _id = 0
        _name = Name
        _description = Description
        _hasAccess = 0

    End Sub

    Public Sub New(id As Integer, name As String, description As String, hasAccess As Integer)

        _id = id
        _name = name
        _description = description
        _hasAccess = hasAccess

    End Sub

End Class

ASPX:

    <%@ Page Language="vb" AutoEventWireup="false"
    CodeBehind="AccountSettings2.aspx.vb" Inherits="AccountSettings2" %>

<!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 id="Head1" runat="server">
    <link rel="stylesheet" type="text/css" href="styles/default.css" />
    <title>Account Settings</title>
</head>
<body>
    <form id="form1" runat="server">

        <asp:ScriptManager runat="server" ID="ScriptManager1"></asp:ScriptManager>

    <asp:UpdatePanel id="UpdatePanel1" runat="server" UpdateMode="Always">
    <ContentTemplate>

        <telerik:RadComboBox ID="rcbAccounts" runat="server" Height="200" Width="200"
            DropDownAutoWidth="Enabled" EmptyMessage="Select an Account" HighlightTemplatedItems="true"
            EnableLoadOnDemand="true" Filter="Contains"
            OnSelectedIndexChanged="rcbAccounts_SelectedIndexChanged" AutoPostBack ="true"
            Label="Accounts: " Skin="Office2010Silver" />

        <asp:Table ID="tblTruckPermissions" runat="server" EnableViewState="true" />

        <asp:Button ID="btnSavePermissions" runat="server" Text="Save" OnClick="btnSavePermissions_Click" />

    </ContentTemplate>
</asp:UpdatePanel>

</form>
</body>
</html>

2 个答案:

答案 0 :(得分:1)

好的,现在我看了一切,我已经清除了原来的答案。以下是一些想法:

<强>首先

我会从Page_Init()方法中取出所有内容并将其移到Page_Load()方法中。应该谨慎使用Page_Int(),我没有看到在这里使用它的充分理由。 Page_Int()的问题在于,在创建大多数对象之前,它会在页面生命周期中过早触发,因此您最终会遇到难以理解的奇怪行为。

我只将它用于与页面相关的LOGIC,并且需要在页面加载之前发生,但是你应该保持它与实际页面对象(按钮,数据网格等)无关。我不会在这里使用它。

此外,有&#34;如果不是IsPostBack那么&#34;在页面中,Page_Int()方法毫无意义,因为它只在页面初始化之前被触发一次,然后再也不会被触发。

<强>第二

确定。会话(&#34; SelectedAccountID&#34)。你需要在这里使用Session变量吗?会话变量在整个网站上保持自己,直到用户关闭网站。如果你需要它是一个会话级变量(在网站的其他地方使用,其他页面等),那就这样吧。

让我们谈谈_selectedAccountID。在加载此页面之前,是否可能在网站的其他位置设置了Session(&#34; SelectedAccountID&#34;)?这就是我所假设的,因为Session(&#34; SelectedAccountID&#34;)是一个Session变量。我在这个假设上写下面的代码,并且你想使用Session的值(&#34; SelectedAccountID&#34;)来设置下拉列表的初始值。

从查看您如何使用_selectedAccountID看起来,您最初会从Session(&#34; SelectedAccountID&#34;)中填充它。并且当下拉列表更改时,您希望将_selectedAccountID和Session(&#34; SelectedAccountID&#34;)重置为所选值。它是否正确?我把代码写成了好像。请参阅下面的最佳处理方法。

接下来,您如何使用_truckPermissions不太清楚。但看起来你只需要另一个ViewState变量。见下文。

另外,我喜欢按照调用的顺序在页面上订购所有内容。所以,让我们来看看......

Imports System.Data.SqlClient
Imports Telerik.Web.UI

Public Class AccountSettings2
Inherits Page

' This is your ViewState variable for selectedAccountID.  You will set it first in Page_Load() inside If Not IsPostback.  It can be access from any method in the code behind, and will persist across postbacks.
Public Property _selectedAccountID() As String
    Get
        Return ViewState("selectedAccountID").ToString()
    End Get
    Set(ByVal value As String)
        ViewState("selectedAccountID") = value
    End Set
End Property

' This is your ViewState variable for truckPermissions.  It can be access from any method in the code behind, and will persist across postbacks.
Public Property _truckPermissions() As List(Of PermissionData2)
    Get
        Return ViewState("truckPermissions")
    End Get
    Set(ByVal value As List(Of PermissionData2))
        ViewState("truckPermissions") = value
    End Set
End Property

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        ' Anything done inside this If Then will happen ONLY when the page loads for the first time. Never again.

        ' Set your initial value for the ViewState variable _selectedAccountID here  
        If Not IsNothing(Session("SelectedAccountID")) Then
            _selectedAccountID = Session("SelectedAccountID")
        Else
            _selectedAccountID = 0 ' Do you need to give this a default value is Session("SelectedAccountID") is empty?  If so, this will work.
        End If

        ' Create your DataTable, but to keep things easy to read inside Page_Load(), move the work to another method
        Dim dtAccounts As DataTable = BuildDataTable()

        ' Do this here, just to be clean
        rcbAccounts.DataValueField = "AccountID"
        rcbAccounts.DataTextField = "Name"
        rcbAccounts.DataSource = dtAccounts
        rcbAccounts.DataBind()

        ' Set the initial value on your dropdown.
        If _selectedAccountID > 0 Then
            rcbAccounts.SelectedValue = _selectedAccountID
            ' SelectAccount(_selectedAccountID) ' I don't think we want to do this here
            CreateTruckPermissionsData(_selectedAccountID) ' But I think we DO want to do this
        End If

    End If

End Sub

Private Function BuildDataTable() As DataTable

    Dim dtAccounts As New DataTable("Accounts")

    dtAccounts.Columns.Add(BuildDataColumn("System.Int32", "AccountID"))
    dtAccounts.Columns.Add(BuildDataColumn("System.String", "Name"))

    Dim row As DataRow
    Dim i As Integer
    For i = 0 To 4
        row = dtAccounts.NewRow()
        row("AccountID") = i
        row("Name") = "Account " & i
        dtAccounts.Rows.Add(row)
    Next

    Return dtAccounts

End Function

Private Function BuildDataColumn(DataType As String, ColumnName As String) As DataColumn
    Dim newCol As New DataColumn()
    newCol.DataType = System.Type.GetType(DataType)
    newCol.ColumnName = ColumnName
    Return newCol
End Function

#Region "Events"

Protected Sub btnSavePermissions_Click(sender As Object, e As EventArgs)

    If _selectedAccountID > 0 Then

        Dim permissionUpdates As List(Of PermissionUpdate) = New List(Of PermissionUpdate)()

        For Each r As TableRow In tblTruckPermissions.Rows
            For Each c As Control In r.Cells(1).Controls
                If c.ID.Contains("ddlTruckPermission") Then
                    Dim ddl As RadDropDownList = DirectCast(c, RadDropDownList)
                    permissionUpdates.Add(New PermissionUpdate(Integer.Parse(ddl.ID.LastIndexOf("ddlTruckPermission")), False, ddl.SelectedValue))
                End If
            Next
        Next

        ' Code to save permissions to database

    End If

End Sub

Protected Sub rcbAccounts_SelectedIndexChanged(sender As Object, e As RadComboBoxSelectedIndexChangedEventArgs)
    Dim newIndex As Integer
    If (Integer.TryParse(e.Value, newIndex)) Then
        SelectAccount(newIndex)
    End If
End Sub

#End Region



#Region "UI Updates"

Private Sub SelectAccount(accountID As Integer)
    _selectedAccountID = accountID
    Session("SelectedAccountID") = accountID
    CreateTruckPermissionsData(accountID)
End Sub

Private Sub CreateTruckPermissionsData(accessTypeID As Integer)
    ' this code can be cleaned up too, like I did for building the other table.  I just didn't have time to get to it.
    tblTruckPermissions.Rows.Clear()

    _truckPermissions.Add(New PermissionData2(1, "Permission 1", "Permission 1", accessTypeID))
    _truckPermissions.Add(New PermissionData2(2, "Permission 2", "Permission 2", accessTypeID))
    _truckPermissions.Add(New PermissionData2(3, "Permission 3", "Permission 3", accessTypeID))
    _truckPermissions.Add(New PermissionData2(4, "Permission 4", "Permission 4", accessTypeID))
    ViewState("_truckPermissions") = _truckPermissions

    Dim dtAccessTypes As New DataTable("AccessTypes")
    Dim col1 As DataColumn = New DataColumn()
    col1.DataType = System.Type.GetType("System.Int32")
    col1.ColumnName = "AccessTypeID"
    dtAccessTypes.Columns.Add(col1)
    Dim col2 As DataColumn = New DataColumn()
    col2.DataType = System.Type.GetType("System.String")
    col2.ColumnName = "Description"
    dtAccessTypes.Columns.Add(col2)

    Dim row1 As DataRow
    Dim row2 As DataRow
    Dim row3 As DataRow
    Dim row4 As DataRow
    row1 = dtAccessTypes.NewRow()
    row1("AccessTypeID") = 1
    row1("Description") = "Type 1"
    dtAccessTypes.Rows.Add(row1)

    row2 = dtAccessTypes.NewRow()
    row2("AccessTypeID") = 2
    row2("Description") = "Type 2"
    dtAccessTypes.Rows.Add(row2)
    row3 = dtAccessTypes.NewRow()
    row3("AccessTypeID") = 3
    row3("Description") = "Type 3"
    dtAccessTypes.Rows.Add(row3)
    row4 = dtAccessTypes.NewRow()
    row4("AccessTypeID") = 4
    row4("Description") = "Type 4"
    dtAccessTypes.Rows.Add(row4)

    For Each pd As PermissionData2 In _truckPermissions
        Dim tr As New TableRow()
        Dim td As New TableCell()
        Dim td2 As New TableCell()
        Dim l As New Label()
        Dim ddl As New RadDropDownList()

        l.Text = pd.Name
        ddl.ID = "ddlTruckPermission" + pd.ID.ToString()
        ddl.DataTextField = "Description"
        ddl.DataValueField = "AccessTypeID"
        ddl.DataSource = dtAccessTypes
        ddl.DataBind()
        ddl.SelectedValue = pd.HasAccess

        td.Controls.Add(l)
        td2.Controls.Add(ddl)
        tr.Cells.Add(td)
        tr.Cells.Add(td2)

        tblTruckPermissions.Rows.Add(tr)
    Next

End Sub


#End Region

答案 1 :(得分:0)

我找到了一种更好的方法来处理我的场景。我使用转发器控件来处理几乎所有代码,而不是尝试手动执行。我使用http://weblogs.asp.net/infinitiesloop/TRULY-Understanding-Dynamic-Controls-_2800_Part-4_2900_来帮助指导我。感谢Casey Crookston在此方面提供了很多帮助。

<asp:Repeater ID="rptTruckPermissions" runat="server" EnableViewState="true" OnItemDataBound="rptTruckPermissions_ItemDataBound">
                            <HeaderTemplate>
                                <table>
                            </HeaderTemplate>
                            <ItemTemplate>
                                <tr>
                                    <td><%# DataBinder.Eval(Container.DataItem, "PermissionName") %></td>
                                    <td><telerik:RadDropDownList runat="server" ID="ddlTruckPermissionAccessTypes" /></td>
                                </tr>
                            </ItemTemplate>
                            <FooterTemplate>
                                </table>
                            </FooterTemplate>
                        </asp:Repeater>

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not IsPostBack Then

            If Not IsNothing(_accountDetails) Then
                SelectAccount(_accountDetails.AccountID)
            End If

        End If

    End Sub

Private Sub SelectAccount(accountID As Integer)

        _selectedAccountID = accountID
        Session("SelectedAccountID") = accountID

        BindTruckPermissions()


    End Sub

    Private Sub BindTruckPermissions()

        rptTruckPermissions.DataSource = GetPermissionData(_selectedAccountID, PermissionCategory.Truck)
        rptTruckPermissions.DataBind()

    End Sub

Protected Sub rptTruckPermissions_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)

        If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then

            Dim r As DataRowView = CType(e.Item.DataItem, DataRowView)
            Dim ddl As RadDropDownList = CType(e.Item.FindControl("ddlTruckPermissionAccessTypes"), RadDropDownList)
            Select Case r("PermissionTypeID")

                Case PermissionType.LegacyBasic
                    ddl.DataSource = GetLegacyWebAccessTypes(PermissionType.LegacyBasic)
                Case PermissionType.LegacyPublisher
                    ddl.DataSource = GetLegacyWebAccessTypes(PermissionType.LegacyPublisher)
            End Select

            'ddl.ID = "ddlTruckPermission" + pd.ID.ToString()
            ddl.DataTextField = "Description"
            ddl.DataValueField = "AccessTypeID"
            ddl.DataBind()

            If IsDBNull(r("AccessTypeID")) Then
                ddl.SelectedValue = LegacyWebAccessType.NoAccess
            Else
                ddl.SelectedValue = r("AccessTypeID")
            End If

        End If

    End Sub