正如标题所述,我正在尝试根据 4 个下拉列表中的一个或多个选择来过滤网格视图。在按钮单击事件中,我使用最广泛的信息集填充网格视图。从这里开始,我希望在可用下拉列表(总共 4 个)中进行选择时更新网格视图。
虽然我觉得我可以通过一系列 if 语句和针对每个条件的修改查询来完成此操作,但我觉得应该有一种更有效的方法来完成此操作。下面我发布了与我遇到的这个问题相关的代码。
html/asp 代码
<tr>
<td>
<asp:DropDownList ID="ddlSearchOCFamily" AutoPostBack="True" AppendDataBoundItems="True" DataTextField="FamilyLong" DataValueField="FamilyLong" runat="server"></asp:DropDownList>
</td>
<td>
<asp:DropDownList ID="ddlSearchOCRate" AutoPostBack="True" AppendDataBoundItems="True" DataTextField="RateLong" DataValueField="RateLong" runat="server"></asp:DropDownList>
</td>
<td>
<asp:DropDownList ID="ddlSearchOCTerm" AutoPostBack="True" AppendDataBoundItems="True" DataTextField="TermLong" DataValueField="TermLong" runat="server"></asp:DropDownList>
</td>
<td>
<asp:DropDownList ID="ddlSearchOCEnrollment" AutoPostBack="True" AppendDataBoundItems="True" DataTextField="TypeDescription" DataValueField="TypeDescription" runat="server"></asp:DropDownList>
</td>
</tr>
<tr>
<td>
<div style="overflow: auto; width: 100%; padding: 2px;">
<asp:GridView ID="gvReverseSearchOC" runat="server" Width="99%" BackColor="White" BorderColor="#CC9966" BorderStyle="None"
BorderWidth="1px" CellPadding="4" AutoGenerateColumns="False" PageSize="20" AutoGenerateSelectButton="True">
<FooterStyle BackColor="#FFFFCC" ForeColor="#330099" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="#FFFFCC" />
<PagerStyle BackColor="#FFFFCC" ForeColor="#330099" HorizontalAlign="Center" />
<RowStyle BackColor="White" ForeColor="#330099" />
<SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="#663399" />
<SortedAscendingCellStyle BackColor="#FEFCEB" />
<SortedAscendingHeaderStyle BackColor="#AF0101" />
<SortedDescendingCellStyle BackColor="#F6F0C0" />
<SortedDescendingHeaderStyle BackColor="#7E0000" />
<Columns>
<asp:BoundField DataField="OrderCode" HeaderText="Order Code" SortExpression="OrderCode" Visible="True" ReadOnly="True" HeaderStyle-Wrap="False" />
<asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" ItemStyle-Wrap="False" />
<asp:BoundField DataField="Net Price" HeaderText="Net Price" SortExpression="Net Price" HeaderStyle-Wrap="False" />
</Columns>
</asp:GridView>
</div>
</td>
</tr>
页面加载事件
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim RSQuery As String = "
SELECT dDown.OrderCode, dDown.[Description], dDown.[Net Price]
FROM (
SELECT SKU.OrderCode AS OrderCode, SKU.[Description] AS [Description],
(SELECT FORMAT(SKU.ListPrice * EnrollmentType.Multiplier, 'C')) AS [Net Price]
FROM Enrollment
INNER JOIN EnrollmentType ON Enrollment.EnrollmentTypeID = EnrollmentType.RecID
INNER JOIN SKU ON EnrollmentType.TypeID = SKU.EnrollmentTypeID
INNER JOIN SKUBuild ON SKU.SKU = SKUBuild.SKU
WHERE (Enrollment.AccountNumber = '12345')
AND (Enrollment.Active = 'yes')
AND (SKU.[Description] IS NOT NULL AND NOT (SKU.[Description] = '""'))
) AS dDown
"
pnlSearchOC.Visible = False
PopSearchOCDDLs()
PopGVSearchOC(RSQuery)
End Sub
填充网格视图的过程
Protected Sub PopGVSearchOC(ByVal query As String)
Dim dt As New DataTable
Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ToString)
Using cmd As New SqlCommand(query, con)
con.Open()
Using sdr As SqlDataReader = cmd.ExecuteReader
If sdr.HasRows Then
dt.Load(sdr)
With gvReverseSearchOC
.DataSource = dt
.DataBind()
con.Close()
End With
End If
End Using
End Using
If con.State <> ConnectionState.Closed Then
con.Close()
End If
End Using
End Sub
我还有一个填充下拉列表的过程,但我不认为它与我的问题相关,我可能是错的。
我正在寻找一种优雅的解决方案来根据下拉列表中所做的选择来更新/过滤我的网格视图,任何这方面的信息将不胜感激。如果我缺少任何必要的代码,我很乐意提供它,但我很确定它都在这里。 谢谢你们抽出时间。
好的,你可以通过两种方式做到这一点。
您可以提取数据表,并保留该表(但是,这可能会占用浏览器内存。(但是,您可以使用 session() 来保存结果表 - 但使用 session() 通常意味着如果用户打开该页面的两个副本,然后事情就无法正常工作。
因此,最好对您拥有的 SQL 进行归档。 (我会将该 SQL 放在 SQL Server 视图中 - 我们真的不希望所有 SQL 代码都内联,因为它很难维护。
所以,我们的逻辑:
无选择 - 显示所有数据。选择 1、2、3 或 4 个组合或过滤器,然后我们逐步添加此额外条件。因此,空白 = 忽略,某些值 = 使用给定值进行过滤。
因此,我们需要一个适用于 1 或 10 个文件管理器选项的代码存根和方法。换句话说,如果我们找不到一种简单的方法来“添加”过滤器,那么我们就必须编写考虑所有组合的代码。 (非常糟糕)。
在这个解决方案中,我们也非常不想将值连接到 SQL 中,因为这不仅会导致 SQL 注入,而且这样的代码往往会很快变得非常混乱。
所以,这种方法:
测试给定的过滤器控制 - 如果有值,则添加到我们的标准,但仍然使用正确的参数 - 永远不会连接用户输入值!
我没有你的数据,但让我们制作一个简单的网格,并添加一些过滤器。我们将有 2 个组合,并勾选一个复选框(仅适用于 Active Hotels)。
所以,我们有这个标记,没什么花哨的:
<h4>Filters</h4>
<div style="float:left">
<asp:Label ID="Label1" runat="server" Text="Select City"></asp:Label>
<br />
<asp:DropDownList ID="cboCity" runat="server" Width="180px"
DataValueField="City"
DataTextField="City" >
</asp:DropDownList>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label2" runat="server" Text="Select Province"></asp:Label>
<br />
<asp:DropDownList ID="cboProvince" runat="server" Width="180px"
DataValueField="Province"
DataTextField="Province" >
</asp:DropDownList>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label3" runat="server" Text="Must Have Description"></asp:Label>
<br />
<asp:CheckBox ID="chkDescripiton" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label4" runat="server" Text="Show only Active Hotels"></asp:Label>
<br />
<asp:CheckBox ID="chkActiveOnly" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdSearch" runat="server" Text="Search" CssClass="btn"/>
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdClear" runat="server" Text="Clear Fitler" CssClass="btn"/>
</div>
<div style="clear:both">
<%-- this starts new line for grid --%>
</div>
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table" Width="60%">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:BoundField DataField="Active" HeaderText="Active" />
</Columns>
</asp:GridView>
因此,我们只需放入尽可能多的“div”,将它们向左浮动以供过滤器使用。您可以轻松添加更多过滤器控件。
所以,现在我们加载这些东西的代码是这样的:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadCombos()
Dim cmdSQL As New SqlCommand("SELECT * FROM tblHotels ORDER BY HotelName")
LoadGrid(cmdSQL)
End If
End Sub
Sub LoadCombos()
Dim cmdSQL As New _
SqlCommand("SELECT City FROM tblHotels WHERE City is not null GROUP by City")
cboCity.DataSource = MyrstP(cmdSQL)
cboCity.DataBind()
cboCity.Items.Insert(0, New ListItem("All", "All"))
cmdSQL.CommandText =
"SELECT Province FROM tblHotels WHERE Province is not null GROUP by Province"
cboProvince.DataSource = MyrstP(cmdSQL)
cboProvince.DataBind()
cboProvince.Items.Insert(0, New ListItem("All", "All"))
End Sub
Sub LoadGrid(cmdSQL As SqlCommand)
Dim rstData As DataTable = MyrstP(cmdSQL)
GridView1.DataSource = rstData
GridView1.DataBind()
End Sub
Public Function MyrstP(sqlCmd As SqlCommand) As DataTable
Dim rstData As New DataTable
Using sqlCmd
sqlCmd.Connection = New SqlConnection(My.Settings.TEST4)
sqlCmd.Connection.Open()
rstData.Load(sqlCmd.ExecuteReader)
End Using
Return rstData
End Function
同样,非常简单 - 只需一些干净的代码即可加载我们的组合和网格。
所以,现在我们有这个:
好的,现在是过滤器代码。如前所述,如果我们有 2 或 20 个过滤器,这就可以工作。并且您可以随着时间的推移添加更多内容 - 您不必更改现有代码。
所以,代码是这样的 - 搜索按钮:
Protected Sub cmdSearch_Click(sender As Object, e As EventArgs) Handles cmdSearch.Click
Dim strSQL As String = "SELECT * FROM tblHotels"
Dim strOrderBy As String = " ORDER BY HotelName"
Dim strWhere As String = ""
Dim cmdSQL As New SqlCommand("")
If cboCity.Text <> "All" Then
' city filter
strWhere = "(City = @City)"
cmdSQL.Parameters.Add("@City", SqlDbType.NVarChar).Value = cboCity.Text
End If
If cboProvince.Text <> "All" Then
If strWhere <> "" Then strWhere &= " AND "
strWhere &= " (Province = @Province)"
cmdSQL.Parameters.Add("@Province", SqlDbType.NVarChar).Value = cboProvince.Text
End If
' must have description
If chkDescripiton.Checked Then
If strWhere <> "" Then strWhere &= " AND "
strWhere &= " (Description is not null)"
End If
If chkActiveOnly.Checked Then
If strWhere <> "" Then strWhere &= " AND "
strWhere &= " (Active = 1)"
End If
If strWhere <> "" Then
strSQL &= " WHERE " & strWhere
End If
strSQL &= " " & strOrderBy
cmdSQL.CommandText = strSQL
LoadGrid(cmdSQL)
End Sub
所以,请注意“模式”。对于您添加的每个控件,您都有一个 if/then 块。您检查现有的 where 子句(可能没有),并将“ AND ”添加到 where 子句。然后,您可以将参数添加到 SQL 命令对象。
许多人没有意识到,您可以向命令对象添加参数,甚至不需要设置 SQL 命令对象的 SQL 源! - 它们是不同的概念。
因此,通过上面的内容,我们可以自由地检查/选择过滤器或其他内容,然后点击搜索按钮。
如果您有 2 或 25 个可选控件,则上述方法有效。
非常重要的是,我们在任何情况下都不会将用户输入连接到该 SQL 字符串中 - 只使用参数,因此这种方法是 SQL 注入安全的。