asp:gridview 使用列表框的过滤器无法进行多选

asp:gridview filter using listbox cannot make multiple selection

我有这个 asp:gridview,其中我使用 mySql 存储过程显示数据。我有一个名为 ddlstatus 的列表框,我用它来过滤数据。我使用视图状态来显示从列表框中选择的数据。问题是我想在此列表框中进行多项选择并显示其上的每个选择的数据,但是当它只显示初始选择的数据时。

以下是客户端代码:

<asp:Label ID="lblstat" Text="status" Visible="false" runat="server"></asp:Label>
<asp:ListBox ID="ddlstatus" runat="server" OnSelectedIndexChanged="DropDownChange" AutoPostBack="true" AppendDataBoundItems="true" SelectionMode="Multiple"></asp:ListBox>

<asp:GridView ID="gdvTM" runat="server" ControlStyle-Width="100%"  AutoGenerateColumns="False" DataKeyNames="ID" OnRowDeleting="gdvTM_RowDeleting" PageSize="5" CssClass="cssgridview" AlternatingRowStyle-BackColor="#d5d8dc">
    <Columns >
       <asp:TemplateField HeaderText="Current Status">
         <ItemTemplate >
             <asp:Label ID="lblcstat" runat="server" Text='<%# Eval("status") %>'></asp:Label>
        </ItemTemplate>
      </asp:TemplateField>
    </Columns>
</asp:GridView>

服务器端代码如下:

private void BindDropDownList()
{
    PopulateDropDown(ddlstatus, lblstat.Text);
}
private void PopulateDropDown(ListBox ddl, string columnName)
{
    ddl.Items.Clear();
    ddl.DataSource = BindDropDown(columnName);
    ddl.DataTextField = columnName;
    ddl.DataValueField = columnName;
    ddl.DataBind();
    ddl.Items.Insert(0, new ListItem("Please select", "0"));
}
private void BindGrid()
{
    DataTable dt = new DataTable();
    String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
    MySqlConnection con = new MySqlConnection(strConnString);
    MySqlDataAdapter sda = new MySqlDataAdapter();
    MySqlCommand cmd = new MySqlCommand("GetTMData");
    cmd.CommandType = CommandType.StoredProcedure;  
    string statusVal = null;
    if (ViewState["stat"] != null && ViewState["stat"].ToString() != "0")
    {
        statusVal = ViewState["stat"].ToString();
    }
    cmd.Parameters.AddWithValue("statusVal", statusVal);
    cmd.Connection = con;
    sda.SelectCommand = cmd;
    sda.Fill(dt);
    gdvTM.DataSource = dt;
    int i = dt.Rows.Count;
    gdvTM.DataBind();
    this.BindDropDownList();
    TableCell cell = gdvTM.HeaderRow.Cells[0];
    setDropdownselectedItem(ViewState["stat"] != null ? (string)ViewState["stat"] : string.Empty, ddlstatus);
}
private void setDropdownselectedItem(string selectedvalue, ListBox ddl)
{
    if (!string.IsNullOrEmpty(selectedvalue))
    {
         ddl.Items.FindByValue(selectedvalue).Selected = true;

    }
}
protected void DropDownChange(object sender, EventArgs e)
 {
      ListBox dropdown = (ListBox)sender;
      string selectedValue = dropdown.SelectedItem.Value;
      switch (dropdown.ID.ToLower())
      {
          case "ddlstatus":
             ViewState["stat"] = selectedValue;
             break;
      }

      this.BindGrid();
 }

private DataTable BindDropDown(string columnName)
{
    string username = uName.Text;
    String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
    MySqlConnection con = new MySqlConnection(strConnString);
    MySqlCommand cmd = new MySqlCommand("SELECT DISTINCT (" + columnName + ") FROM approved WHERE tm = @tm AND " + columnName + " IS NOT NULL", con);
    MySqlDataAdapter sda = new MySqlDataAdapter(cmd);
    cmd.Parameters.AddWithValue("@tm", username);
    DataTable dt = new DataTable();
    sda.Fill(dt);
    return dt;
}

