[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 258
  • Last Modified:

Repeater with variable number of columns

I have a query that can return a variable number of columns (uses a pivot). I want to use a repeater control (or something similar) with it. Is there any simple way to achieve this?
I know I can simply create the whole thing dynamically, but that is a nightmare to align. I would rather use something simple like this, if possible.
0
Cluskitt
Asked:
Cluskitt
  • 6
  • 5
1 Solution
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Hello, a simple way is to use a System.Web.UI.WebControls.GridView control, with the property AutoGenerateColumns = true, then bind your Data to its DataSource property.
0
 
CluskittAuthor Commented:
The only problem with creating the whole repeater dynamically is for editing. I've tried once a similar solution (with an asp:Table) but I could never edit the data because the values in the (dynamic) textboxes wouldn't survive postbacks.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
CluskittAuthor Commented:
As for using a gridview, my problem is just setting up a custom update method (too complex to use an SQLDataSourceAdapter)
0
 
CluskittAuthor Commented:
Ok, using a gridview seems to be a good way to go, but it generates only label type columns. How can I set this so it generates textboxes?
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Using a column template field is a good idea, I'm busy right now, I will give you a example shortly.
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Oh... You are going to use this with AutoGenerateColumns= true, let me see what can I do..
0
 
CluskittAuthor Commented:
Well, there are many situations which would be acceptable:
1) Generating the gridview with AutoGenerateColumns=true, all columns are textboxes. I can then loop through the controls and set Enabled=False on some.
2) Generating the gridview with AutoGenerateColumns=true, some columns are labels, some are textboxes (defined at runtime)
3) Generating the gridview with AutoGenerateColumns=false. Creating a dataset or datatable object, looping through the columns to define column type and then binding it.

I would prefer the second option, though the third would be almost the same and acceptable as well. If all else fails, the first would be sufficient.
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Hello, I have tried to change the default behavior of the GridView when AutoGenerateColumns=true without acceptable results, so I have decided to create a Web User Control that render dynamically a Table with TextBoxes, maybe this can give you a start, so you can adapt this code to your needs, I have designed it in a way that supports control state between post backs:

This is the Web User Control code (ascx file):
<%@ Import Namespace="System.Data" %>
<%@ Control Language="VB" ClassName="MyCustomControl"  %>

<script runat="server">

    Protected Overrides Sub LoadViewState(ByVal savedState As Object)
        MyBase.LoadViewState(savedState)
        If IsPostBack Then
            BuildControls(Nothing)
        End If
    End Sub

    Private mDataSource As Object = Nothing
    Public Property DataSource As Object
        Get
            Return mDataSource
        End Get
        Set(ByVal value As Object)
            If value Is Nothing Then
                mDataSource = Nothing
                Exit Property
            End If
            
            If Not TryCast(value, DataTable) Is Nothing OrElse Not TryCast(value, IDataReader) Is Nothing Then
                mDataSource = value
            Else
                Throw New Exception("Invalid DataSource")
            End If
        End Set
    End Property
    
    Private Property Columns As Integer
        Get
            Return Convert.ToInt32(ViewState("Columns"))
        End Get
        Set(ByVal value As Integer)
            ViewState("Columns") = value
        End Set
    End Property

    Private Property Rows As Integer
        Get
            Return Convert.ToInt32(ViewState("Rows"))
        End Get
        Set(ByVal value As Integer)
            ViewState("Rows") = value
        End Set
    End Property
    
    Public Overrides Sub DataBind()
        If mDataSource Is Nothing Then Exit Sub
        
        Dim reader As IDataReader
        If mDataSource.GetType() Is GetType(DataTable) Then
            reader = CType(mDataSource, DataTable).CreateDataReader
        Else
            reader = mDataSource
        End If
        
        BuildControls(reader)
        
        MyBase.DataBind()
    End Sub
    
    Sub BuildControls(ByVal reader As IDataReader)
        Dim headerCellText() As String = CType(ViewState("HeaderCellText"), String())
        
        If Not reader Is Nothing Then
            Columns = reader.FieldCount
            ReDim headerCellText(Columns - 1)
        End If

        Dim tableHeader As New TableRow
        For index = 0 To Columns - 1
            Dim cell As New TableCell
            If Not reader Is Nothing Then
                cell.Text = Server.HtmlEncode(reader.GetName(index))
                headerCellText(index) = cell.Text
            Else
                cell.Text = headerCellText(index)
            End If
            tableHeader.Cells.Add(cell)
        Next
        MyTable.Rows.Add(tableHeader)
        ViewState("HeaderCellText") = headerCellText
        
        If Not reader Is Nothing Then
            Dim rowCount As Integer = 0
            Do While reader.Read
                rowCount += 1
                BuildRow(reader)
            Loop
            Rows = rowCount
        Else
            For index = 0 To Rows - 1
                BuildRow(Nothing)
            Next
        End If
    End Sub
    
    Sub BuildRow(ByVal reader As IDataReader)
        Dim tableRow As New TableRow
        For index = 0 To Columns - 1
            Dim cell As New TableCell
            Dim textBox As New TextBox
            If Not reader Is Nothing Then
                textBox.Text = reader.GetValue(index).ToString()
            End If
            cell.Controls.Add(textBox)
            tableRow.Cells.Add(cell)
        Next
        MyTable.Rows.Add(tableRow)
    End Sub
</script>

<asp:Table ID="MyTable" runat="server" GridLines="Both" >
</asp:Table>

Open in new window

You can download the file from this link:
MyCustomControl.ascx

This is the demo page code (aspx file):
<%@ Import Namespace="System.Data" %>
<%@ Register Src="MyCustomControl.ascx" TagName="MyCustomControl" TagPrefix="uc1" %>

<%@ Page Language="VB" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
        If Not IsPostBack Then
            Dim dtt As New DataTable
            dtt.Columns.Add("ColA", GetType(String))
            dtt.Columns.Add("ColB", GetType(String))
            dtt.Columns.Add("ColC", GetType(String))
            dtt.Rows.Add("Test 1", "Test 2", "Test 3")
            dtt.Rows.Add("Test 1", "Test 2", "Test 3")
            dtt.Rows.Add("Test 1", "Test 2", "Test 3")
            dtt.Rows.Add("Test 1", "Test 2", "Test 3")
            
            MyCustomControl1.DataSource = dtt
            MyCustomControl1.DataBind()
        End If
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <uc1:MyCustomControl ID="MyCustomControl1" runat="server" />
        <br />
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </div>
    </form>
</body>
</html>

Open in new window

Here the aspx demo file:
Default22.aspx
0
 
CluskittAuthor Commented:
We decided to generate a few different static controls in order to speed things up. We'll convert to dynamic later, but the priority now is to get it working. Seeing as this was taking too long, we'd rather have 10 repeated pages with slightly different static layout. But we will return to set it dynamic. From what I've seen, your code seems to be good. I could adapt it to my needs. I'm just not sure if the text in the textboxes would survive postbacks. That is, if we changed the text and clicked a button, which text would appear at the time of the button click event? The one that was loaded from the query, or the one that was input by the user? I would have to test with it, which means it can't be right now. Thanks for your help, though! :)
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Well, good luck with your project, if you read my previous post:
I have designed it in a way that supports control state between post backs
I have the post back scenario in consideration, because I think it was important to you, if you test the demo page, change the textbox values and press the button on the page, the new text will be preserved between post backs... otherwise It would be easy to do.
0
 
CluskittAuthor Commented:
Cool. Thanks a lot. Sorry I don't have more time to test your code right away, but I will get back to it later. I'll let you know how it goes then.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 6
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now