asp:gridview 过滤器使用列表框不能进行多选

Posted

技术标签:

【中文标题】asp:gridview 过滤器使用列表框不能进行多选【英文标题】:asp:gridview filter using listbox cannot make multiple selection 【发布时间】:2019-07-21 03:24:14 【问题描述】:

我有这个 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

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

【问题讨论】:

这意味着如果您在列表框中选择四个项目,那么您只会在DropDownChange 事件处理程序的string selectedValue = dropdown.SelectedItem.Value; 上收到第一个项目值,对吧?然后仅为此项加载数据 @er-sho 是的,并且在回发之后,列表中没有选择其他三个项目 您知道如何将多个值传递给存储过程中的单个参数,例如,如果我选择abc,那么这些值将通过statusVal 在您的 SP 中传递参数? @er-sho 是的,我们必须使用 IN 对吗?但是我们可以使用 foreach(ListItem Item1 in ddlstatus.items) 来代替吗? 那么这个statusVal参数的输入需求如何?表示它的数组,如 ["a", "b", "c"] 或只有字符串,如 a, b, c 【参考方案1】:

请将列表框设为多个

<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 />";

        

     

  

【讨论】:

【参考方案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\''。如果不是,那么它看起来像'\''

【讨论】:

您是否在按钮点击中收到了多个值?在线添加断点 => var selectedNames.. 我收到错误“对象引用未设置为对象的实例。” 错误在哪一行? 让我们continue this discussion in chat。 字符串数组是否传递给SP参数?【参考方案3】:

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

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

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

    不要使用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();
 

【讨论】:

对不起,你是对的,我希望我的回答能澄清反对意见。基本上,如果实际的主要问题得到解决,您不需要更改 UI(添加一个按钮,并在列表中禁用自动回发),下拉列表会在回发 (1.) 上反弹,并且在您保留的答案上使用视图状态来传递状态值也是不必要的开销(和视图状态大小),并且您未能解决过程(2.)的问题,因为它是 mysql 我没有具体的答案,但我确定有人否则会。 在通过 TeamViewer 远程访问分析完整源代码后,我给出了一个解决方案,例如我对 OP 问题的回答。视图状态对他来说是强制性的。我认为您应该取消投票我的回答。因为您会在不了解 OP 的完整源代码的情况下提供基于主要且直接的方法的解决方案。 :)

以上是关于asp:gridview 过滤器使用列表框不能进行多选的主要内容,如果未能解决你的问题,请参考以下文章

在选择情况下未触发asp gridview可见性

如何根据文本框值过滤列表框值

按列表过滤熊猫数据框

Access VBA 如何根据多选列表框中的选择过滤记录集?

将过滤器列表应用于来自使用 pandas 的列表的数据框

根据多个组合框过滤查询,但如果组合框为空,则显示所有记录,包括空,