Question

I have a databound gridview that I create dynamically. The datasource returns an object based on the several DropDownLists (types of objects are different). Depending on the type of the object, the GridView must display certain fields specific only for the object. Also, there is a DropDownList whose SelectedValue decides which columns of an object will be added/excluded from the GridView.

Here is a method that creates the GridView (I write in VB.NET but C# is also very welcome):

Private Sub CreateGridView()
    Dim gv As New GridView
    With gv
        .AllowSorting = True
        .AutoGenerateColumns = False
        .CssClass = "gv"
        .EmptyDataText = "The list is empty"
        .ID = "gv"
        .ShowFooter = True

        .AlternatingRowStyle.Wrap = False
        .EditRowStyle.Wrap = False
        .FooterStyle.Wrap = False
        .HeaderStyle.Wrap = False

        .SortedAscendingCellStyle.CssClass = "sortAscCell"
        .SortedAscendingHeaderStyle.CssClass = "sortAscHeader"
        .SortedDescendingCellStyle.CssClass = "sortDescCell"
        .SortedDescendingHeaderStyle.CssClass = "sortDescHeader"

        AddHandler .RowDataBound, AddressOf gv_RowDataBound
        AddHandler .DataBound, AddressOf gv_DataBound
        AddHandler .RowUpdating, AddressOf gv_RowUpdating

        .DataSource = odsEquipment.Select
        .DataKeyNames = {"equipmentID"}
    End With

    For Each item As Dictionary In odsDictionary.Select
        If ddlStages.SelectedValue <> "" Then
            If ddlStages.SelectedValue >= item.stage_id Then
                Dim tf As New TemplateField()
                tf.SortExpression = item.col
                tf.HeaderTemplate = New GridViewTemplate(item.title, item.col)
                tf.ItemTemplate = New GridViewTemplate(DataControlRowType.DataRow, item.col, item.ctrlType, item.length)
                tf.FooterTemplate = New GridViewTemplate(DataControlRowType.Footer, item.col, item.ctrlType, item.length)

                gv.Columns.Add(tf)
            End If
        End If
    Next

    gv.DataBind()

    divGV.Controls.Add(gv)
End Sub

The GridView is always in Edit mode, meaning, it's ItemTemplate is a TexBox/DropDownList/CheckBox. Here is an ITemplate Class:

Imports System.Data

Public Class GridViewTemplate
    Implements ITemplate

    Private templateType As DataControlRowType
    Private title As String
    Private columnBinding As String
    Private ctrlType As String
    Private length As Integer

    Public Sub New(ByVal vTitle As String, vColumnBinding As String)
        templateType = DataControlRowType.Header
        title = vTitle
        columnBinding = vColumnBinding
    End Sub

    Public Sub New(ByVal type As DataControlRowType, ByVal vColumnBinding As String, ByVal vCtrlType As String, vLength As Integer)
        templateType = type
        columnBinding = vColumnBinding
        ctrlType = vCtrlType
        length = vLength
    End Sub

    Private Sub InstantiateIn(container As Control) Implements ITemplate.InstantiateIn
        Select Case templateType
            Case DataControlRowType.Header
                Dim lb As New LinkButton()
                lb.ID = "lb" + columnBinding
                lb.CommandName = "Sort"
                lb.CommandArgument = columnBinding
                lb.Text = title
                container.Controls.Add(lb)
                Exit Select

            Case DataControlRowType.DataRow
                If ctrlType = "Label" Then
                    Dim lbl = New Label()
                    lbl.ID = "lbl" + columnBinding
                    AddControl(lbl, container)
                ElseIf ctrlType = "TextBox" Then
                    Dim tb As New TextBox
                    tb.ID = "tb" + columnBinding
                    tb.MaxLength = length
                    AddControl(tb, container)
                ElseIf ctrlType = "CheckBox" Then
                    Dim cb = New CheckBox()
                    cb.ID = "cb" + columnBinding
                    AddControl(cb, container)
                ElseIf ctrlType = "DropDownList" Then
                    Dim ddl = New DropDownList()
                    ddl.ID = "ddl" + columnBinding
                    AddControl(ddl, container)
                End If
                Exit Select

            Case DataControlRowType.Footer
                If ctrlType = "Label" Then
                    Dim tbFrom As New TextBox()
                    tbFrom.ID = "tb" + columnBinding + "From"
                    container.Controls.Add(tbFrom)
                    Dim tbTo As New TextBox()
                    tbTo.ID = "tb" + columnBinding + "From"
                    container.Controls.Add(tbTo)
                ElseIf ctrlType = "TextBox" Then
                    Dim tb As New TextBox
                    tb.ID = "tb" + columnBinding
                    tb.MaxLength = length
                    container.Controls.Add(tb)
                ElseIf ctrlType = "CheckBox" Then
                    Dim cb = New CheckBox()
                    cb.ID = "cb" + columnBinding
                    container.Controls.Add(cb)
                ElseIf ctrlType = "DropDownList" Then
                    Dim ddl = New DropDownList()
                    ddl.ID = "ddl" + columnBinding
                    AddControl(ddl, container)
                End If
                Exit Select

            Case Else
                Exit Select
        End Select
    End Sub

    Private Sub AddControl(ctrl As Control, container As Control)
        AddHandler ctrl.DataBinding, AddressOf OnDataBinding
        container.Controls.Add(ctrl)
    End Sub

    Private Sub OnDataBinding(ByVal sender As Object, ByVal e As EventArgs)
        If sender.GetType = GetType(Label) Then
            Dim lb As Label = DirectCast(sender, Label)
            Dim container As GridViewRow = DirectCast(lb.NamingContainer, GridViewRow)
            lb.Text = DataBinder.Eval(container.DataItem, columnBinding).ToString

        ElseIf sender.GetType = GetType(TextBox) Then
            Dim tb As TextBox = DirectCast(sender, TextBox)
            Dim container As GridViewRow = DirectCast(tb.NamingContainer, GridViewRow)
            tb.Text = DataBinder.Eval(container.DataItem, columnBinding).ToString

        ElseIf sender.GetType = GetType(CheckBox) Then
            Dim cb As CheckBox = DirectCast(sender, CheckBox)
            Dim container As GridViewRow = DirectCast(cb.NamingContainer, GridViewRow)
            cb.Checked = DataBinder.Eval(container.DataItem, columnBinding).ToString

        ElseIf sender.GetType = GetType(DropDownList) Then
            Dim ddl As DropDownList = DirectCast(sender, DropDownList)
            Dim container As GridViewRow = DirectCast(ddl.NamingContainer, GridViewRow)
            If columnBinding = "criticalityRating" Then
                ddl.Items.Add("")
                For i = 1 To 4
                    ddl.Items.Add(i)
                Next
            ElseIf columnBinding = "property_id" Then
                For Each p As PropertyMP In PropertyMPDB.GetProperties
                    ddl.Items.Add(New ListItem(p.propertyMP, p.property_id))
                Next
            End If
            If templateType = DataControlRowType.DataRow Then
                ddl.SelectedValue = DataBinder.Eval(container.DataItem, columnBinding).ToString
            End If
        End If
    End Sub
End Class

The DropDownLists are bound to their own ObjectDataSources and are created in the mark-up.

As I understand, the GridView must be instantiated on every postback in the Page.Init. The Page.Load is to late for creating the gridview as it will not maintain the ViewState and will be impossible to update. However, when I create it on Init, the DropDownLists are not created or DataBound yet, so there is no selected value. I tried populating the DropDownLists on their Inits instead of bining them to the DataSource but it throws a ViewState error when I change the SelectedValue.

When I create the GridView on Load, everything works perfectly, except the most important part, updating...

Can anyone help me with figuring out where do I initialize/bind the GridView/DropDownLists? I have been struggling with this for three days now, getting desperate here :(

Was it helpful?

Solution

Did not find a solution but found a workaround.

The GridView is created OnInit, fields are added on GridView Init. After all of the DropDownLists are DataBound, the ObjectDataSource receives its parameters from the DropDownLists.

There is one DropDownList, which is responsible for the type of Object returned. After I change the SelectedValue, the DropDownList is reinitiated and ObjectDataSource still has the old value and returns the wrong object. This is where the error was - binding GridView with an Object with wrong fields. Instead of this, I used QueryString and did a postback. On the next load, the ObjectDataSource returns the correct object that matches GridView's fields. Everything is smooth from there.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top