动态创建的标签和文本框无法定位

问题描述

我正在构建一个动态创建的弹出窗口,其中包含一个动态创建的网格和控件(标签和文本框)。 网格部分工作正常,不是问题。但是,控件给我带来了问题。 这个想法是为网格中的每一列创建一个 Label一个 TextBox。我能够很好地创建它们,但根本无法定位它们。 label.Locationlabel.Toplabel.point 等会返回错误,指出它不是 Label 的一部分。 TextBox 也会发生同样的事情。 当它们确实显示时,它们会出现在水平行中,TextBoxLabel 重叠,除非宽度设置得足够大(这当然会留下一堆空白空间)。 我希望在 TextBox 之后立即与 Label 垂直对齐。 就像是: labelText:文本框

这些控件被添加asp:Panel (pnlFields)

For Each col As DataColumn In dataTable.Columns
      Dim label As New Label()
      label.Text = col.ColumnName & ": "
      label.Height = 24
      label.Width = label.Text.Length()
      pnlFields.Controls.Add(label)
      Dim textBox As New TextBox()
      textBox.Height = 24
      textBox.Width = 100
      pnlFields.Controls.Add(textBox)
Next

我想尝试让 Label 的宽度与它包含的文本一样长,而不是静态的,这样我(希望)能够将 TextBox 位置设置为正确在 Label 之后。

无论如何,我似乎根本无法指定位置来执行此操作。 有什么想法吗?

谢谢!

编辑:标记

<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <asp:Panel runat="server" ID="pnlFields" CssClass="FormStyle" Height="600px" />  
      <asp:Panel runat="server" ID="pnlFinder" CssClass="FormStyle">
       <telerik:RadGrid ID="batchRecords" runat="server" Skin="Windows7" ShowHeader="true" AutoGenerateColumns="true" Width="600px" AutopostBack="true">
           <MasterTableView CommandItemdisplay="Bottom" AllowPaging="true">
               <CommandItemSettings ShowAddNewRecordButton="false" />
               <Columns>
                   <telerik:GridButtonColumn UniqueName="selectRecord" HeaderText="Edit" CommandName="Select" Text="Edit Record" ButtonType="ImageButton" ImageUrl="~/images/icons/pencil.png">
                   </telerik:GridButtonColumn>
               </Columns>
           </MasterTableView>
       </telerik:RadGrid>
   </asp:Panel>
</asp:Content>

解决方法

我真的,但真的不认为需要创建这些文本框。有大量内置的重复控件。如果您即时创建这些控件,那么您就无法连接事件背后的代码 - 因此您几乎放弃了使用 asp.net 和所有这些出色的内置控件的全部理由。

我看不出为什么您可以注入并包含一些额外的“div”并将样式应用于这些 div。但是,在你走那条路之前?

您应该尝试提出一个非常有力的理由,说明为什么要走这条路,而不是使用列表视图、网格视图或中继器控件。它们旨在一遍又一遍地重复数据 - 并且使用非常少的代码和非常少的标记来实现。

用于填写这些控件的数据来自哪里?甚至相反 - 控件的结果将放置在哪里?你看,通过使用说中继器或其他什么?它们是数据绑定的。因此,一个人可以说添加 2 或 15 行数据,然后在一次 sql 更新操作中您可以写出所有这些数据! - 换句话说,您正在重复一些控制 - 但基于这里的大问题是什么以及如何?

如前所述,如果您创建并注入这样的控件,那么您就不能为这些控件拥有或连接事件。所以,对于这里的最终目标,要认真思考很久。您可能会修复布局问题,但是您的下一个问题/问题将是事件代码,然后是获取该输入并以某种方式将其推回某个数据库所需的复杂代码。因此,我真的不推荐这条路。

此外,使用其中一个内置的“重复”对象可以让您相对轻松地在屏幕上编辑该数据,并且如前所述,可以使用相同的方法写回一行或 15 行数据代码 - 并且比尝试将动态控件注入该表单要容易得多。此外,一旦您设法注入这些控件,您将使用什么“id”来引用这些控件?

这里的最终目标是关键概念。

