为什么我的 GridView FooterRow 引用了错误的行?
我有一个 GridView,并且使用相当常见的方法,我使用 FooterRow 和 TemplateFields 来提供缺少的插入功能。到目前为止,一切都很好。
页脚包含一个带有 LinkButton 的 TemplateField,用于提供执行插入操作的回发。在 LinkButton 单击的处理程序中,对 GridView 绑定到的 ObjectDataSource 调用 Insert() 方法。 ObjectDataSource 的插入参数填充在其 Inserting 事件的处理程序中。所有这些的代码(已删节)如下所示:
标记:
<asp:GridView ID="gvComplexRates" runat="server" AutoGenerateColumns="False"
DataKeyNames="id" DataSourceID="odsComplexMileageRates"
EnableModelValidation="True" ShowFooter="True">
<Columns>
<asp:TemplateField ShowHeader="False">
:
:
<FooterTemplate>
<asp:LinkButton ID="addLinkButton" runat="server" CausesValidation="false"
CommandName="Insert" Text="Add"></asp:LinkButton>
</FooterTemplate>
</asp:TemplateField>
:
:
</asp:GridView>
代码隐藏:
Private Sub gvComplexRates_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles gvComplexRates.RowCommand
Select Case e.CommandName
Case "Insert"
odsComplexMileageRates.Insert()
End Select
End Sub
Private Sub odsComplexMileageRates_Inserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceMethodEventArgs) Handles odsComplexMileageRates.Inserting
Dim fuelTypeDropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddFuelTypeInsert")
Dim engineTypeDropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddEngineTypeInsert")
Dim rateTextBox As TextBox = gvComplexRates.FooterRow.FindControl("tbRateInsert")
Dim vatRateTextBox As TextBox = gvComplexRates.FooterRow.FindControl("tbVatRateInsert")
e.InputParameters("expense_type_id") = ddExpenseTypeSelect.SelectedValue
e.InputParameters("fuel_type_id") = fuelTypeDropDown.SelectedValue
e.InputParameters("engine_type_id") = engineTypeDropDown.SelectedValue
e.InputParameters("rate") = rateTextBox.Text
e.InputParameters("vat_rate") = vatRateTextBox.Text
End Sub
我的 FooterRow
中的两个字段是从其他表填充的 DropDownLists
。同样,这工作正常,我可以毫无问题地添加、编辑和删除行。
当我使用此页面中的模式对话框将额外的行插入到用于填充 FooterRow
中的 DropDownLists
的表中时,问题就出现了。插入操作工作正常,模式对话框关闭,此时我使用 javascript 回发(基本上是对 __doPostBack()
的调用),以便我的 FooterRow
DropDownLists
可以更新。其代码是:
Protected Sub updateFuelEngineDropdowns()
odsFuelTypes.Select()
odsEngineTypes.Select()
Dim dropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddFuelTypeInsert")
dropDown.DataBind()
dropDown = gvComplexRates.FooterRow.FindControl("ddEngineTypeInsert")
dropDown.DataBind()
End Sub
这个子 updateFuelEngineDropdowns()
是从 Page Load 事件中调用的。我第一次调用它时效果很好。由于某种原因,在调试器的后续运行中,我收到了 NullReferenceExceptions。深入研究调试对象查看器,很明显 GridView
FooterRow
正在引用页脚上方不包含控件的行(至少在这个非编辑阶段)并且所以,相当合理地,给了我空引用。
我使用的调试 QuickView 表达式是:gvComplexRates.FooterRow.Controls(3)
DirectCast(gvComplexRates.FooterRow.Controls(3),System.Web.UI.WebControls.DataControlFieldCell).Controls(1)
其中第一个显示 td
标记。这是有道理的。第二个显示文本“10”,它是页脚上方行的内容。
有谁知道为什么会发生这种情况?
谢谢丹
I have a GridView
and, using a fairly common method, I'm using a FooterRow
and TemplateFields
to provide the missing insert ability. So far so good.
The footer contains a TemplateField with a LinkButton to provide the postback that does the insertion. In the handler for the LinkButton's click, the Insert() method is called on the ObjectDataSource that the GridView is bound to. The ObjectDataSource's insert parameters are populated in the handler for its Inserting event. The code for all of this (abridged) looks like this:
Markup:
<asp:GridView ID="gvComplexRates" runat="server" AutoGenerateColumns="False"
DataKeyNames="id" DataSourceID="odsComplexMileageRates"
EnableModelValidation="True" ShowFooter="True">
<Columns>
<asp:TemplateField ShowHeader="False">
:
:
<FooterTemplate>
<asp:LinkButton ID="addLinkButton" runat="server" CausesValidation="false"
CommandName="Insert" Text="Add"></asp:LinkButton>
</FooterTemplate>
</asp:TemplateField>
:
:
</asp:GridView>
Code Behind:
Private Sub gvComplexRates_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles gvComplexRates.RowCommand
Select Case e.CommandName
Case "Insert"
odsComplexMileageRates.Insert()
End Select
End Sub
Private Sub odsComplexMileageRates_Inserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceMethodEventArgs) Handles odsComplexMileageRates.Inserting
Dim fuelTypeDropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddFuelTypeInsert")
Dim engineTypeDropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddEngineTypeInsert")
Dim rateTextBox As TextBox = gvComplexRates.FooterRow.FindControl("tbRateInsert")
Dim vatRateTextBox As TextBox = gvComplexRates.FooterRow.FindControl("tbVatRateInsert")
e.InputParameters("expense_type_id") = ddExpenseTypeSelect.SelectedValue
e.InputParameters("fuel_type_id") = fuelTypeDropDown.SelectedValue
e.InputParameters("engine_type_id") = engineTypeDropDown.SelectedValue
e.InputParameters("rate") = rateTextBox.Text
e.InputParameters("vat_rate") = vatRateTextBox.Text
End Sub
Two of the fields in my FooterRow
are DropDownLists
that are populated from other tables. Again this works fine and I can add, edit and remove rows without problem.
The problem comes when I use a modal dialog from this page to insert extra rows into the tables used to populate the DropDownLists
in the FooterRow
. The insert operations work fine and the modal dialog closes and at this point I use a javascript postback (basically a call to __doPostBack()
) so that my FooterRow
DropDownLists
can be updated. The code for this is:
Protected Sub updateFuelEngineDropdowns()
odsFuelTypes.Select()
odsEngineTypes.Select()
Dim dropDown As DropDownList = gvComplexRates.FooterRow.FindControl("ddFuelTypeInsert")
dropDown.DataBind()
dropDown = gvComplexRates.FooterRow.FindControl("ddEngineTypeInsert")
dropDown.DataBind()
End Sub
This sub, updateFuelEngineDropdowns()
, is called from the Page Load event. The first time I called it it worked fine. For some reason in subsequent runs through the debugger I'm getting NullReferenceExceptions
. Digging into the debug object viewer it is apparent that the GridView
FooterRow
is referencing the row above the footer which contains no controls (at least not at this non-editing stage) and so, quite reasonably, gives my the Null reference.
The debug QuickView expressions I use are:gvComplexRates.FooterRow.Controls(3)
DirectCast(gvComplexRates.FooterRow.Controls(3),System.Web.UI.WebControls.DataControlFieldCell).Controls(1)
The first of these shows a tag of td
. Which makes sense. The second shows text of "10" which is the content for the row above the footer.
Does anybody know why this is happening?
Thanks Dan
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你在哪里“提供缺失的插入能力”?
您必须在每次回发时重建页脚控件,GridView.RowCreated-Event 将是一个好地方。
更新:
将新行插入下拉列表后,必须对 GridView 进行数据绑定。
Where are you "providing the missing insert ability"?
You have to rebuild the footer-controls on every postback, the GridView.RowCreated-Event would be a good place.
Update:
You have to Databind your GridView after you inserted new rows into your Dropdowns' Tables.
没错,这有点尴尬。我在最初的问题中撒了一个善意的谎言。通过遗漏而不是故意误导。事实上,我没有使用 GridView,而是它的子类,当数据源不包含数据时,它将显示行。这使得用户能够在表为空时插入新行。这个子类重写了
FooterRow
属性,令我羞愧的是,正是这个导致了错误。所以我在这里犯了两个错误:首先,我未能正确测试我的 GridView 子类;其次,我试图通过不在我包含的代码片段中显示它的使用来防止我认为对我的子类产生不必要的关注在问题中。我的不好。感谢蒂姆花时间尝试帮助我。担
Right, this is a bit embarrassing. I gave a little white lie in the original question. By omission rather than a deliberate attempt to mislead. I am not, in fact, using a
GridView
but a subclass of it that will display rows when thedatasource
contains no data. This enables the user to insert new rows when the table is empty. This subclass overrides theFooterRow
property and, to my shame, it was this that was getting things wrong. So I made two errors here: first I failed to test myGridView
subclass properly and second I sought to prevent what I thought would be unnecessary attention on my subclass by not showing its use in the code snippets I included in the question. My bad. Thanks to Tim for taking the time to try and help me.Dan