CheckBox 在取消选中后恢复为选中状态
CheckBox reverts to checked after being unchecked
我有一个包含嵌套 GridView 的 ASP.Net 网页。在嵌套的 GridView 中是一个带有 CheckBox 的模板字段。此 AutoPostBack 设置为 True 以触发 CheckedChanged 事件。当您单击 CheckBox 将其从选中状态更改为未选中状态时,它会恢复为选中状态。
我需要知道什么 CheckBox 未选中,以便我可以将其从包含当前选定项的 DataTable 中删除。
下载整个项目.zip here
此问题的代码在 Views 文件夹的 CreateSchedule.aspx 文件中。
这是 GridView 的 ASP.Net:
<asp:GridView ID="GridView1" runat="server" AllowPaging="False" AutoGenerateColumns="False" Height="25px" Width="250px" CellPadding="4" ForeColor="#333333" GridLines="None">
<AlternatingRowStyle BackColor="White" />
<RowStyle Height="25px" />
<Columns>
<asp:BoundField DataField="CourseName" HeaderText="Course" SortExpression="CourseName" >
<HeaderStyle Width="80px" height="25px"/>
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<img alt = "" style="cursor: pointer" src="images/plus.png" />
<asp:Panel ID="pnlSections" runat="server" Style="display: none">
<!-- Table inside the table -->
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" DataKeyNames="CRN" ForeColor="#333333" GridLines="None" ShowHeader="False">
<Columns>
<asp:TemplateField>
<ItemStyle Width="25px" HorizontalAlign="left"/>
<ItemTemplate>
<asp:CheckBox ID="chkCtrl" runat="server" OnCheckedChanged="CheckedClicked" AutoPostBack="True" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Days" SortExpression="Days" >
<ItemStyle Width="60px" />
</asp:BoundField>
<asp:BoundField DataField="Time" SortExpression="Time" >
<ItemStyle Width="90px" />
</asp:BoundField>
</Columns>
<RowStyle VerticalAlign="Middle" BackColor="white" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString2 %>" ProviderName="<%$ ConnectionStrings:ConnectionString2.ProviderName %>" SelectCommand="SELECT [CRN], [Days], [Time] FROM [ScheduleOfClasses] WHERE ([Course] = ?)">
<SelectParameters>
<asp:Parameter Name=" Course" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EditRowStyle BackColor="#2461BF" />
<FooterStyle BackColor="#04488A" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#04488A" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#04488A" ForeColor="White" HorizontalAlign="Center" />
<RowStyle VerticalAlign="Middle" BackColor="white" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
这是我的 Page_Load
子页面。本质上,如果它不是 post 返回,它会创建一个新的 DataTable/Xml 文件并覆盖。如果它是 post 返回(即单击 CheckBox 时),它应该检查不再检查的任何行并将其从 DataTable 中删除。我无法测试它的逻辑,因为它会被重新检查。
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Me.SetDataSource("ACCT")
' Create a new DataTable.
Dim table As DataTable = New DataTable("CourseSelection")
' Declare variables for DataColumn and DataRow objects.
Dim column As DataColumn
' Create new DataColumn, set DataType, ColumnName
' and add to DataTable.
column = New DataColumn()
column.DataType = System.Type.GetType("System.Int32")
column.ColumnName = "crn"
column.AutoIncrement = False
column.ReadOnly = True
column.Unique = True '- same CRN does not conflict
' Add the Column to the DataColumnCollection.
table.Columns.Add(column)
' Create course column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "course"
column.AutoIncrement = False
column.ReadOnly = False
column.Unique = False
' Add the column to the table.
table.Columns.Add(column)
' Create instructor column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "instructor"
column.AutoIncrement = False
column.ReadOnly = False
column.Unique = False
' Add the column to the table.
table.Columns.Add(column)
' Create course time column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "coursetime"
column.AutoIncrement = False
column.ReadOnly = False
column.Unique = False
' Add the column to the table.
table.Columns.Add(column)
' Create course day column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "courseday"
column.AutoIncrement = False
column.ReadOnly = False
column.Unique = False
' Add the column to the table.
table.Columns.Add(column)
' Make the ID column the primary key column, taken out to avoid conflict of unique key
Dim PrimaryKeyColumns(0) As DataColumn
PrimaryKeyColumns(0) = table.Columns("crn")
table.PrimaryKey = PrimaryKeyColumns
Dim dsXML As New DataSet("CourseSelections")
dsXML.Merge(table)
dsXML.WriteXml("c:\temp\dt.xml", XmlWriteMode.WriteSchema)
' Else statement to be worked on
Else
Dim nestedCounter As Integer = 0
Dim rowCounter As Integer = 0
Dim subject As String
Dim ds As New DataSet
' XML File Directory
ds.ReadXml("c:\temp\dt.xml")
Dim table As New DataTable
table = ds.Tables("CourseSelection")
Dim CheckedCRNs As New ArrayList
subject = Left(GridView1.Rows(1).Cells(0).ToString(), 4)
For Each row As GridViewRow In GridView1.Rows
Dim NestedGridView As GridView = GridView1.Rows(rowCounter).FindControl("GridView2")
nestedCounter = 0
For Each r As GridViewRow In NestedGridView.Rows
If r.RowType = DataControlRowType.DataRow Then
Dim chkRow As CheckBox = TryCast(r.Cells(0).FindControl("chkCtrl"), CheckBox)
If chkRow.Checked Then
CheckedCRNs.Add(NestedGridView.DataKeys(nestedCounter).Value.ToString())
End If
End If
nestedCounter = nestedCounter + 1
Next
rowCounter = rowCounter + 1
Next
Dim foundRows() As DataRow
If Not table.Select("course like '" & subject & "*'").Length = CheckedCRNs.Count Then
foundRows = table.Select("course like '" & subject & "*'")
For i = 0 To foundRows.GetUpperBound(0)
If Not CheckedCRNs.Contains(foundRows(i)(0)) Then
table.Rows(i).Delete()
End If
Next i
Dim dsXML As New DataSet("CourseSelections")
dsXML.Merge(table)
dsXML.WriteXml("c:\temp\dt.xml", XmlWriteMode.WriteSchema)
End If
End If
End Sub
CheckedClicked 子:
Protected Sub CheckedClicked(sender As Object, e As EventArgs)
' Variables to be pulled from Database
Dim Course As String = ""
Dim CourseTime As String = ""
Dim CourseDay As String = ""
Dim Instructor As String = ""
' Variables used for position of columns and rows
Dim crn As Integer
Dim nestedCounter As Integer = 0
Dim rowCounter As Integer = 0
Dim ds As New DataSet
' Color variables
Dim colorOfClass As String = ""
colorOfClass = getColorOfClasses(colorPosition)
' XML File Directory
ds.ReadXml("c:\temp\dt.xml")
Dim table As New DataTable
table = ds.Tables("CourseSelection")
For Each row As GridViewRow In GridView1.Rows
Dim NestedGridView As GridView = GridView1.Rows(rowCounter).FindControl("GridView2")
nestedCounter = 0
For Each r As GridViewRow In NestedGridView.Rows
If r.RowType = DataControlRowType.DataRow Then
Dim chkRow As CheckBox = TryCast(r.Cells(0).FindControl("chkCtrl"), CheckBox)
If chkRow.Checked Then
If table.Select("CRN='" & NestedGridView.DataKeys(nestedCounter).Value.ToString() & "'").Length = 0 Then
crn = NestedGridView.DataKeys(nestedCounter).Value.ToString()
End If
End If
End If
nestedCounter = nestedCounter + 1
Next
rowCounter = rowCounter + 1
Next
Dim con As New OleDbConnection
Try
Using con
con.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings("ConnectionString2").ConnectionString
con.Open()
Using cmd = New OleDbCommand
cmd.Connection = con
cmd.CommandText = "SELECT Course, Time, Days, Instructor FROM ScheduleOfClasses WHERE CRN= " & crn
Using oRDR As OleDbDataReader = cmd.ExecuteReader
'Gets columns for each value
While (oRDR.Read)
Course = oRDR.GetValue(0)
CourseTime = oRDR.GetValue(1)
CourseDay = oRDR.GetValue(2)
Instructor = oRDR.GetValue(3)
End While
End Using
con.Close()
End Using
End Using
Catch ex As Exception
Throw New Exception(ex.Message)
Finally
con.Close()
End Try
Dim dRow As DataRow
dRow = table.NewRow()
dRow("crn") = CInt(crn)
dRow("course") = Course
dRow("instructor") = Instructor
dRow("coursetime") = CourseTime
dRow("CourseDay") = CourseDay
table.Rows.Add(dRow)
arrayOfCRNs.Add(crn)
Dim NewDs As New DataSet("CourseSelections")
NewDs.Merge(table)
NewDs.WriteXml("c:\temp\dt.xml", XmlWriteMode.WriteSchema)
Dim cDay As String = "" 'Current day when looping through class days
Dim cCol As Integer = 0 'Current column that is set based on the cDay
Dim StartRow As Integer 'Row in the table that the class starts
Dim ClassLength As Integer = 0 'Number of rows in the table to be colored in based on the length of the class
Dim StartHours As String = Mid(CourseTime, 3, 2) 'The hour of the day that the class starts
Select Case StartHours
Case "00" 'When the class starts on the hour, StartRow is calculated to the correlated hour
StartRow = (CInt(Left(CourseTime, 2)) - 8) * 4
Case "30" 'When the class starts at the bottom of the hour, StartRow is calculated to the correlated _
'hour plus 2 to account for thirty minutes
StartRow = (CInt(Left(CourseTime, 2)) - 8) * 4 + 2
End Select
'Class length of a class is the total minutes divided by 15 minutes per hour, rounded down
ClassLength = Math.Floor((CInt(Mid(CourseTime, 6, 4)) - CInt(Left(CourseTime, 4))) / 15)
'Conversion from Class Length = 7, to 5 cells
ClassLength = ClassLength - ((CInt(Mid(CourseTime, 6, 2)) - CInt(Left(CourseTime, 2))) * 2)
'Number of course days as size of String, checking String for each day Monday-Friday
For n As Integer = 1 To CourseDay.Length
cDay = Mid(CourseDay, n, 1) 'Set cDay to the nth day
Select Case cDay
Case "M"
cCol = 0
Case "T"
cCol = 1
Case "W"
cCol = 2
Case "R"
cCol = 3
Case "F"
cCol = 4
End Select
Dim fillRowCounter As Integer = 1
' Populate the table with the correct data
For cRow As Integer = StartRow To StartRow + ClassLength - 1
'If the current row is divisible by 4 then add one; this is due to the row span of the first column
If cRow Mod 4 = 0 Then cCol = cCol + 1
schedule.Rows(cRow).Cells(cCol).BgColor = colorOfClass
If fillRowCounter = 1 Then schedule.Rows(cRow).Cells(cCol).InnerText = CInt(crn)
If fillRowCounter = 2 Then schedule.Rows(cRow).Cells(cCol).InnerText = Course
If fillRowCounter = 3 Then schedule.Rows(cRow).Cells(cCol).InnerText = Instructor
If fillRowCounter > 3 Then schedule.Rows(cRow).Cells(cCol).InnerText = ""
If cRow Mod 4 = 0 Then cCol = cCol - 1
fillRowCounter = fillRowCounter + 1
Next cRow
Next n
更新
我将 GridView 更改为 Page_Load
上的数据绑定,而不是使用 SqlDataSource。但是我仍然遇到与以前相同的问题。下面是我最初绑定 GridView 时调用的子程序。
Protected Sub SetDataSource(Subject As String)
Dim connectionString As String = ConfigurationManager.ConnectionStrings("ConnectionString2").ConnectionString
Dim queryString As String = "SELECT [CourseName] FROM [Courses] WHERE ([SubjectID] = '" & Subject & "')"
Dim DataKeyArray As String() = {"CourseName"}
Dim ds As New DataSet()
Try
' Connect to the database and run the query.
Dim connection As New OleDbConnection(connectionString)
Dim adapter As New OleDbDataAdapter(queryString, connection)
' Fill the DataSet.
adapter.Fill(ds)
Catch ex As Exception
' The connection failed. Display an error message.
'Message.Text = "Unable to connect to the database."
End Try
' Run the query and bind the resulting DataSet
' to the GridView control.
If (ds.Tables.Count > 0) Then
GridView1.DataSource = ds
GridView1.DataKeyNames = DataKeyArray
GridView1.DataBind()
ds.Dispose()
ds.Clear()
Else
'Message.Text = "Unable to connect to the database."
End If
Dim rowCounter As Integer = 0
Dim DataKeyArray2 As String() = {"CRN"}
For Each row As GridViewRow In GridView1.Rows
Dim NestedGridView As GridView = GridView1.Rows(rowCounter).FindControl("GridView2")
Dim gView = GridView1
queryString = "SELECT [CRN], [Days], [Time] FROM [ScheduleOfClasses] WHERE ([Course] = '" & GridView1.DataKeys(rowCounter).Value & "')"
Try
' Connect to the database and run the query.
Dim connection As New OleDbConnection(connectionString)
Dim adapter As New OleDbDataAdapter(queryString, connection)
' Fill the DataSet.
adapter.Fill(ds)
Catch ex As Exception
' The connection failed. Display an error message.
'Message.Text = "Unable to connect to the database."
End Try
' Run the query and bind the resulting DataSet
' to the GridView control.
If (ds.Tables.Count > 0) Then
NestedGridView.DataSource = ds
NestedGridView.DataKeyNames = DataKeyArray2
NestedGridView.DataBind()
ds.Dispose()
ds.Clear()
Else
'Message.Text = "Unable to connect to the database."
End If
rowCounter = rowCounter + 1
Next
End Sub
更新 2
在取消选中复选框后调试 Page_Load
事件时,网页上的复选框似乎未选中,但 chkRow.Checked
的值为 true,即使该复选框在网页上显示为未选中. (chkRow 是未选中的复选框)
更新 3
我有点突破了。我发现复选框的问题在于嵌套的 gridview 位于使用 JavaScript 折叠和展开的面板内。本质上它是 ASP.Net 中的一个错误,当控件在 Page_Load
上禁用然后稍后启用时。我想通了,因为我的 GridView2
和 chkCtrl
无法在 VB 中引用,因此 GridView2
未在 Page_Load
上初始化。我也是通过阅读 this 弄明白的。该解决方案提到创建一个隐藏字段并将其设置为另一个复选框的值,但我不确定如何根据我的情况执行此操作。
当我注释掉面板时,复选框按预期取消选中并触发了 ClickedChanged。但是,我需要可折叠面板,因为它包含大量数据,所有内容都已展开。我在想,如果我最初可以加载所有 GridView,然后在 Page_Load
上折叠它们,但我也不知道该怎么做。
这是我的 GridView 的最新 aspx,这次包括我的面板的代码:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<%'Using plus and minus images to show drop down of classes'%>
<script type="text/javascript">
$("[src*=plus]").live("click", function () {
$(this).closest("tr").after("<tr><td></td><td colspan = '999'>" + $(this).next().html() + "</td></tr>")
$(this).attr("src", "images/minus.png");
});
$("[src*=minus]").live("click", function () {
$(this).attr("src", "images/plus.png");
$(this).closest("tr").next().remove();
});
</script>
<%'Grid View Table'%>
<asp:GridView ID="GridView1" runat="server" AllowPaging="False" AutoGenerateColumns="False" Height="25px" Width="250px" CellPadding="4" ForeColor="#333333" GridLines="None">
<AlternatingRowStyle BackColor="White" />
<RowStyle Height="25px" />
<Columns>
<asp:BoundField DataField="CourseName" HeaderText="Course" SortExpression="CourseName" >
<HeaderStyle Width="80px" height="25px"/>
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<img alt = "" style="cursor: pointer" src="images/plus.png" />
<asp:Panel ID="pnlSections" runat="server" Style="display: none">
<!-- Table inside the table -->
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" DataKeyNames="CRN" ForeColor="#333333" GridLines="None" ShowHeader="False">
<Columns>
<asp:TemplateField>
<ItemStyle Width="25px" HorizontalAlign="left"/>
<ItemTemplate>
<asp:CheckBox ID="chkCtrl" runat="server" OnCheckedChanged="CheckedClicked" AutoPostBack="True" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Days" SortExpression="Days" >
<ItemStyle Width="60px" />
</asp:BoundField>
<asp:BoundField DataField="Time" SortExpression="Time" >
<ItemStyle Width="90px" />
</asp:BoundField>
</Columns>
<RowStyle VerticalAlign="Middle" BackColor="white" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString2 %>" ProviderName="<%$ ConnectionStrings:ConnectionString2.ProviderName %>" SelectCommand="SELECT [CRN], [Days], [Time] FROM [ScheduleOfClasses] WHERE ([Course] = ?)">
<SelectParameters>
<asp:Parameter Name=" Course" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EditRowStyle BackColor="#2461BF" />
<FooterStyle BackColor="#04488A" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#04488A" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#04488A" ForeColor="White" HorizontalAlign="Center" />
<RowStyle VerticalAlign="Middle" BackColor="white" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
这听起来很像您忘记在绑定 gridview 数据的 Page_Load
事件中检查页面是否回发。因此,每次取消选中复选框时,您都会无意中重新绑定 gridview,这就是它恢复到原始状态(已选中)的原因。
If Not IsPostBack Then
//bind gridview
Else
//other stuff
End
更新
我认为当 gridviews 与 SqlDataSource 一起使用时,这是一个 Postback
问题。您可能需要查看以下资源,甚至可能需要更改数据绑定方法:
http://www.codeproject.com/Articles/20520/Workaround-when-SQLDataSource-doesn-t-Maintain-Sel
希望对您有所帮助!
使用 OnChange 而不是 OnCheckedChanged。
ASPX
<asp:CheckBox ID="chkCtrl" runat="server" OnChange="CheckedClicked" AutoPostBack="True" />
问题是包含复选框的 GridView2 在 Page_Load
上被禁用。它最初是禁用的,因为 gridview 嵌套在可折叠面板内。我卸下了面板,一切正常。
我可能 post 提出一个不同的问题来询问有关使可折叠面板工作的问题。
折叠面板无法使用 javascript 的解决方案。在内部 Gridview 周围使用一个 ImageButton 和一个 Panel。这使 ViewState 与实际发生的事情保持同步。
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="ExpandButton" runat="server" OnClick="ExpandButton_Click" ImageUrl="~/Images/plus.png" />
</ItemTemplate>
</asp:TemplateField>
将面板放在外部 GridView 的最后一列内,在任何项目之后。在我的例子中,这是 Cell[5],在其他一些按钮之后。请注意,此面板关闭外部 Gridview 的单元格和行并插入一个新行并为内部 GridView 启动一个新单元格,跨越所有列。
<asp:TemplateField HeaderText="Key Options" HeaderStyle-CssClass="text-center bg-info">
<ItemTemplate>
<asp:Button ID="AssignButton" runat="server" CssClass="btn btn-primary btn-xs" Text="Assign Keys" Enabled="false" />
<asp:Button ID="RecallButton" runat="server" CssClass="btn btn-primary btn-xs" Text="Recall Key" Enabled="false" />
<asp:Panel ID="KeysPanel" runat="server" Visible="false">
</td></tr><tr>
<td colspan="999">
<asp:GridView ID="KeysGV" runat="server" AutoGenerateColumns="false" CssClass="table table-striped"
EmptyDataText="No assignments have been made.">
<Columns>
.
.
.
</Columns>
</asp:GridView>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
ExpandButton 回发如下所示:
protected void ExpandButton_Click(object sender, EventArgs e)
{
GridViewRow myRow = ((Control)sender).NamingContainer as GridViewRow;
ImageButton expandBtn = sender as ImageButton;
if (expandBtn.ImageUrl == "~/Images/plus.png")
{
expandBtn.ImageUrl = "~/Images/minus.png";
Panel pnl = myRow.Cells[5].Controls[0].FindControl("KeysPanel") as Panel;
pnl.Visible = true;
}
else
{
expandBtn.ImageUrl = "~/Images/plus.png";
Panel pnl = myRow.Cells[5].Controls[0].FindControl("KeysPanel") as Panel;
pnl.Visible = false;
}
}
我有一个包含嵌套 GridView 的 ASP.Net 网页。在嵌套的 GridView 中是一个带有 CheckBox 的模板字段。此 AutoPostBack 设置为 True 以触发 CheckedChanged 事件。当您单击 CheckBox 将其从选中状态更改为未选中状态时,它会恢复为选中状态。
我需要知道什么 CheckBox 未选中,以便我可以将其从包含当前选定项的 DataTable 中删除。
下载整个项目.zip here
此问题的代码在 Views 文件夹的 CreateSchedule.aspx 文件中。
这是 GridView 的 ASP.Net:
<asp:GridView ID="GridView1" runat="server" AllowPaging="False" AutoGenerateColumns="False" Height="25px" Width="250px" CellPadding="4" ForeColor="#333333" GridLines="None">
<AlternatingRowStyle BackColor="White" />
<RowStyle Height="25px" />
<Columns>
<asp:BoundField DataField="CourseName" HeaderText="Course" SortExpression="CourseName" >
<HeaderStyle Width="80px" height="25px"/>
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<img alt = "" style="cursor: pointer" src="images/plus.png" />
<asp:Panel ID="pnlSections" runat="server" Style="display: none">
<!-- Table inside the table -->
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" DataKeyNames="CRN" ForeColor="#333333" GridLines="None" ShowHeader="False">
<Columns>
<asp:TemplateField>
<ItemStyle Width="25px" HorizontalAlign="left"/>
<ItemTemplate>
<asp:CheckBox ID="chkCtrl" runat="server" OnCheckedChanged="CheckedClicked" AutoPostBack="True" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Days" SortExpression="Days" >
<ItemStyle Width="60px" />
</asp:BoundField>
<asp:BoundField DataField="Time" SortExpression="Time" >
<ItemStyle Width="90px" />
</asp:BoundField>
</Columns>
<RowStyle VerticalAlign="Middle" BackColor="white" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString2 %>" ProviderName="<%$ ConnectionStrings:ConnectionString2.ProviderName %>" SelectCommand="SELECT [CRN], [Days], [Time] FROM [ScheduleOfClasses] WHERE ([Course] = ?)">
<SelectParameters>
<asp:Parameter Name=" Course" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EditRowStyle BackColor="#2461BF" />
<FooterStyle BackColor="#04488A" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#04488A" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#04488A" ForeColor="White" HorizontalAlign="Center" />
<RowStyle VerticalAlign="Middle" BackColor="white" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
这是我的 Page_Load
子页面。本质上,如果它不是 post 返回,它会创建一个新的 DataTable/Xml 文件并覆盖。如果它是 post 返回(即单击 CheckBox 时),它应该检查不再检查的任何行并将其从 DataTable 中删除。我无法测试它的逻辑,因为它会被重新检查。
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Me.SetDataSource("ACCT")
' Create a new DataTable.
Dim table As DataTable = New DataTable("CourseSelection")
' Declare variables for DataColumn and DataRow objects.
Dim column As DataColumn
' Create new DataColumn, set DataType, ColumnName
' and add to DataTable.
column = New DataColumn()
column.DataType = System.Type.GetType("System.Int32")
column.ColumnName = "crn"
column.AutoIncrement = False
column.ReadOnly = True
column.Unique = True '- same CRN does not conflict
' Add the Column to the DataColumnCollection.
table.Columns.Add(column)
' Create course column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "course"
column.AutoIncrement = False
column.ReadOnly = False
column.Unique = False
' Add the column to the table.
table.Columns.Add(column)
' Create instructor column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "instructor"
column.AutoIncrement = False
column.ReadOnly = False
column.Unique = False
' Add the column to the table.
table.Columns.Add(column)
' Create course time column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "coursetime"
column.AutoIncrement = False
column.ReadOnly = False
column.Unique = False
' Add the column to the table.
table.Columns.Add(column)
' Create course day column.
column = New DataColumn()
column.DataType = System.Type.GetType("System.String")
column.ColumnName = "courseday"
column.AutoIncrement = False
column.ReadOnly = False
column.Unique = False
' Add the column to the table.
table.Columns.Add(column)
' Make the ID column the primary key column, taken out to avoid conflict of unique key
Dim PrimaryKeyColumns(0) As DataColumn
PrimaryKeyColumns(0) = table.Columns("crn")
table.PrimaryKey = PrimaryKeyColumns
Dim dsXML As New DataSet("CourseSelections")
dsXML.Merge(table)
dsXML.WriteXml("c:\temp\dt.xml", XmlWriteMode.WriteSchema)
' Else statement to be worked on
Else
Dim nestedCounter As Integer = 0
Dim rowCounter As Integer = 0
Dim subject As String
Dim ds As New DataSet
' XML File Directory
ds.ReadXml("c:\temp\dt.xml")
Dim table As New DataTable
table = ds.Tables("CourseSelection")
Dim CheckedCRNs As New ArrayList
subject = Left(GridView1.Rows(1).Cells(0).ToString(), 4)
For Each row As GridViewRow In GridView1.Rows
Dim NestedGridView As GridView = GridView1.Rows(rowCounter).FindControl("GridView2")
nestedCounter = 0
For Each r As GridViewRow In NestedGridView.Rows
If r.RowType = DataControlRowType.DataRow Then
Dim chkRow As CheckBox = TryCast(r.Cells(0).FindControl("chkCtrl"), CheckBox)
If chkRow.Checked Then
CheckedCRNs.Add(NestedGridView.DataKeys(nestedCounter).Value.ToString())
End If
End If
nestedCounter = nestedCounter + 1
Next
rowCounter = rowCounter + 1
Next
Dim foundRows() As DataRow
If Not table.Select("course like '" & subject & "*'").Length = CheckedCRNs.Count Then
foundRows = table.Select("course like '" & subject & "*'")
For i = 0 To foundRows.GetUpperBound(0)
If Not CheckedCRNs.Contains(foundRows(i)(0)) Then
table.Rows(i).Delete()
End If
Next i
Dim dsXML As New DataSet("CourseSelections")
dsXML.Merge(table)
dsXML.WriteXml("c:\temp\dt.xml", XmlWriteMode.WriteSchema)
End If
End If
End Sub
CheckedClicked 子:
Protected Sub CheckedClicked(sender As Object, e As EventArgs)
' Variables to be pulled from Database
Dim Course As String = ""
Dim CourseTime As String = ""
Dim CourseDay As String = ""
Dim Instructor As String = ""
' Variables used for position of columns and rows
Dim crn As Integer
Dim nestedCounter As Integer = 0
Dim rowCounter As Integer = 0
Dim ds As New DataSet
' Color variables
Dim colorOfClass As String = ""
colorOfClass = getColorOfClasses(colorPosition)
' XML File Directory
ds.ReadXml("c:\temp\dt.xml")
Dim table As New DataTable
table = ds.Tables("CourseSelection")
For Each row As GridViewRow In GridView1.Rows
Dim NestedGridView As GridView = GridView1.Rows(rowCounter).FindControl("GridView2")
nestedCounter = 0
For Each r As GridViewRow In NestedGridView.Rows
If r.RowType = DataControlRowType.DataRow Then
Dim chkRow As CheckBox = TryCast(r.Cells(0).FindControl("chkCtrl"), CheckBox)
If chkRow.Checked Then
If table.Select("CRN='" & NestedGridView.DataKeys(nestedCounter).Value.ToString() & "'").Length = 0 Then
crn = NestedGridView.DataKeys(nestedCounter).Value.ToString()
End If
End If
End If
nestedCounter = nestedCounter + 1
Next
rowCounter = rowCounter + 1
Next
Dim con As New OleDbConnection
Try
Using con
con.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings("ConnectionString2").ConnectionString
con.Open()
Using cmd = New OleDbCommand
cmd.Connection = con
cmd.CommandText = "SELECT Course, Time, Days, Instructor FROM ScheduleOfClasses WHERE CRN= " & crn
Using oRDR As OleDbDataReader = cmd.ExecuteReader
'Gets columns for each value
While (oRDR.Read)
Course = oRDR.GetValue(0)
CourseTime = oRDR.GetValue(1)
CourseDay = oRDR.GetValue(2)
Instructor = oRDR.GetValue(3)
End While
End Using
con.Close()
End Using
End Using
Catch ex As Exception
Throw New Exception(ex.Message)
Finally
con.Close()
End Try
Dim dRow As DataRow
dRow = table.NewRow()
dRow("crn") = CInt(crn)
dRow("course") = Course
dRow("instructor") = Instructor
dRow("coursetime") = CourseTime
dRow("CourseDay") = CourseDay
table.Rows.Add(dRow)
arrayOfCRNs.Add(crn)
Dim NewDs As New DataSet("CourseSelections")
NewDs.Merge(table)
NewDs.WriteXml("c:\temp\dt.xml", XmlWriteMode.WriteSchema)
Dim cDay As String = "" 'Current day when looping through class days
Dim cCol As Integer = 0 'Current column that is set based on the cDay
Dim StartRow As Integer 'Row in the table that the class starts
Dim ClassLength As Integer = 0 'Number of rows in the table to be colored in based on the length of the class
Dim StartHours As String = Mid(CourseTime, 3, 2) 'The hour of the day that the class starts
Select Case StartHours
Case "00" 'When the class starts on the hour, StartRow is calculated to the correlated hour
StartRow = (CInt(Left(CourseTime, 2)) - 8) * 4
Case "30" 'When the class starts at the bottom of the hour, StartRow is calculated to the correlated _
'hour plus 2 to account for thirty minutes
StartRow = (CInt(Left(CourseTime, 2)) - 8) * 4 + 2
End Select
'Class length of a class is the total minutes divided by 15 minutes per hour, rounded down
ClassLength = Math.Floor((CInt(Mid(CourseTime, 6, 4)) - CInt(Left(CourseTime, 4))) / 15)
'Conversion from Class Length = 7, to 5 cells
ClassLength = ClassLength - ((CInt(Mid(CourseTime, 6, 2)) - CInt(Left(CourseTime, 2))) * 2)
'Number of course days as size of String, checking String for each day Monday-Friday
For n As Integer = 1 To CourseDay.Length
cDay = Mid(CourseDay, n, 1) 'Set cDay to the nth day
Select Case cDay
Case "M"
cCol = 0
Case "T"
cCol = 1
Case "W"
cCol = 2
Case "R"
cCol = 3
Case "F"
cCol = 4
End Select
Dim fillRowCounter As Integer = 1
' Populate the table with the correct data
For cRow As Integer = StartRow To StartRow + ClassLength - 1
'If the current row is divisible by 4 then add one; this is due to the row span of the first column
If cRow Mod 4 = 0 Then cCol = cCol + 1
schedule.Rows(cRow).Cells(cCol).BgColor = colorOfClass
If fillRowCounter = 1 Then schedule.Rows(cRow).Cells(cCol).InnerText = CInt(crn)
If fillRowCounter = 2 Then schedule.Rows(cRow).Cells(cCol).InnerText = Course
If fillRowCounter = 3 Then schedule.Rows(cRow).Cells(cCol).InnerText = Instructor
If fillRowCounter > 3 Then schedule.Rows(cRow).Cells(cCol).InnerText = ""
If cRow Mod 4 = 0 Then cCol = cCol - 1
fillRowCounter = fillRowCounter + 1
Next cRow
Next n
更新
我将 GridView 更改为 Page_Load
上的数据绑定,而不是使用 SqlDataSource。但是我仍然遇到与以前相同的问题。下面是我最初绑定 GridView 时调用的子程序。
Protected Sub SetDataSource(Subject As String)
Dim connectionString As String = ConfigurationManager.ConnectionStrings("ConnectionString2").ConnectionString
Dim queryString As String = "SELECT [CourseName] FROM [Courses] WHERE ([SubjectID] = '" & Subject & "')"
Dim DataKeyArray As String() = {"CourseName"}
Dim ds As New DataSet()
Try
' Connect to the database and run the query.
Dim connection As New OleDbConnection(connectionString)
Dim adapter As New OleDbDataAdapter(queryString, connection)
' Fill the DataSet.
adapter.Fill(ds)
Catch ex As Exception
' The connection failed. Display an error message.
'Message.Text = "Unable to connect to the database."
End Try
' Run the query and bind the resulting DataSet
' to the GridView control.
If (ds.Tables.Count > 0) Then
GridView1.DataSource = ds
GridView1.DataKeyNames = DataKeyArray
GridView1.DataBind()
ds.Dispose()
ds.Clear()
Else
'Message.Text = "Unable to connect to the database."
End If
Dim rowCounter As Integer = 0
Dim DataKeyArray2 As String() = {"CRN"}
For Each row As GridViewRow In GridView1.Rows
Dim NestedGridView As GridView = GridView1.Rows(rowCounter).FindControl("GridView2")
Dim gView = GridView1
queryString = "SELECT [CRN], [Days], [Time] FROM [ScheduleOfClasses] WHERE ([Course] = '" & GridView1.DataKeys(rowCounter).Value & "')"
Try
' Connect to the database and run the query.
Dim connection As New OleDbConnection(connectionString)
Dim adapter As New OleDbDataAdapter(queryString, connection)
' Fill the DataSet.
adapter.Fill(ds)
Catch ex As Exception
' The connection failed. Display an error message.
'Message.Text = "Unable to connect to the database."
End Try
' Run the query and bind the resulting DataSet
' to the GridView control.
If (ds.Tables.Count > 0) Then
NestedGridView.DataSource = ds
NestedGridView.DataKeyNames = DataKeyArray2
NestedGridView.DataBind()
ds.Dispose()
ds.Clear()
Else
'Message.Text = "Unable to connect to the database."
End If
rowCounter = rowCounter + 1
Next
End Sub
更新 2
在取消选中复选框后调试 Page_Load
事件时,网页上的复选框似乎未选中,但 chkRow.Checked
的值为 true,即使该复选框在网页上显示为未选中. (chkRow 是未选中的复选框)
更新 3
我有点突破了。我发现复选框的问题在于嵌套的 gridview 位于使用 JavaScript 折叠和展开的面板内。本质上它是 ASP.Net 中的一个错误,当控件在 Page_Load
上禁用然后稍后启用时。我想通了,因为我的 GridView2
和 chkCtrl
无法在 VB 中引用,因此 GridView2
未在 Page_Load
上初始化。我也是通过阅读 this 弄明白的。该解决方案提到创建一个隐藏字段并将其设置为另一个复选框的值,但我不确定如何根据我的情况执行此操作。
当我注释掉面板时,复选框按预期取消选中并触发了 ClickedChanged。但是,我需要可折叠面板,因为它包含大量数据,所有内容都已展开。我在想,如果我最初可以加载所有 GridView,然后在 Page_Load
上折叠它们,但我也不知道该怎么做。
这是我的 GridView 的最新 aspx,这次包括我的面板的代码:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<%'Using plus and minus images to show drop down of classes'%>
<script type="text/javascript">
$("[src*=plus]").live("click", function () {
$(this).closest("tr").after("<tr><td></td><td colspan = '999'>" + $(this).next().html() + "</td></tr>")
$(this).attr("src", "images/minus.png");
});
$("[src*=minus]").live("click", function () {
$(this).attr("src", "images/plus.png");
$(this).closest("tr").next().remove();
});
</script>
<%'Grid View Table'%>
<asp:GridView ID="GridView1" runat="server" AllowPaging="False" AutoGenerateColumns="False" Height="25px" Width="250px" CellPadding="4" ForeColor="#333333" GridLines="None">
<AlternatingRowStyle BackColor="White" />
<RowStyle Height="25px" />
<Columns>
<asp:BoundField DataField="CourseName" HeaderText="Course" SortExpression="CourseName" >
<HeaderStyle Width="80px" height="25px"/>
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<img alt = "" style="cursor: pointer" src="images/plus.png" />
<asp:Panel ID="pnlSections" runat="server" Style="display: none">
<!-- Table inside the table -->
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" DataKeyNames="CRN" ForeColor="#333333" GridLines="None" ShowHeader="False">
<Columns>
<asp:TemplateField>
<ItemStyle Width="25px" HorizontalAlign="left"/>
<ItemTemplate>
<asp:CheckBox ID="chkCtrl" runat="server" OnCheckedChanged="CheckedClicked" AutoPostBack="True" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Days" SortExpression="Days" >
<ItemStyle Width="60px" />
</asp:BoundField>
<asp:BoundField DataField="Time" SortExpression="Time" >
<ItemStyle Width="90px" />
</asp:BoundField>
</Columns>
<RowStyle VerticalAlign="Middle" BackColor="white" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString2 %>" ProviderName="<%$ ConnectionStrings:ConnectionString2.ProviderName %>" SelectCommand="SELECT [CRN], [Days], [Time] FROM [ScheduleOfClasses] WHERE ([Course] = ?)">
<SelectParameters>
<asp:Parameter Name=" Course" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EditRowStyle BackColor="#2461BF" />
<FooterStyle BackColor="#04488A" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#04488A" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#04488A" ForeColor="White" HorizontalAlign="Center" />
<RowStyle VerticalAlign="Middle" BackColor="white" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
这听起来很像您忘记在绑定 gridview 数据的 Page_Load
事件中检查页面是否回发。因此,每次取消选中复选框时,您都会无意中重新绑定 gridview,这就是它恢复到原始状态(已选中)的原因。
If Not IsPostBack Then
//bind gridview
Else
//other stuff
End
更新
我认为当 gridviews 与 SqlDataSource 一起使用时,这是一个 Postback
问题。您可能需要查看以下资源,甚至可能需要更改数据绑定方法:
http://www.codeproject.com/Articles/20520/Workaround-when-SQLDataSource-doesn-t-Maintain-Sel
希望对您有所帮助!
使用 OnChange 而不是 OnCheckedChanged。
ASPX
<asp:CheckBox ID="chkCtrl" runat="server" OnChange="CheckedClicked" AutoPostBack="True" />
问题是包含复选框的 GridView2 在 Page_Load
上被禁用。它最初是禁用的,因为 gridview 嵌套在可折叠面板内。我卸下了面板,一切正常。
我可能 post 提出一个不同的问题来询问有关使可折叠面板工作的问题。
折叠面板无法使用 javascript 的解决方案。在内部 Gridview 周围使用一个 ImageButton 和一个 Panel。这使 ViewState 与实际发生的事情保持同步。
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="ExpandButton" runat="server" OnClick="ExpandButton_Click" ImageUrl="~/Images/plus.png" />
</ItemTemplate>
</asp:TemplateField>
将面板放在外部 GridView 的最后一列内,在任何项目之后。在我的例子中,这是 Cell[5],在其他一些按钮之后。请注意,此面板关闭外部 Gridview 的单元格和行并插入一个新行并为内部 GridView 启动一个新单元格,跨越所有列。
<asp:TemplateField HeaderText="Key Options" HeaderStyle-CssClass="text-center bg-info">
<ItemTemplate>
<asp:Button ID="AssignButton" runat="server" CssClass="btn btn-primary btn-xs" Text="Assign Keys" Enabled="false" />
<asp:Button ID="RecallButton" runat="server" CssClass="btn btn-primary btn-xs" Text="Recall Key" Enabled="false" />
<asp:Panel ID="KeysPanel" runat="server" Visible="false">
</td></tr><tr>
<td colspan="999">
<asp:GridView ID="KeysGV" runat="server" AutoGenerateColumns="false" CssClass="table table-striped"
EmptyDataText="No assignments have been made.">
<Columns>
.
.
.
</Columns>
</asp:GridView>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
ExpandButton 回发如下所示:
protected void ExpandButton_Click(object sender, EventArgs e)
{
GridViewRow myRow = ((Control)sender).NamingContainer as GridViewRow;
ImageButton expandBtn = sender as ImageButton;
if (expandBtn.ImageUrl == "~/Images/plus.png")
{
expandBtn.ImageUrl = "~/Images/minus.png";
Panel pnl = myRow.Cells[5].Controls[0].FindControl("KeysPanel") as Panel;
pnl.Visible = true;
}
else
{
expandBtn.ImageUrl = "~/Images/plus.png";
Panel pnl = myRow.Cells[5].Controls[0].FindControl("KeysPanel") as Panel;
pnl.Visible = false;
}
}