DataTable 行索引与绑定到 Gridview 时的顺序不匹配

DataTable row indexes do no match the order when bound to Gridview

提问人:Barnabeck 提问时间:9/1/2023 最后编辑:Barnabeck 更新时间:9/2/2023 访问量:68

问:

我有一个包含不同项目的 Gridview,按整数列“Order”排序。我正在将提供 Gridview 的 DataTable 保存为“会话参数”。

Item        Order      LinkButtons
----------------------------------
Item1         1         up   down
Item2         2         up   down
Item3         3         up   down

这个想法是通过使用 LinkButton 上下移动项目来自定义项目的顺序。

这就是我所做的:

  • 我从 RowClick 事件中获取行索引

    LinkButton lb = (sender as LinkButton);
    string OrderNr = lb.CommandArgument;
    int OrderNummer = Convert.ToInt16(OrderNr);
    GridViewRow row = (GridViewRow)lb.NamingContainer;
    int idx = row.RowIndex;
    
  • 调用 Session 表并更改 Order 参数

    DataTable t = Session["SessionData"] as DataTable;
    t.Rows[idx][1] = Convert.ToString(OrderNummer - 1);
    t.Rows[idx-1][1] = Convert.ToString(OrderNummer);
    
  • 然后,我对 DataTable 重新排序并将其绑定回 Grid

    t.DefaultView.Sort = "OderNr";
    t = t.DefaultView.ToTable();
    

不幸的是,这仅适用于第一次操作。之后,从 t.Rows[idx] 返回的内容对我来说是不可预测的,因为 Gridrow 行索引与 DataTable Row 索引不匹配。

非常混乱


最后,我的解决方案是避免行索引,并使用 CommandArgument “OrderNumber” 在循环中标识 DataTable 行。
    protected void SelectOrderUp(object sender, EventArgs e)
    {
        if (Session["SessionData"] != null)
        {
            LinkButton lb = (sender as LinkButton);
            string OrderNr = lb.CommandArgument;
            int OrderNummer = Convert.ToInt16(OrderNr);

            DataTable t = Session["SessionData"] as DataTable;
            DataRow[] rows = t.Select();

            for (int i = 0; i < rows.Length; i++)
            {
                if (Convert.ToInt16(rows[i][7].ToString()) == OrderNummer)
                {
                    rows[i][7] = Convert.ToString(OrderNummer-1);
                    rows[i - 1][7] = OrderNummer;
                    break;
                }
            }

            t.DefaultView.Sort = "OrderNummer";
            t = t.DefaultView.ToTable();
            Session["SessionData"] = t;

            GridView_Criteria.DataSource = t;
            GridView_Criteria.DataBind();
        }
    }
C# asp.net 会话变量

评论

0赞 jdweng 9/1/2023
网格视图是否有用于添加新行的编辑行?您可能正在对空白编辑行进行排序,这将解释问题。
0赞 Barnabeck 9/1/2023
不,网格中没有编辑模式。

答:

1赞 Shahram Alemzadeh 9/2/2023 #1

在 C# 中没有影响,代码可能需要优化/微调。

aspx的

<asp:GridView ID="GridView1" runat="server">
    <Columns>
        <asp:TemplateField ShowHeader="false">
            <ItemTemplate>
                <asp:LinkButton ID="Btn_UP" runat="server" Text="UP" CommandArgument='<%# Eval("Order") %>' OnCommand="Btn_UP_Command"></asp:LinkButton>
                <asp:LinkButton ID="Btn_DN" runat="server" Text="Down" CommandArgument='<%# Eval("Order") %>' OnCommand="Btn_DN_Command"></asp:LinkButton>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Page_Load

if (!IsPostBack)
{
    GridView1.DataSource = Get_DataTable();
    GridView1.DataBind();
}

Get_DataTable

public DataTable Get_DataTable()
{
    if (Session["dt"] == null)
    {
        DataTable dt = new DataTable();
        dt.Columns.Add("Item", typeof(string));
        dt.Columns.Add("Order", typeof(int));
        for (int i = 1; i <= 10; i++)
            dt.Rows.Add($"Item {i}", i);
        return dt;
    }
    else
        return (DataTable)Session["dt"];
}

Btn_UP_Command

DataTable dt = Get_DataTable();
int order = int.Parse(e.CommandArgument.ToString());
if (order == 1)
    return;
