Search code examples
asp.netvb.netascx

ASP .NET Dynamically Create User Controls


I am working on a web application (IIS) targeting .NET 4.0 using Visual Studio 2015. I need to have a page with multiple user controls but the number of controls will not be known until runtime.

There will always be at least six controls. They should appear on screen like tiles in two rows of three - each tile approximately 30% of the screen width and 45% of the screen height.

That's not a problem. The issue is when there are more than 6 tiles due to user settings. The number of tiles needed will be retrieved from the database (SQL). Additional tiles should be added in a new row in the same layout as the original six but the screen should not expand - there should be a scrollbar to scroll down and see the next row of tiles.

I have a main page with the six initial controls, a placeholder, and a generic user control to put in that placeholder. I don't know how to get the placeholder to keep the same layout. Or even if this is the best way to accomplish the task.

Main .ASPX:

<%@ Page Language="vb" AutoEventWireup="false" Inherits="Reporting" CodeBehind="Reporting.aspx.vb"%>
<%@ Register TagPrefix="uc1" TagName="ReportingTile" Src="ReportingTile.ascx" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body style="overflow:hidden; width:100%; height:100%">
    <form id="form1" runat="server">        
        <asp:Panel ID="pnlTile1" runat="server" BackColor="White" style="position:absolute; width:31%; height:44%; left:1%; top:2%; font-family: Arial; font-size: 12px;">
            <uc1:ReportingTile id="ReportingTile1" runat="server"></uc1:ReportingTile>
        </asp:Panel>

        <asp:Panel ID="pnlTile2" runat="server" BackColor="White" style="position:absolute; width:31%; height:44%; left:34%; top:2%; font-family: Arial; font-size: 12px;">
            <uc1:ReportingTile id="ReportingTile2" runat="server"></uc1:ReportingTile>
        </asp:Panel>

        <asp:Panel ID="pnlTile3" runat="server" BackColor="White" style="position:absolute; width:31%; height:44%; left:67%; top:2%; right:2%; font-family: Arial; font-size: 12px;">
            <uc1:ReportingTile id="ReportingTile3" runat="server"></uc1:ReportingTile>
        </asp:Panel>

        <asp:Panel ID="pnlTile4" runat="server" BackColor="White" style="position:absolute; width:31%; height:44%; left:1%; top:49%; font-family: Arial; font-size: 12px;">
            <uc1:ReportingTile id="ReportingTile4" runat="server"></uc1:ReportingTile>
        </asp:Panel>

        <asp:Panel ID="pnlTile5" runat="server" BackColor="White" style="position:absolute; width:31%; height:44%; left:34%; top:49%; font-family: Arial; font-size: 12px;">
            <uc1:ReportingTile id="ReportingTile5" runat="server"></uc1:ReportingTile>
        </asp:Panel>

        <asp:Panel ID="pnlTile6" runat="server" BackColor="White" style="position:absolute; width:31%; height:44%; left:67%; top:49%; right:2%; font-family: Arial; font-size: 12px;">
            <uc1:ReportingTile id="ReportingTile6" runat="server"></uc1:ReportingTile>
        </asp:Panel>

        <div style="height:44%;width:31%;background-color:whitesmoke;">
            <asp:PlaceHolder ID="placeHolder1" runat="server"></asp:PlaceHolder>
        </div>
        <div runat="server" style="position:absolute;bottom:0px;left:0px;right:0px;margin:0;height:40px;">
            <asp:Table runat="server" Height="100%" Width="100%" BackColor="White" HorizontalAlign="Center">
                <asp:TableRow HorizontalAlign="Center" VerticalAlign="Bottom" Width="100%">
                    <asp:TableCell HorizontalAlign="Center" VerticalAlign="Bottom" style="background-color:white;">
                        <asp:ImageButton ID="btnCloseWindow" runat="server" CausesValidation="False" ImageUrl="../images/btn-CloseWindow.png" />
                    </asp:TableCell>
                </asp:TableRow>
            </asp:Table>
        </div>
    </form>
</body>
</html>

.ASPX.vb (I've hardcoded 3 additional controls just for testing):

Imports System.Linq
    Partial Public Class Reporting
        Inherits System.Web.UI.Page

        Private Property NumberOfControls As Integer
            Get
                Return CInt(ViewState("NumControls"))
            End Get
            Set(ByVal Value As Integer)
                ViewState("NumControls") = Value
            End Set
        End Property

        Protected Overrides Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim myControl As ReportingTile = CType(Page.LoadControl("~/ReportingTile.ascx"), ReportingTile)            
            Me.NumberOfControls = 3
            Me.createControls()
        End Sub

        Private Sub createControls()
            Dim count As Integer = Me.NumberOfControls

            For i As Integer = 2 To count - 1
                Dim myControl As ReportingTile = CType(Page.LoadControl("~/ReportingTile.ascx"), ReportingTile)
                Dim ph As PlaceHolder = New PlaceHolder()
                ph.ID = "ControlID_" & i.ToString()
                ph.Controls.Add(myControl)
                Dim lt As Literal = New Literal()
                lt.Text = "<br />"
                Page.Form.Controls.Add(ph)
                Page.Form.Controls.Add(lt)
            Next
        End Sub
    End Class
End Namespace

Generic User Control:

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="ReportingTile.ascx.vb" Inherits="ReportingTile" %>
<asp:Table ID="tblHPSettingsOptions" runat="server">
    <asp:TableRow>
        <asp:TableCell>
            <asp:Label runat="server" Font-Bold="true">Reporting Tile</asp:Label>
        </asp:TableCell>
    </asp:TableRow>
</asp:Table>

Solution

  • It is much better to use Bootstrap Grid System, Masonry, Flexbox or some other front end plugin insead of messing around yourself with styles in the controls itself. This is bound to cause problems (as you have noticted)

    https://getbootstrap.com/

    https://css-tricks.com/snippets/css/a-guide-to-flexbox/

    https://masonry.desandro.com/