【问题标题】:Dynamically add DropDownList with Events to HTML table将带有事件的 DropDownList 动态添加到 HTML 表
【发布时间】:2017-04-19 11:32:07
【问题描述】:

我正在尝试设置如下所示的表格:

| 姓名 | 电子邮件 | 当前用户组 | 更改用户组 |

每行的 ChangeUserGroup 列都有一个 DropDownList 控件,其中包含 3 个选项(student、advisor、admin),在 SelectedIndexChanged 事件中,每一行都会更新其用户的 userGroup。

几周前我有这个工作,但从未提交过更改,我丢失了它们并且不记得我是如何工作的。

这是我目前按表构建的方式:

  1. Page_Load 调用 BuildUserTableHtml() 在表中创建 DropDownList。

    private void buildUserTableHtml(List<User> users)
    {
    StringWriter htmlString = new StringWriter();
    using (HtmlTextWriter writer = new HtmlTextWriter(htmlString))
    {
        foreach(User user in users)
        {
            string name = user.firstName + " " + user.lastName;
    
            //tr
            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
    
            //td 1
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write(name);
            writer.RenderEndTag(); //td 1 end
    
            //td 2
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write(user.email);
            writer.RenderEndTag(); //td 2 end
    
            //td 3
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write(user.userGroup);
            writer.RenderEndTag(); //td 3 end
    
            //td
            HtmlTableCell cell = new HtmlTableCell();
            DropDownList ddl = new DropDownList();
            ddl.Items.Add(new ListItem("UerGroup", "0"));
            ddl.Items.Add(new ListItem("User", "USER"));
            ddl.Items.Add(new ListItem("Advisor", "ADVISOR"));
            ddl.Items.Add(new ListItem("Admin", "ADMIN"));
            ddl.SelectedIndex = 0;
            ddl.AutoPostBack = true;
            ddl.SelectedIndexChanged += userGroup_ItemChanged;
            cell.Controls.Add(ddl);
            cell.RenderControl(writer); // end td 4
    
            //td 5
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "glyphicon glyphicon-remove");
            writer.AddAttribute("data-toggle", "tooltop");
            writer.AddAttribute(HtmlTextWriterAttribute.Title, "Delte User");
            writer.AddAttribute("href", "#");
            writer.RenderBeginTag(HtmlTextWriterTag.A);
            writer.RenderBeginTag(HtmlTextWriterTag.Span);
            writer.RenderEndTag();
            writer.RenderEndTag();
            writer.RenderEndTag(); //td 5 end
    
            writer.RenderEndTag(); //tr end
    
        }
    }
    userTable_PlcHldr.Controls.Add(new Literal { Text = htmlString.ToString() });
    }
    

userTable_PlcHldr 是一个已构建的表中的 .NET 占位符,该表使用 javascript 插件使其可搜索。

<table id="userTable" class="table table-striped table-hover table-bordered">
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Email</th>
                        <th>User Group</th>
                        <th>Change</th>
                        <th>Delete User</th>
                    </tr>
                </thead>
                <tbody>
                        <asp:PlaceHolder ID="userTable_PlcHldr" runat="server" ></asp:PlaceHolder>

                </tbody>
            </table>
  1. 更改 DropDownList 的选定值 - 应该触发 userGroup_ItemChanged()

    protected void userGroup_ItemChanged(object sender, EventArgs e)
    {
    UserGroup userGroup;
    DropDownList ddl = (DropDownList)sender;
    bool update = true;
    
    string value = ddl.SelectedValue;
    int ID = Int32.Parse(ddl.ID.Substring(1));
    switch (value)
    {
        case "ADMIN":
            userGroup = UserGroup.ADMIN;
            break;
        case "ADVISOR":
            userGroup = UserGroup.ADVISOR;
            break;
        case "USER":
            userGroup = UserGroup.USER;
            break;
        default:
            userGroup = UserGroup.DEFUALT;
            update = false;
            break;
    }
    try
    {
        if (update)
            UserGroups.UpdateUserGroup(ID, userGroup);
    
    } catch (Exception ex)
    {
        string error = ex.Message;
    }
    }
    

