【问题标题】:How to dynamically add server controls into repeater?如何将服务器控件动态添加到转发器中?
【发布时间】:2020-09-28 23:50:51
【问题描述】:

我必须显示动态填充数据的表格,结构和布局有点复杂,所以我使用由自定义逻辑渲染成数据的转发器。

为了向普通用户显示数据,一切正常,但对于网站管理员,我需要允许一些操作......但我没有看到任何简单方便的方法来做到这一点。

我想到的就是这样写:

<asp:Repeater ID="TeamsRepeater" runat="server">
    <HeaderTemplate>
        <table class="t_data"><thead>
            ... some header controls here ...
        </thead><tbody>
    </HeaderTemplate>
    <ItemTemplate>
        <tr>
            <td>...</td>
            <td><%#((MyObject)Container.DataItem).MyValue%></td>
            <td runat="server"><asp:TextBox Value=<%#((MyObject)Container.DataItem).MyValue%></td>
            <td runat="server"><asp:button Text="Update"/></td>
        </tr>
    </ItemTemplate>
        </tbody></table>
</asp:Repeater>

另外我需要添加将更新所有 3 个可见性的逻辑:

  1. 显示不可编辑的 MyValue 的单元格(应该对普通用户可见)
  2. 显示可编辑 MyValue 的单元格(应该对管理员可见)
  3. 包含更新按钮的单元格(应该对管理员可见,以便他们触发更新操作)。

我觉得如果我继续这样,代码会很丑陋,我什至看不出有什么方法可以实现它......

问题:

我应该如何更改服务器控件的可见性?

欢迎任何建议!

谢谢。

附:我的网站是使用 ASP.NET 4.0 编写的(虽然我可以考虑将其升级到 ASP.NET 4.5)