dt.Select($"Order={order}")[0]["Order"] = -1;
dt.Select($"Order={order - 1}")[0]["Order"] = order;
dt.Select("Order=-1")[0]["Order"] = order - 1;
dt.DefaultView.Sort = "Order";
Session["dt"] = dt.DefaultView.ToTable();
GridView1.DataSource = dt;
GridView1.DataBind();

Btn_DN_Command

DataTable dt = Get_DataTable();
int order = int.Parse(e.CommandArgument.ToString());
if (order == dt.Rows.Count)
    return;
dt.Select($"Order={order}")[0]["Order"] = -1;
dt.Select($"Order={order + 1}")[0]["Order"] = order;
dt.Select("Order=-1")[0]["Order"] = order + 1;
dt.DefaultView.Sort = "Order";
Session["dt"] = dt.DefaultView.ToTable();
GridView1.DataSource = dt;
GridView1.DataBind();

评论

0赞 Barnabeck 9/2/2023
谢谢Shahram,效果很好!我不熟悉 DataTable 操作的语法,因此我可能会考虑 Albert 的解决方案。你能帮我了解 dt 的语法吗?选择操作。我需要过滤那些没有“order”列值的 dt 行。并非所有记录都可以订购
2赞 Albert D. Kallal 9/2/2023 #2

这里的问题是您使用“默认”视图进行网格绑定。

但默认视图不会更改基表的行索引!!

这导致了 2 种可能的解决方案:

请考虑使用 GridView 中的 dataitem 索引,而不是行索引。

或者,更简单的方法是对基表进行排序。

你可以用这个来做到这一点:

        rstData.DefaultView.Sort = "MyOrder";
        rstData = rstData.DefaultView.ToTable();
        Session["rstData"] = rstData;

注意:在上面非常接近,我们必须将 rstData 表推回 session[],因为我们已经用 重新构建了该表。ToTable(),它实际上是对象的新实例。

因此,这是一个工作示例(我在此示例中包含了 MyOrder 列)。另请记住,行是从 0 开始的,您的示例从 1 开始。在此示例中,“MyOrder”列从 0 开始,而不是从 1 开始。

所以,说这个标记:

<asp:GridView ID="GVHotels" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ID" CssClass="table" 
    Width="45%" >
    <Columns>
        <asp:BoundField DataField="FirstName" HeaderText="FirstName" />
        <asp:BoundField DataField="LastName" HeaderText="LastName" />
        <asp:BoundField DataField="City" HeaderText="City" />
        <asp:BoundField DataField="HotelName" HeaderText="HotelName" />
        <asp:BoundField DataField="Description" HeaderText="Description" />
        <asp:BoundField DataField="MyOrder" HeaderText="Order" />
        <asp:TemplateField>
            <ItemTemplate>
                <asp:Button ID="cmdUp" runat="server" Text="UP"
                    OnClick="cmdUp_Click" CssClass="btn" />
            </ItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField>
            <ItemTemplate>
                <asp:Button ID="cmdDown" runat="server" Text="Down"
                    OnClick="cmdDown_Click" CssClass="btn" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

以及背后的代码:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            string strSQL = @"SELECT * FROM tblHotelsA
                        WHERE Active = 1";

            rstData = General.MyRst(strSQL);
            LoadGrid();
        }
        else
            rstData = (DataTable)Session["rstData"];
    }

    void LoadGrid()
    {
        rstData.DefaultView.Sort = "MyOrder";
        rstData = rstData.DefaultView.ToTable();
        Session["rstData"] = rstData;
        GVHotels.DataSource = rstData;
        GVHotels.DataBind();

    }

    protected void cmdUp_Click(object sender, EventArgs e)
    {
        Button btn = (Button)sender;
        GridViewRow gRow = (GridViewRow)btn.NamingContainer;
        int IX = gRow.RowIndex;            
        if (IX > 0)
        {
            rstData.Rows[IX]["MyOrder"] = IX - 1;
            rstData.Rows[IX - 1]["MyOrder"] = IX;
            LoadGrid();
        }
    }

    protected void cmdDown_Click(object sender, EventArgs e)
    {
        Button btn = (Button)sender;
        GridViewRow gRow = (GridViewRow)btn.NamingContainer;
        int IX = gRow.RowIndex;
        if (IX < rstData.Rows.Count - 1)
        {
            rstData.Rows[IX]["MyOrder"] = IX + 1;
            rstData.Rows[IX + 1]["MyOrder"] = IX;
            LoadGrid();
        }
    }

结果是这样的:

enter image description here

评论

0赞 Barnabeck 9/2/2023
非常感谢你,阿尔伯特!很好地解释了让我发疯的问题。