在后端 ASP Repeater 中生成按钮,然后在 c 中找到控件#

Generating button in backend ASP Repeater and then finding the control in c#

提问人:Henry B 提问时间:2/17/2023 最后编辑:AbolfazlHenry B 更新时间:2/21/2023 访问量:123

问:

因此,我使用 Repeater 中的函数在后面的代码中创建一个按钮。然后,有一个按钮应该采用这些自动生成的按钮(如果我选中按钮 A 中的复选框,我会获取中继器中 A 行的值,按钮 B 也是如此,依此类推......

我可以看到在调试复选框是否正确生成时检查代码。所以我应该能够找到它,但不能。即使我使用了 findControl,但一直无法做到。

下面是前面的代码:

<asp:Panel ID="mainPanel" runat="server">
<asp:Repeater ID="repStudents" runat="server">
....
 <%# GetButton(Eval("Role").ToString()) %>
.... 
 <asp:LinkButton runat="server" OnClick="showChosen" ClientIDMode="Static"
CausesValidation="true">Save</asp:LinkButton>

在这里,我生成按钮,然后尝试显示所选值:

    protected string GetButton(string status)
            {
                string love="";
    
                if(status == "Rel")
                {
                    love = "<input id='relBtn' type='checkbox' runat='server'/>";
                }
                else
                {
                    love = "<input id='rfBtn' checked type='checkbox' runat='server'/>";
            }
            return love;
        }


protected void showChosen(object sender, EventArgs e)
        {
            CheckBox cb = (CheckBox)(mainPanel.FindControl("relBtn"));
            if(cb.Checked)
                lblError.Text = "Checkbox is checked";
else
                lblError.Text = "Checkbox is not checked";
            divError.Visible = true;

我得到的只是 Null 引用异常,即使如此,整个页面中也只有一个 relBtn。如果我查看页面生成的代码,我可以看到 relBtn,但由于某种原因,我找不到 Checkbox。

C# asp.net 转发器 FindControl

评论

0赞 Dai 2/17/2023
...为什么在 2023 年使用 WebForms?

答:

0赞 Albert D. Kallal 2/17/2023 #1

好吧,除非你穿越沙漠,爬山,用尽所有“合理”的选择?

你必须问为什么你要编写代码来注入一个按钮,而这是来自中继器、列表视图、网格视图等的每个控件的整个想法!

换句话说,编写代码代码的必要性,以及一个好的强有力的案例还没有提出。

为什么我们需要一个巨大的壮观的惊天动地的叙述来解释为什么使用这种方法?

因为在 99% 的情况下,您不需要这样做,并且整个 asp.net 系统附近的数据感知控制和的是围绕您而设计的,而不必走那条路。

所以,如果你有一些按钮,或者其他什么?只需将其放入中继器控件中,它就会为您一遍又一遍地“重复”!!

所以,说这个简单的中继器:

<asp:Repeater ID="Repeater1" runat="server"  >
    <ItemTemplate>                
        <div style="border-style:solid;color:black;width:320px;height:450px;float:left;margin-right:10px;margin-bottom:10px">
            <div style="text-align:center;padding:2px 10px 2px 10px" class="cards" >
                <asp:Button ID="cmdMyView" runat="server" Text="View" 
                    CssClass="btn-info" style="float:right"
                    CommandArgument = '<%# Eval("ID") %>'
                    OnClick="cmdMyView_Click" />
                <br />

                <h3 id="hFighter" runat="server"><%# Eval("Fighter") %></h3>
                <asp:Image ID="Image2" runat="server" 
                    ImageUrl = '<%# Eval("ImagePath") %>' Width="170" />
                <h4>Engine</h4>
                <asp:Label ID="EngineLabel2" runat="server" Text='<%# Eval("Engine") %>' />
                <h4>Description</h4>
                <asp:Label ID="DescLabel" runat="server" Text='<%# Eval("Description") %>' />
                <br /> 
            </div>
        </div> 
        </ItemTemplate>
</asp:Repeater>

请注意该按钮和该按钮的普通 jane 单击事件。

因此,为了填充中继器,我们有这个:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        LoadData()
    End If

End Sub

Sub LoadData()

    Using conn As New SqlConnection(My.Settings.TEST4)
        Dim strSQL As String =
            "SELECT * FROM Fighters"

        Using cmdSQL As New SqlCommand(strSQL, conn)
            conn.Open()
            Dim rstData As New DataTable
            rstData.Load(cmdSQL.ExecuteReader)
            Repeater1.DataSource = rstData
            Repeater1.DataBind()
        End Using
    End Using

End Sub

现在我们看到/得到这个:

enter image description here

现在,该按钮从上方单击(查看按钮)。

Protected Sub cmdMyView_Click(sender As Object, e As EventArgs)

    Dim btn As Button = sender
    Dim rRow As RepeaterItem = btn.NamingContainer

    Debug.Print("Row index = " & rRow.ItemIndex)
    Debug.Print("DATA ID pk = " & btn.CommandArgument)
    Dim hFighter As HtmlGenericControl = rRow.FindControl("hFighter")
    Debug.Print("Figher name = " & hFighter.InnerText)

End Sub

输出:

Row index = 3
DATA ID pk = 4
Figher name = Lockheed Martin F-35 Lightning II

因此,请注意简单的按钮单击如何选取当前数据行。

由此,我们可以使用查找控件,或者获取点击的“行索引”,或者在我们的例子中,我们还在按钮命令 arugment 中包含了数据库 PK id。

因此,当几乎所有数据感知控件都会非常轻松地一遍又一遍地为您重复数据和控件时,很难提出所有这些“手倒置”来编写代码来“注入”按钮,实际上零代码让这些按钮或控件为您重复。

有一些罕见的情况可以编写要注入的代码,但它们应该是最后的手段,因为在 99% 的情况下,不需要这样的代码,更糟糕的是,当你回发时,这种注入的控件不会持久,你必须在每次回发时重新注入才能使这样的页面正常工作。

编辑:所以,这可以使用

标记:

<asp:Repeater ID="Repeater1" runat="server">
    <ItemTemplate>
        <i id="iHotel" runat="server"><%# Eval("HotelName") %></i>
        <br />
        <asp:CheckBox ID="chkREL" runat="server"
            Checked='<%# Eval("Status").ToString() == "Rel" ? true : false %>' />
        <br />
        <asp:Button ID="Button1" runat="server" Text="Button"
            OnClick="Button1_Click" />
        <hr />
    </ItemTemplate>
</asp:Repeater>

说出要加载的代码:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            LoadData();
        }
    }

    void LoadData()
    {
        Repeater1.DataSource = General.MyRst("SELECT * FROM tblHotelsA");
        Repeater1.DataBind();   

    }

