【问题标题】:Gridview why all visible rows are set to dirty?Gridview 为什么所有可见行都设置为脏?
【发布时间】:2011-04-29 20:14:35
【问题描述】:

我正在使用 http://roohit.com/site/showArc.php?shid=bbb62 所讨论的 BulkEditGridView 控件,它非常适合我的需求。我遇到的问题是,每当我保存时,每个可见行(我启用了分页)都会更新。单步执行代码,我看到 grid.DirtyRows.Count 等于单击保存按钮时每页的项目数减 1。

我找不到将行设置为脏的位置。有什么建议可以看吗?

我的代码隐藏只有这个:

using System;
using System.Web.UI.WebControls;
using System.Collections.Generic;
using System.Collections;
using System.Data.Common;

public partial class MSDS_MSDS_Admin_GridUpdate : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            gridMSDS.DataKeyNames = new String[] { "id" };
            gridMSDS.DataBind();
        }
    }
}

编辑:这是 aspx 代码。

<%@ Page Language="C#" MasterPageFile="~/MSDS/MSDS.master" AutoEventWireup="true" EnableEventValidation="false" CodeFile="GridUpdate.aspx.cs" Inherits="MSDS_MSDS_Admin_GridUpdate" Title="Untitled Page" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<%@ Register Assembly="RealWorld.Grids" Namespace="RealWorld.Grids" TagPrefix="cc2" %>
<asp:Content ID="Content1" ContentPlaceHolderID="PageContent" runat="Server">
    <br />
    <asp:Button ID="btnSave" runat="server" Text="Save" Width="100%" />
    <cc2:BulkEditGridView ID="gridMSDS" runat="server" AllowPaging="True" AllowSorting="True"
        DataSourceID="sqlData" EnableInsert="False" InsertRowCount="1" PageSize="20"
        SaveButtonID="btnSave" AutoGenerateColumns="False">
        <Columns>
            <asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" Visible="false"
                ReadOnly="True" SortExpression="ID" />
            <asp:BoundField DataField="ChemicalTitle" HeaderText="ChemicalTitle" SortExpression="ChemicalTitle" />
            <asp:TemplateField HeaderText="SheetDate" SortExpression="SheetDate">
                <EditItemTemplate>
                    <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("SheetDate") %>' Width="85px"></asp:TextBox>
                    <cc1:CalendarExtender ID="TextBox1_CalendarExtender" runat="server" Enabled="True"
                        TargetControlID="TextBox1">
                    </cc1:CalendarExtender>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:Label ID="Label2" runat="server" Text='<%# Eval("SheetDate") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:BoundField DataField="Filename" HeaderText="Filename" SortExpression="Filename" />
            <asp:BoundField DataField="Manufacturer" HeaderText="Manufacturer" SortExpression="Manufacturer" />
            <asp:BoundField DataField="UsageDept" HeaderText="UsageDept" SortExpression="UsageDept" />
            <asp:TemplateField HeaderText="Notes" SortExpression="Notes">
                <EditItemTemplate>
                    <asp:TextBox ID="TextBox5" runat="server" Text='<%# Bind("Notes") %>' TextMode="MultiLine"></asp:TextBox>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:Label ID="Label6" runat="server" Text='<%# Bind("Notes") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Status" SortExpression="Status">
                <EditItemTemplate>
                    <asp:DropDownList ID="ddlStatus" runat="server" DataSourceID="sqlStatus" DataTextField="DisplayValue"
                        DataValueField="Value" SelectedValue='<%# Bind("Status") %>'>
                    </asp:DropDownList>
                    <asp:SqlDataSource ID="sqlStatus" runat="server" ConnectionString="<%$ ConnectionStrings:NCLWebConnectionString %>"
                        SelectCommand="getOptionList" SelectCommandType="StoredProcedure">
                        <SelectParameters>
                            <asp:Parameter DefaultValue="msds_Status" Name="ListName" Type="String" />
                        </SelectParameters>
                    </asp:SqlDataSource>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:DropDownList ID="ddlStatus" runat="server" DataSourceID="sqlStatus" disabled="true"
                        BackColor="White" DataTextField="DisplayValue" DataValueField="Value" SelectedValue='<%# Bind("Status") %>'>
                    </asp:DropDownList>
                    <asp:SqlDataSource ID="sqlStatus" runat="server" ConnectionString="<%$ ConnectionStrings:NCLWebConnectionString %>"
                        SelectCommand="getOptionList" SelectCommandType="StoredProcedure">
                        <SelectParameters>
                            <asp:Parameter DefaultValue="msds_Status" Name="ListName" Type="String" />
                        </SelectParameters>
                    </asp:SqlDataSource>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Health" SortExpression="Health">
                <EditItemTemplate>
                    <center>
                        <asp:TextBox ID="TextBox2" runat="server" Style="text-align: center" Text='<%# Bind("Health") %>'
                            Width="25px"></asp:TextBox>
                    </center>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:Label ID="Label3" runat="server" Text='<%# Bind("Health") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Fire" SortExpression="Fire">
                <EditItemTemplate>
                    <center>
                        <asp:TextBox ID="TextBox3" runat="server" Text='<%# Bind("Fire") %>' Width="25px"></asp:TextBox></center>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:Label ID="Label4" runat="server" Text='<%# Bind("Fire") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Reactivity" SortExpression="Reactivity">
                <EditItemTemplate>
                    <center>
                        <asp:TextBox ID="TextBox4" runat="server" Text='<%# Bind("Reactivity") %>' Width="25px"></asp:TextBox></center>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:Label ID="Label5" runat="server" Text='<%# Bind("Reactivity") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:BoundField DataField="DateUpdated" HeaderText="DateUpdated" SortExpression="DateUpdated"
                ReadOnly="True" />
            <asp:BoundField DataField="UpdatedBy" ReadOnly="True" HeaderText="UpdatedBy" SortExpression="UpdatedBy" />
        </Columns>
    </cc2:BulkEditGridView>
    <asp:SqlDataSource ID="sqlData" runat="server" ConnectionString="<%$ ConnectionStrings:NCLWebConnectionString %>"
        SelectCommand="SELECT [ID], [ChemicalTitle], dbo.dateOnly([SheetDate]) As [SheetDate], [Filename], [Manufacturer], [UsageDept], [Notes], isnull([Status], 4) as [Status], [Health], [Fire], [Reactivity], [DateUpdated], [UpdatedBy] FROM [msds_Sheets] ORDER BY [ChemicalTitle]"
        UpdateCommand="msds_UpdateSheet" UpdateCommandType="StoredProcedure">
        <UpdateParameters>
            <asp:Parameter Name="ID" Type="Int32" />
            <asp:Parameter Name="ChemicalTitle" Type="String" />
            <asp:Parameter Name="SheetDate" DbType="DateTime" />
            <asp:Parameter Name="Filename" Type="String" />
            <asp:Parameter Name="Manufacturer" Type="String" />
            <asp:Parameter Name="UsageDept" Type="String" />
            <asp:Parameter Name="Notes" Type="String" />
            <asp:Parameter Name="Status" Type="Int16" />
            <asp:Parameter Name="Health" Type="Int16" />
            <asp:Parameter Name="Fire" Type="Int16" />
            <asp:Parameter Name="Reactivity" Type="Int16" />
            <asp:ProfileParameter Name="UpdatedBy" Type="String" PropertyName="Username" />
        </UpdateParameters>
    </asp:SqlDataSource>