【问题讨论】:

    标签: c# asp.net repeater


    【解决方案1】:

    嗯,这不是一个那么简单的任务。在您的情况下,您需要完全自定义转发器,您需要访问控件并更改它们的属性,您需要拥有按钮并将事件处理程序分配给它们。
    所以我的回答可能有点长,但我认为你们都需要完全自定义ASP.NET Repeater

    请按照这个答案一步一步来。

    假设

    1. 我们有一个包含两列的表:绑定到中继器的 ID 和标题。

    2. 我们有一个这样的 ASPX 页面:

      <asp:UpdatePanel ID="UpdatePanel1" runat="server">
      <ContentTemplate>
          <asp:Repeater ID="rptMyRepeater" ClientIDMode="AutoID" runat="server" OnItemDataBound="rptMyRepeater_ItemDataBound" OnItemCommand="rptMyRepeater_ItemCommand" DataSourceID="SqlDataSource1">
              <ItemTemplate>
                  <asp:TextBox ID="txtMyTextBox" runat="server"></asp:TextBox>
                  <asp:Button ID="btnSowID" CommandName="ShowID" runat="server" Text="Show ID" />
                  <asp:Button ID="btnShowTitle" CommandName="ShowTitle" runat="server" Text="Show Title" />
                  <br /><br />
              </ItemTemplate>
          </asp:Repeater>
          <asp:Label ID="lblMsg" runat="server" Text=""></asp:Label>
      </ContentTemplate>
      </asp:UpdatePanel>
      <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:postdataConnectionString %>" SelectCommand="SELECT * FROM [Titles]"></asp:SqlDataSource>
      

      Repeater 内部有 3 个控件:两个 Button 和一个 TextBox,Repeater 外部有 Label (lblMsg)。


    情景:

    1. 我们希望在文本框中显示标题。
    2. 奇数 ID 显示按钮,偶数 ID 隐藏按钮。
    3. 通过单击每个按钮,在 lblMsg 中显示相关行的 ID 或标题。

      我认为这个场景涵盖了所有其他场景,您可以修改代码来执行任何其他操作。


    演练:

    1.为了达到第一个目标,我们使用ItemDataBound事件处理程序:

    protected void rptMyRepeater_ItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
    {
        System.Data.DataRowView dataItem = e.Item.DataItem as System.Data.DataRowView;
        if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
        {
            TextBox txtMyTextBox = e.Item.FindControl("txtMyTextBox") as TextBox;
            txtMyTextBox.Text = dataItem.Row["Title"].ToString();
        }
    }
    

    在上面我们在Repeater中找到TextBox并从数据库中分配Title Column。

    输出:

    2.现在我们要为奇数 ID 显示按钮并为偶数 ID 隐藏它们,因此也添加此部分:

    Button btnSowID = e.Item.FindControl("btnSowID") as Button;
    Button btnShowTitle = e.Item.FindControl("btnShowTitle") as Button;
    if (Convert.ToInt32(dataItem.Row["ID"]) % 2 == 0)
    {
        btnSowID.Visible = false;
        btnShowTitle.Visible = false;
    }
    

    在上面我们在Repeater中找到btnSowID和btnShowTitle,并检查该行的ID是否甚至因此将相关按钮的可见性设置为false。 很明显,您可以实现任何其他条件。例如,如果当前用户是管理员,则显示按钮。

    输出:

    3.现在我们要为Repater中的每个Button添加Click Handler。正如您在 ASPX 代码中看到的,我们为按钮设置了 CommandName 属性,我们将来会使用此属性。
    最终目标是单击每个按钮,lblMsg 向我们显示相关按钮单击的同一行的 ID 或标题。所以我们需要识别被点击的Button所在的行。
    为了达到这一点,我们将相关的 ID 或 Title 值分配给 ItemDataBound 处理程序下每个 Button 的 CommandArgument 属性。
    所以最后的ItemDataBound一定是这样的:

        protected void rptMyRepeater_ItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
        {
            System.Data.DataRowView dataItem = e.Item.DataItem as System.Data.DataRowView;
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                TextBox txtMyTextBox = e.Item.FindControl("txtMyTextBox") as TextBox;
                txtMyTextBox.Text = dataItem.Row["Title"].ToString();
    
                Button btnSowID = e.Item.FindControl("btnSowID") as Button;
                btnSowID.CommandArgument = dataItem.Row["ID"].ToString();
    
                Button btnShowTitle = e.Item.FindControl("btnShowTitle") as Button;
                btnShowTitle.CommandArgument = dataItem.Row["Title"].ToString();
    
                if (Convert.ToInt32(dataItem.Row["ID"]) % 2 == 0)
                {
                    btnSowID.Visible = false;
                    btnShowTitle.Visible = false;
                }
            }
        }
    

    为了捕捉Repeater内部按钮的点击事件,我们使用ItemCommand处理程序。这个处理程序帮助我们捕获和处理中继器内的控件事件。 所以我们像这样定义ItemCommand Handler:

        protected void rptMyRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            switch (e.CommandName)
            {
                case "ShowID":
                    lblMsg.Text = e.CommandArgument.ToString();
                    break;
    
                case "ShowTitle":
                    lblMsg.Text = e.CommandArgument.ToString();
                    break;
            }
        }
    

    在上面,我们检查了在 ASPX 代码中手动设置的 CommandName 属性,并确定单击的是 ShowID 按钮或 ShowTitle 按钮。 当我们在第一步中找到它时,然后尝试找到 Button 放置在哪一行。于是我们读取了CommandArgumentItemDataBoundHandler下动态设置的属性。

    您还可以使用此方法创建 btnEdit 和 btnRemove 等按钮,将 CommandNames 设置为 Edit 和 Remove 并将 CommandArgument 设置为 Row ID,并在 ItemCommand Handler 下的数据库中执行更新或删除。

    输出:

    【讨论】:

    • 感谢您的详细解答。据我所知,这并不是真正需要的,因为我知道这种方法并且正在寻找一种替代方法。但我坚信这会让其他人受益。
    • @Budda:我觉得也许您正在寻找 aspx 页面中的内联代码解决方案(我认为它没有明确提及)但我认为将来您将面临问题通过处理事件的内联解决方案以及可能在场景更改中,您的代码看起来也很混乱,在两种情况下,您必须使用ItemCommand 处理程序。所以我认为 CodeBehind 解决方案更简洁、更灵活。对不起,如果这个答案不是你想要的。
    • 是的,我一直在寻找某种类型的内联解决方案。但看起来即使可能,这也将是不可读且不可维护的。所以谢谢你的想法。已经实现了:)
    【解决方案2】:

    这是正确的做法。但是,我会将所有可见性逻辑封装在您的对象中,并避免在绑定表达式中使用 if else 逻辑。

    【讨论】:

      【解决方案3】:

      我们可以使用 ItemdataBound 上中继器内的 PlaceHolder 控件动态创建控件。

      我正在分享以下链接,其中包含完整示例。 [在Asp.Net(c#)中使用占位符在Repeater内部进行动态控制?][1] http://programmerskills.blogspot.com/2016/05/dynamic-control-create-dynamic-control.html

      【讨论】:

        猜你喜欢
        • 2012-07-27
        • 2011-12-01
        • 2012-11-11
        • 2016-01-16
        • 1970-01-01
        • 2011-02-08
        • 2011-10-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多