结果是这样的:

enter image description here

按钮点击:

protected void Button1_Click(object sender, EventArgs e)
{
    Button btn = (Button)sender;
    RepeaterItem iRow = (RepeaterItem)btn.NamingContainer;
    Debug.Print($"Row click index = {iRow.ItemIndex}");

    CheckBox chkRel = (CheckBox)iRow.FindControl("chkREL");
    Debug.Print($"Check box checked = {chkRel.Checked}");

    HtmlGenericControl iHotel = (HtmlGenericControl)iRow.FindControl("iHotel");
    Debug.Print($"Hotel name from 'p' item = {iHotel.InnerText}");

}

输出:

Row click index = 1
Check box checked = True
Hotel name from 'p' item = Ramada Lodge

评论

0赞 Henry B 2/17/2023
好吧,首先,感谢您的回复。只是想知道为什么我无法找到控件,我明白了,它可能不是最优化的解决方案,我应该一个接一个地创建它,因为在大多数情况下,我应该实现只有 2-3 行。
0赞 Albert D. Kallal 2/17/2023
好吧,我们必须仔细观察。但是,请记住,在回发时,这些注入的控件在代码隐藏中没有相应的类定义(在编译时发生)。在回发之后,此类控件将丢失 - (除非您在每次回发时重新运行代码以重新注入它们)。因此,不能对生成的页面“类”对象执行查找控件,因为这些控件是在编译时解析的,而不是在运行时解析的。但是,您应该能够搜索该控件的“响应”标头,而不是搜索页面类或页面类中的控件。
0赞 Albert D. Kallal 2/17/2023
有关如何处理此问题的更多示例代码,请参阅我的编辑。