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

时间:2019-02-27 11:54:23

标签: c# mysql asp.net stored-procedures gridview

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

以下是客户端代码:

<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

我该如何实现?预先感谢。

3 个答案:

答案 0 :(得分:3)

请使列表框为多个

<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 :(得分:2)

首先,自动回发不允许您选择多个项目,因为要选择第二个项目,回发已经发生在第一个选定的项目上,所以

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

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

例如,要收集多个选定的项目,我们只需选择按钮即可,您可以在任意位置收集这些项目,

然后添加一个按钮,该按钮将调用以下代码

<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

如果从下拉列表中选择多个项目,则SP的参数数据看起来像'\'apple\',\'banana\''。如果不是,则看起来像'\''

答案 2 :(得分:1)

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

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

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

  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();
 }