我有一个在后面的代码中创建的表。在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>
答案 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