带有TemplateFields的Ddynamic GridView - LifeCycle中的混乱

时间:2013-04-09 20:50:29

标签: c# vb.net gridview page-lifecycle templatefield

我有一个动态创建的数据绑定网格视图。数据源基于多个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并在标记中创建。

据我所知,必须在Page.Init中的每个回发中实例化GridView。 Page.Load因创建gridview而迟到,因为它不会维护ViewState,也无法更新。但是,当我在Init上创建它时,DropDownLists尚未创建或DataBound尚未创建,因此没有选定的值。我尝试在他们的Inits上填充DropDownLists而不是将它们绑定到DataSource,但是当我更改SelectedValue时它会抛出ViewState错误。

当我在Load上创建GridView时,一切都很完美,除了最重要的部分,更新......

任何人都可以帮我弄清楚我在哪里初始化/绑定GridView / DropDownLists?我已经三天苦苦挣扎,在这里绝望了:(

1 个答案:

答案 0 :(得分:1)

找不到解决方案但找到了解决方法。

GridView创建OnInit,在GridView Init上添加字段。在所有DropDownLists都是DataBound之后,ObjectDataSource从DropDownLists接收其参数。

有一个DropDownList,它负责返回的Object类型。更改SelectedValue后,重新启动DropDownList,ObjectDataSource仍具有旧值并返回错误的对象。这就是错误所在 - 将GridView绑定到具有错误字段的Object。而不是这个,我使用QueryString并做了一个回发。在下一次加载时,ObjectDataSource返回与GridView字段匹配的正确对象。从那里一切都很顺利。