</asp:Content>

测试程序如下:
- 加载页面。
- 编辑第一行的内容。
- 点击保存按钮。

【问题讨论】:

  • 看看这篇文章有没有帮助onthefencedevelopment.com/?p=68
  • 网格视图中的脏行有问题,而不是整个页面都被标记为脏。
  • 我无法复制这种行为,即使启用了分页。 (即它只更新我更改的行。)你能发布你的BulkEditGridView标签及其属性吗?另外,您也可以发布与寻呼机相关的任何内容吗?
  • 我做了一些额外的测试,包括SheetData 字段和CalendarExtender。我已经尝试了很多东西,您的代码对我来说运行良好。几个问题:(1)你的btnSave_Click是做什么的?不需要保存,因为 BEGV 控件会为您执行此操作。 (2) 即使您什么也不编辑,这些行是否会像脏一样回来? (即只需按Save),(3)您的测试顺序是什么? (即在按下Save 之前,给我一些关于你做什么、分页等的详细信息),(4)页面上是否有任何脚本(ToolkitScriptManager 添加的脚本除外)?谢谢
  • 我仍然无法让它崩溃,所以我们需要弄清楚我的代码/环境和你的有什么不同。如果是我,我会:(1)创建一个新的虚拟母版页,并让您的页面引用它。 (2) 将SheetDateTemplateField 注释掉,并将其替换为BoundField。 (你需要这个,因为我不认为你的CalendarExtender 没有你的母版页,显然有ToolKitScriptManager。)