下面是 MySql 存储过程:

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetTMData`(in statusVal varchar(45))
BEGIN
SELECT *
   FROM approved
   WHERE (statusVal IS NULL
                OR status = statusVal)
         order by date desc;
END

我怎样才能做到这一点?提前致谢。

首先,自动 post 返回不允许您 select 多个项目,因为最多 select 第二个项目, post 返回已经发生在第一个 selected item 所以,

您必须为您的列表框设置AutoPostBack="false"

<asp:ListBox ID="ddlstatus" runat="server" AutoPostBack="false" AppendDataBoundItems="true" SelectionMode="Multiple"></asp:ListBox>

要收集多个 selected 项目,我们只需选择按钮,例如,您可以在任何地方收集这些项目,

然后添加一个调用下面代码的按钮

<asp:Button ID="button1" runat="server" OnClick="button1_Click" Text="Click"/>

在上面的按钮事件处理程序上添加下面的代码,

protected void button1_Click(object sender, EventArgs e)
{
    var selectedNames = ddlstatus.Items.Cast<ListItem>()
                         .Where(i => i.Selected)
                         .Select(i => i.Value)
                         .ToList();

    string selectedValue = string.Join("','", selectedNames);

    selectedValue = "'" + selectedValue + "'";

    ViewState["stat"] = selectedValue;
}

然后 ViewState 中的逗号分隔项将用于存储过程参数

string statusVal = null;
if (ViewState["stat"] != null && ViewState["stat"].ToString() != "0")
{
    statusVal = ViewState["stat"].ToString();
}
cmd.Parameters.AddWithValue("statusVal", statusVal);  //<= Now this string variable contains comma separated list box items values.

如果您在 Page_Load 上填充您的列表框,请确保将其填充到 !Page.IsPostBack 中,例如

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        //Populate your list box here
    }
}

你的SP是

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetTMData1`(in statusVal varchar(255))
BEGIN

IF statusVal = '\'\'' THEN 
   select * from approved;
ELSE
  SET @sql = CONCAT('SELECT * FROM approved WHERE status IN (', statusVal, ')');
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;    
END IF ;        
END

如果您从下拉列表中 select 多项,那么您的 SP 参数数据看起来像 '\'apple\',\'banana\''。如果不是那么它看起来像 '\''.

请将列表框设为多个

<asp:ListBox id="ListBox1" 
           Rows="6"
           Width="100px"
           **SelectionMode="Multiple"** 
           runat="server">

         <asp:ListItem Selected="True">Item 1</asp:ListItem>
         <asp:ListItem>Item 2</asp:ListItem>
         <asp:ListItem>Item 3</asp:ListItem>
         <asp:ListItem>Item 4</asp:ListItem>
         <asp:ListItem>Item 5</asp:ListItem>
         <asp:ListItem>Item 6</asp:ListItem>

      </asp:ListBox>

然后在服务器端 void SubmitBtn_Click(对象发送者, EventArgs e) {

     Message.Text = "You chose: <br />";

     // Iterate through the Items collection of the ListBox and 
     // display the selected items.
     foreach (ListItem item in ListBox1.Items)
     {

        if(item.Selected)
        {

           Message.Text += item.Text + "<br />";

        }

     }

  }

我发现了一些可能需要解决的问题,

  1. 确保方法 BindDropDownList 仅在非回发(页面刷新)时调用,因为您的方法 PopulateDropDown 正在清除列表中的项目,这意味着视图状态无法在回发中恢复,因此可能是仅选择一项的原因。

  2. 我不是 100% 的 table 架构,但提供的 SQL 似乎无法通过多个状态正确查询,你应该可能会发送一个逗号分隔的值列表,并在 SQL 中将它们变成一个临时 table 以便您有效地搜索具有多个状态的项目(您可能应该为此创建一个新问题)。

  3. 不要使用SelectedItem进行多选,相反你需要为那些被选中的项目迭代你的列表项,你不需要使用ViewState来传递它(你可能因为上面的第 1 点而这样做了)。例如,您可以将方法 BindGridDropDownChange 替换为:

private void BindGrid()
{
    DataTable dt = new DataTable();
    String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
    MySqlConnection con = new MySqlConnection(strConnString);
    MySqlDataAdapter sda = new MySqlDataAdapter();
    MySqlCommand cmd = new MySqlCommand("GetTMData");
    cmd.CommandType = CommandType.StoredProcedure;  
    string statusVal = null;
     foreach (ListItem item in ddlstatus.Items)
     {
        if(item.Selected)
        {
           if(statusVal.length > 0)
               statusVal += ",";
           statusVal += item.Value;
        }
     }
    cmd.Parameters.AddWithValue("statusVal", statusVal);
    cmd.Connection = con;
    sda.SelectCommand = cmd;
    sda.Fill(dt);
    gdvTM.DataSource = dt;
    gdvTM.DataBind();

}

protected void DropDownChange(object sender, EventArgs e)
 {
      this.BindGrid();
 }