但是,此代码不起作用。它正确呈现页面上的控件,但 SelectedItemChanged 永远不会触发。启用自动回发。我认为这是因为控件实际上并未正确添加到页面中,而服务器看不到它们。

还有人知道怎么做吗?

【问题讨论】:

  • 我们一般不会像那样构建控制 HTML。在 ASPX 标记上声明您的控件,然后将适当的数据绑定到它。使用中继器等。
  • @mason 好的 - 我以前没有使用过中继器。如果我弄清楚与否,我会进行一些研究并报告。
  • 如果您刚刚学习 ASP.NET,为什么要从 Web 窗体而不是 MVC 开始?
  • 我从过去几个夏天的实习经历中了解了一些 ASP.NET,并且该公司使用 Web Forms 而不是 MVC。我正在从事的项目是一个为期一个学期的小组项目,我是唯一一个对 Web 应用程序有任何经验的人。我没有尝试同时教自己和其他 3 名学生 MVC,而是使用 WebForms,因为我熟悉它。如果有更多的时间和拥有更多知识的团队,我会使用 MVC。
  • MVC 比 Web 窗体更容易学习,它更快,更容易获得体面的架构,并且 Web 窗体不会包含在 ASP.NET 的未来中。如果还不算太晚,我强烈建议您check out MVC。只需一点 C# 和 HTML 知识,就可以轻松上手并运行。

标签: c# asp.net drop-down-menu


【解决方案1】:

我能够使用 asp:Repeater 来完成这项工作。

<table id="userTable" class="table table-striped table-hover table-bordered">
    <thead>
        <tr>
            <th>Name</th>
            <th>Email</th>
            <th>User Group</th>
            <th>Change</th>
            <th>Delete User</th>
        </tr>
    </thead>
    <tbody>
        <asp:Repeater ID="Repeater1" runat="server">
            <ItemTemplate>
                <tr>
                    <td><asp:Label runat="server" Text='<%# Eval("firstName").ToString() + " " + Eval("lastName").ToString() %>'></asp:Label></td>
                    <td><asp:Label runat="server" Text='<%# Eval("email") %>'></asp:Label></td>
                    <td><asp:Label runat="server" Text='<%# Eval("userGroup") %>'></asp:Label></td>
                    <td>
                        <asp:DropDownList AutoPostBack="true" OnSelectedIndexChanged="userGroup_ItemChanged" runat="server" CssClass="form-control">
                            <asp:ListItem Value="0"> <-UserGroup-> </asp:ListItem>
                            <asp:ListItem Value="USER"> User </asp:ListItem>
                            <asp:ListItem Value="ADVISOR"> Advisor </asp:ListItem>
                            <asp:ListItem Value="ADMIN"> Admin </asp:ListItem>
                        </asp:DropDownList>
                    </td>
                    <td>
                        <asp:LinkButton ID="deleteUser" runat="server" CssClass="btn btn-secondary" OnClick="deleteUser_Click">
                            <span class ="glyphicon glyphicon-remove" data-toggle="tooltip" title="Delete User"></span>
                        </asp:LinkButton>
                    </td>
                    <asp:HiddenField ID="hiddenID" runat="server" Value='<%# Eval("userID") %>' />
                </tr>
            </ItemTemplate>
        </asp:Repeater>
    </tbody>
</table>

然后在我的 OnSelectedIndexChanged 方法 userGroup_ItemChanged() 中,我能够通过执行以下操作获取 hiddenID:

DropDownList ddl = (DropDownList)sender;
RepeaterItem item = (RepeaterItem)ddl.NamingContainer;
HiddenField hiddenID = (HiddenField)item.FindControl("hiddenID");
int ID = int.Parse(hiddenID.Value);