标签: c# asp.net gridview sqldatasource


【解决方案1】:

您发布的代码看起来不错。我的测试代码与您的几乎相同,但我无法产生您所看到的不需要的结果。

您的代码和我的代码之间最显着的区别是我没有您的母版页的代码。我的母版页是 VS 2008 创建的默认页面。除此之外,不同之处在于 SQL 和底层数据库。具体来说,我没有使用任何存储过程,并且我对所涉及的数据类型做出了合理的假设:IDintStatussmallintSheetDateDateDateUpdatedDateTime,其他都是varchar

编辑:您的SheetDate 似乎只是数据库中基础DateTime 值的日期部分。您的查询为了显示目的而转换基础数据值这一事实并不相关,因为网格视图无法判断它正在获取修改后的值。 编辑结束

以下是一些诊断问题的建议:

  • 在没有母版页的情况下进行测试,或者使用 非常简单的虚拟母版页 保证没有脚本 与BulkEditGridView 互动。 由于ToolkitScriptManager 是 显然在您的母版页上,您将 需要移动脚本 管理器控制页面本身, 否则暂时摆脱 CalendarExtender 元素,其中 需要脚本管理器。

  • 暂时替换Status 带有绑定数据的模板字段 场,以消除可能 与DropDownList 互动。 下拉列表没有导致 我的测试中有问题,但可能有 是你之间的细微差别 代码和我的。

  • 如果这些都没有帮助,那么可能的原因是您的 BulkEditGridView 的版本。

编辑 - 其他诊断建议:

  • 根据对BulkEditGridView 源代码的检查,该代码似乎正确地跟踪了网格中哪些行是“脏的”。因此,虚假脏行最可能的原因是网格中的一个或多个控件错误地检测到其数据内容的更改。您可以在调试器中检测到这一点,使用 BulkEditGridView 的源代码,而不是预编译的 DLL。

  • HandleRowChanged 的开头设置断点,该事件处理程序检测网格中任何单元格的变化。通过在调试器中检查该对象的sender 参数,您可以知道网格中的哪些控件正在发生值更改。特别是,您将能够判断哪些控件(如果有)错误地触发了值更改事件。

  • 一旦您确定哪些控件错误地报告其值已更改,您就可以关注为什么会发生这种情况。

编辑结束

其他一些改进代码的建议如下。 这些不会解决原来的问题,但会让代码更干净:

  • 在所有模板字段中,删除ItemTemplates。它们永远不能被使用,因为BulkEditGridView 强制每一行都处于编辑状态。

  • 在后面的代码中,BindData() 不需要调用,因为源 数据在声明中指定 标记,因此是网格视图 控件会自动绑定 数据。

