Ddynamic GridView с TemplateFields - путаница в LifeCycle

У меня есть сетка с привязкой к данным, которую я создаю динамически. Источник данных возвращает объект на основе нескольких DropDownLists (типы объектов разные). В зависимости от типа объекта GridView должен отображать определенные поля, специфичные только для объекта. Кроме того, существует DropDownList, SelectedValue которого определяет, какие столбцы объекта будут добавлены / исключены из GridView.

Вот метод, который создает GridView (я пишу на VB.NET, но C # тоже очень приветствуется):

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

GridView всегда находится в режиме редактирования, то есть ItemTemplate является TexBox / DropDownList / CheckBox. Вот класс ITemplate:

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

DropDownLists привязаны к своим собственным ObjectDataSources и создаются в разметке.

Насколько я понимаю, GridView должен создаваться при каждой обратной передаче в Page.Init. Page.Load слишком поздно для создания gridview, поскольку он не будет поддерживать ViewState и его будет невозможно обновить. Однако, когда я создаю его в Init, DropDownLists еще не созданы или DataBound, поэтому нет выбранного значения. Я попытался заполнить DropDownLists в их Inits вместо того, чтобы связывать их с DataSource, но при изменении SelectedValue выдает ошибку ViewState.

Когда я создаю GridView при загрузке, все работает отлично, кроме самой важной части, обновления ...

Может ли кто-нибудь помочь мне выяснить, где мне инициализировать / привязать GridView / DropDownLists? Я уже три дня борюсь с этим, уже отчаялся :(


person Nikita Silverstruk    schedule 09.04.2013    source источник


Ответы (1)


Не нашел решения, но нашел обходной путь.

GridView создается OnInit, поля добавляются в GridView Init. После того, как все DropDownLists являются DataBound, ObjectDataSource получает свои параметры из DropDownLists.

Есть один DropDownList, который отвечает за тип возвращаемого объекта. После изменения SelectedValue DropDownList повторно инициируется, а ObjectDataSource по-прежнему имеет старое значение и возвращает неправильный объект. Вот где была ошибка - привязка GridView к объекту с неправильными полями. Вместо этого я использовал QueryString и сделал обратную передачу. При следующей загрузке ObjectDataSource возвращает правильный объект, который соответствует полям GridView. Оттуда все гладко.

person Nikita Silverstruk    schedule 11.04.2013