【讨论】:

    【解决方案2】:

    Web 窗体的方式不是构建字符串并将其附加到控件层次结构中。太乱了。

    相反,Web 窗体会鼓励您将数据绑定到页面上已存在的控件,该控件已在 aspx 中声明。

    我准备了一个工作演示,您可以将它放入一个新的 Web 窗体应用程序中,它应该正常工作

    标记:

    <%@ Page Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebFormsHelloWorld._Default" %>
    
    <asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
        <asp:Repeater runat="server" ID="UsersRepeater" ItemType="WebFormsHelloWorld.User">
            <HeaderTemplate>
                <table>
                    <tr>
                        <th>Name</th>
                        <th>Email</th>
                        <th>Group</th>
                        <th>Change Group</th>
                    </tr>
            </HeaderTemplate>
            <ItemTemplate>
                <tr>
                    <td><%#: Item.Name %></td>
                    <td><%#: Item.Email %></td>
                    <td><%#: Item.Group %></td>
                    <td>
                        <asp:HiddenField runat="server" ID="UsersNameHiddenField" Value="<%#: Item.Name %>" />
                        <asp:DropDownList runat="server" OnSelectedIndexChanged="Unnamed_SelectedIndexChanged" AutoPostBack="true">
                            <asp:ListItem Text="--Select Item--" Value="SelectItem" />
                            <asp:ListItem Text="Admin" Value="Admin" />
                            <asp:ListItem Text="Advisor" Value="Advisor" />
                            <asp:ListItem Text="User" Value="User" />
                        </asp:DropDownList>
                    </td>
                </tr>
            </ItemTemplate>
            <FooterTemplate>
                </table>
            </FooterTemplate>
        </asp:Repeater>
    </asp:Content>
    

    如您所见,我们已经在 ASPX 页面中很好地声明了我们的标记。我们正在利用的另一个很酷的东西是强类型模型。通过设置中继器的ItemType,我们可以使用Item.Property来访问我们模型对象的属性。

    后面的代码:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace WebFormsHelloWorld
    {
        public partial class _Default : Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                if(!IsPostBack)
                {
                    var users = new List<User>
                    {
                        new User { Name = "Luke Skywalker", Email="luke@skywalker.com", Group = "Admin"},
                        new User { Name = "Han Solo", Email="han@solo.com", Group = "Advisor"},
                        new User { Name = "Leia Organa", Email="lea@alderan.com", Group = "User"},
                    };
    
                    UsersRepeater.DataSource = users;
                    UsersRepeater.DataBind();
                }
            }
    
            protected void Unnamed_SelectedIndexChanged(object sender, EventArgs e)
            {
                DropDownList changedDropDownList = sender as DropDownList;
                var parentRow = changedDropDownList.Parent;
                var hiddenField = parentRow.FindControl("UsersNameHiddenField") as HiddenField;
                var userName = hiddenField.Value;
                Debug.WriteLine($"User {userName}, new group {changedDropDownList.SelectedValue}");
            }
        }
    
        public class User
        {
            public string Name { get; set; }
            public string Email { get; set; }
            public string Group { get; set; }
        }
    }
    

    出于测试目的,我在代码中创建了一个用户列表。对于您的真实应用程序,您可能会从某个存储库中获取它们。然后,当它不是回发时,我们将它们绑定到转发器。

    在下拉列表的事件处理程序中,我们从隐藏字段中获取我们正在修改的用户的名称。我们不得不做一些愚蠢的控制层次遍历来获取这些数据,这是 Web 窗体中令人讨厌的部分。我们将发送者(启动事件的控件)转换为下拉列表并获取它的当前选定值。最后,我们将其写入调试控制台。在您的应用程序中,您可能希望更新存储库中的域对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-16
      • 2018-05-23
      • 1970-01-01
      • 2011-01-04
      • 2018-04-22
      • 2011-05-04
      相关资源
      最近更新 更多