【讨论】:

  • 我可以不试一试,但我相信我在尝试使排序和分页工作时将 databind() 放在那里。此外,可能不需要项目模板。一开始我只是让它们自动生成,然后我改变了一些东西。
  • @MAW - 排序和分页不应该需要数据绑定,因为这需要回发,因此您的数据绑定代码无论如何都不会执行。我有点认为项目模板是自动生成的。在我查看 BEGV 源代码之前,我并不清楚它们是不需要的。
  • SheetDate 实际上是一个日期时间,我使用用户定义的 sql 函数将其截断为一个日期。我尝试替换 RealWorldGridView dll,没有骰子。我还尝试在内容页面上添加一个 scriptmanagerproxy,没有骰子。
  • 您必须使用源代码,而不是预编译的 dll。有几种方法可以做到这一点。
  • 我不知所措,因为我无法复制它。如果您只在查询中返回sheetDate,而不调用dbo.dateOnly,请查看代码是否有效。我在这里用完整的DateTime 值尝试了我的代码,它工作正常。我看不出截断日期会有什么不同,但这是我的代码和你的代码之间唯一的显着区别。我会尝试在午餐时间查看回复。
【解决方案2】:

我不是 BulkEditGridView 控件方面的专家,但这是我在 Matt Dotson 的 blog entry 中发现的

除非您明确注意更改,否则您可能无法知道该行已更新。首先,为每一行添加一个更改处理程序

protected override void InitializeRow(GridViewRow row, DataControlField[] fields)
   {
      base.InitializeRow(row, fields);
      foreach (DataControlFieldCell cell in row.Cells)
      {
         if (cell.Controls.Count > 0)
         {
            AddChangedHandlers(cell.Controls);
         }
      }
   }

你可以用这个sn-p

private void AddChangedHandlers(ControlCollection controls)
   {
      foreach (Control ctrl in controls)
      {
         if (ctrl is TextBox)
         {
            ((TextBox)ctrl).TextChanged += new EventHandler(this.HandleRowChanged);
         }
         else if (ctrl is CheckBox)
         {
            ((CheckBox)ctrl).CheckedChanged += new EventHandler(this.HandleRowChanged);
         }
         else if (ctrl is DropDownList)
         {
            ((DropDownList)ctrl).SelectedIndexChanged += new EventHandler(this.HandleRowChanged);
         }
      }
   }

然后你定义一个脏行列表并在那里添加需要更新的行(在事件处理程序中)

   private List<int> dirtyRows = new List<int>();
   void HandleRowChanged(object sender, EventArgs args)
   {
      GridViewRow row = ((Control) sender).NamingContainer as GridViewRow;
      if (null != row && !dirtyRows.Contains(row.RowIndex))
      {
         dirtyRows.Add(row.RowIndex);
      }
   }

最后,要提交更改,遍历所有脏行并保存更改

   public void Save()
   {
      foreach (int row in dirtyRows)
      {
         this.UpdateRow(row, false);
      }

      dirtyRows.Clear();
   }

这是你的 ASPX 代码

<asp:Button runat="server" ID="SaveButton" Text="Save Data" />
   <blog:BulkEditGridView runat="server" id="EditableGrid" DataSourceID="AdventureWorks" AutoGenerateColumns="False" DataKeyNames="LocationID" SaveButtonID="SaveButton" >
      <Columns>
         <asp:BoundField DataField="LocationID" HeaderText="LocationID" InsertVisible="False" ReadOnly="True" SortExpression="LocationID" />
         <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
         <asp:BoundField DataField="Availability" HeaderText="Availability" SortExpression="Availability" />
         <asp:BoundField DataField="CostRate" HeaderText="CostRate" SortExpression="CostRate" />
      </Columns>
   </blog:BulkEditGridView>

【讨论】:

  • 我看到了,但是查看控件的源代码,这些都是控件内置的。赠品是 this.、base. 和 override 的使用。这是让我感到困惑的部分原因。
  • 这似乎是 BulkEditGridView 控件本身的代码,所以理论上只需要调用 Save 方法即可。我在您的代码中看不到您实际上调用了 Save,是吗?
  • 他的文章说不需要。他为提供良好的开发人员体验感到非常自豪。我会看看有什么不同。
  • 显式调用 Save() 无效;
  • @MAW74656 - 你是对的。当单击Save 按钮时,Save() 由控件在内部调用。再次单击它不会执行任何操作,因为 save 方法会清除 dirtyRows 列表(请参阅此答案中的上述代码)。
猜你喜欢
  • 2015-10-02
  • 2021-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多