我发现 gridview 很好 - 通常标记较少。但是,当您开始在该网格中说 3 个或更多自定义控件时?然后我喜欢 listview 而不是 gridview(因为 listview 允许你拖放和使用标准的 asp.net 控件,而不必将该控件放在模板块中。但是,你的情况?每行只有两个额外的控件网格?当然,坚持使用网格视图。

那么,要将这两个额外的列添加到该网格中?你可以这样做:

首先,我将使用向导来创建这个 gridview。然后我炸掉了数据源ID设置,也去掉了表单上的数据源控件。

所以,我数不到 1 分钟 - 放下 gridview。单击表单中的配置数据源。这个:

enter image description here

所以我配置了数据源,生成了 gv,然后删除了数据源 ID,并从标记中删除了数据源控件。所以,这需要 30 秒的时间,我最终得到了这个网格:

所以,我们得到了这个:

        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
            <Columns>
                <asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
                <asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
                <asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
                <asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
                <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
            </Columns>
        </asp:GridView>

加载这个网格的代码是这样的:

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

    If IsPostBack = False Then

        LoadGrid()

    End If

End Sub

Sub LoadGrid()

    Using cmdSQL As New SqlCommand("SELECT ID,FirstName,LastName,HotelName,City from tblHotels",New SqlConnection(My.Settings.TEST3))

        cmdSQL.Connection.Open()
        GridView1.DataSource = cmdSQL.ExecuteReader
        GridView1.DataBind()

    End Using
End Sub

现在我们有了这个:

enter image description here

好吧,用更少的时间写这篇文章还不错!!!

注意我们如何只用 3 行代码来加载网格?

超级简单。

好的,现在让我们在网格中添加一个标签和一个文本框。

好吧,只需为 gv 模板执行此操作:

enter image description here

所以,请注意我们刚刚添加了两个额外的列。标记是这样的:

      <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
            <Columns>
                <asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
                <asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
                <asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
                <asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
                <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />

                <asp:TemplateField HeaderText = "My label">
                    <ItemTemplate>
                        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>

                <asp:TemplateField HeaderText = "My Text Box">
                    <ItemTemplate>
                        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>

            </Columns>
        </asp:GridView>

现在,当我们运行上面的代码时,我们得到:

enter image description here

我的意思是那容易还是什么?我可以将那个标签 + 文本框放在 SAME TEMPLATE 列中。因此,您可以非常自由地将这些额外的列添加到该网格中,而且我们不必编写代码——事实上这非常容易,结果是我们现在有了额外的两列——并且非常轻松地实现了这一点。

而且我们还可以相对轻松地设置/更改标签和文本框的值 - 甚至基于该行的其他列数据,并且可以轻松地再次执行此操作。

所以,在一天结束时?我不建议您尝试手动添加两列,因为我们有上面概述的如此出色的方法。更好的是,用户在每行和文本框中键入的值可以通过代码从该 gv 中提取和重新释放 - 并且可以轻松完成 2 行或 20 行数据。

编辑: 由于对 gv 的控制和添加将在运行时(动态),那么您仍然希望使用 gv 对象模型 - 与该模型作斗争是一个非常糟糕的主意 - 顺其自然。

因此,您可以通过这种方式向 gv 添加额外的绑定字段列:

Sub LoadGrid()

    Using cmdSQL As New SqlCommand("SELECT ID,New SqlConnection(My.Settings.TEST3))

        cmdSQL.Connection.Open()
        GridView1.DataSource = cmdSQL.ExecuteReader
        AddColumns()

        GridView1.DataBind()

    End Using
End Sub

Sub AddColumns()

    Dim lblfield As New BoundField()
    lblfield.HeaderText = "Label1"
    GridView1.Columns.Add(lblfield)

    Dim txtfield As New BoundField()
    txtfield.HeaderText = "TextBox"
    GridView1.Columns.Add(txtfield)


End Sub

然后在项目绑定事件上,您还可以像这样注入您选择的控件:

 Protected Sub GridView1_RowDataBound(sender As Object,e As GridViewRowEventArgs) Handles GridView1.RowDataBound

    If e.Row.RowType = DataControlRowType.DataRow Then

        Dim MyLabel As New Label
        MyLabel.ID = "Label1"
        MyLabel.Text = "Label Text"
        e.Row.Cells(5).Controls.Add(MyLabel)

        Dim MyTextBox As New TextBox
        MyTextBox.ID = "Textbox1"
        MyTextBox.Text = "Text box value"
        e.Row.Cells(6).Controls.Add(MyTextBox)

    End If

End Sub

所以,现在有了这个简单的标记:

       <link href="Content/cuscosky.css" rel="stylesheet" />
        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
            <Columns>
                <asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
                <asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
                <asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
                <asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
                <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />

            </Columns>
        </asp:GridView>

那么,用上面的代码?我们得到相同的结果,以及这个输出:

enter image description here

,

编辑: 我通过在标记中创建一个 HTML 表来解决这个问题,然后以编程方式添加带有控件(标签和文本框)和唯一 ID 的行和单元格。然后我能够找到并使用正确的数据填充这些控件。 比尝试手动定位每个控件要容易得多。

我能够解决定位控件的问题。 我需要使用 label.Style.Add() 并输入所需的值。 现在似乎可以正常工作了。

谢谢!