单击按钮时,我需要在datagridview中上移或下移选定的行,但datagridview绑定到一个SQL数据库.起初,我使用了此代码,但出现了错误,因为如果控件绑定到数据,则不可能以编程方式向DataGridview集合添加行.是否可以通过datagridview来组织数据库中行的移动?

private void btnUp_Click(object sender, EventArgs e)
{
    DataGridView dgv = gridTasks;
    try
    {
        int totalRows = dgv.Rows.Count;
        // get index of the row for the selected cell
        int rowIndex = dgv.SelectedCells[ 0 ].OwningRow.Index;
        if ( rowIndex == 0 )
            return;
        // get index of the column for the selected cell
        int colIndex = dgv.SelectedCells[ 0 ].OwningColumn.Index;
        DataGridViewRow selectedRow = dgv.Rows[ rowIndex ];
        dgv.Rows.Remove( selectedRow );
        dgv.Rows.Insert( rowIndex - 1, selectedRow );
        dgv.ClearSelection();
        dgv.Rows[ rowIndex - 1 ].Cells[ colIndex ].Selected = true;
    }
    catch { }
}
private void btnUp_Click(object sender, EventArgs e)
{
    DataGridView dgv = gridTasks;
    try
    {
        int totalRows = dgv.Rows.Count;
        // get index of the row for the selected cell
        int rowIndex = dgv.SelectedCells[ 0 ].OwningRow.Index;
        if ( rowIndex == 0 )
            return;
        // get index of the column for the selected cell
        int colIndex = dgv.SelectedCells[ 0 ].OwningColumn.Index;
        DataGridViewRow selectedRow = dgv.Rows[ rowIndex ];
        dgv.Rows.Remove( selectedRow );
        dgv.Rows.Insert( rowIndex - 1, selectedRow );
        dgv.ClearSelection();
        dgv.Rows[ rowIndex - 1 ].Cells[ colIndex ].Selected = true;
    }
    catch { }
}

推荐答案

如果绑定到SQL数据库意味着DataGridView.DataSource是DataTable,则考虑使用BindingSource.

创建一个窗体级别的BindingSource变量,获取DataTable并将BindingSource.DataSource分配给您的表.

将以下类添加到您的项目中,该类负责通过BindingSource向上/向下移动行.

备注:

在代码中,如果设置了排序顺序,则需要删除它,这在下面的代码中完成.

若要编辑单元格,请双击或F2.

public static class BindingSourceExtensions
{
    /// <summary>
    /// Move row up by one
    /// </summary>
    /// <param name="sender"></param>
    public static void MoveRowUp(this BindingSource sender)
    {
        if (!string.IsNullOrWhiteSpace(sender.Sort))
        {
            sender.Sort = "";
        }

        var newIndex = Convert.ToInt32((sender.Position == 0) ? 
            0 : 
            sender.Position - 1);

        var dt = (DataTable)sender.DataSource;
        DataRow rowToMove = ((DataRowView)sender.Current).Row;
        var newRow = dt.NewRow();

        newRow.ItemArray = rowToMove.ItemArray;
        dt.Rows.RemoveAt(sender.Position);
        dt.Rows.InsertAt(newRow, newIndex);

        dt.AcceptChanges();

        sender.Position = newIndex;

    }

    /// <summary>
    /// Move row down by one
    /// </summary>
    /// <param name="sender"></param>
    public static void MoveRowDown(this BindingSource sender)
    {
        if (!string.IsNullOrWhiteSpace(sender.Sort))
        {
            sender.Sort = "";
        }

        var upperLimit = sender.Count - 1;
        var newIndex = Convert.ToInt32((sender.Position + 1 >= upperLimit) ? 
            upperLimit : 
            sender.Position + 1);

        var dt = (DataTable)sender.DataSource;
        DataRow rowToMove = ((DataRowView)sender.Current).Row;
        var newRow = dt.NewRow();

        newRow.ItemArray = rowToMove.ItemArray;
        dt.Rows.RemoveAt(sender.Position);
        dt.Rows.InsertAt(newRow, newIndex);

        dt.AcceptChanges();

        sender.Position = newIndex;

    }

}

在您的表单中,用于您的向上/向下按钮.

private void upButton_Click(object sender, EventArgs e)
{
    _bindingSource.MoveRowUp();
}

private void downButton_Click(object sender, EventArgs e)
{
    _bindingSource.MoveRowDown();
}

我所做的是将DataGridView.SelectionMode设置为FullRowSelect,如果不设置此项,则在上下移动行时,当前单元格将移动到第一个单元格,这对用户来说可能很奇怪.

注意:要获得当前行数据,只需点击按钮.

var row = ((DataRowView)_bindingSource.Current).Row;

在下面的gif中,前两列通常不会显示,它们仅用于演示目的.我使用第一列将订单保存到数据库表中以持久化订单.

enter image description here

EDIT

对模拟数据的简单使用

public partial class Form1 : Form
{
    private readonly BindingSource _bindingSource = new();
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        DataTable dt = new DataTable();
        dt.Columns.Add(new DataColumn() 
            { ColumnName = "FirstName", DataType = typeof(string) });
        dt.Columns.Add(new DataColumn() 
            { ColumnName = "LastName", DataType = typeof(string) });
        dt.Rows.Add("Karen", "Payne");
        dt.Rows.Add("Anne", "Smith");
        dt.Rows.Add("Jane", "Adams");
        _bindingSource.DataSource = dt;
        dataGridView1.DataSource = _bindingSource;
    }

    private void upButton_Click(object sender, EventArgs e)
    {
        _bindingSource.MoveRowUp();
    }

    private void downButton_Click(object sender, EventArgs e)
    {
        _bindingSource.MoveRowDown();
    }

    private void currentButton_Click(object sender, EventArgs e)
    {
        var row = ((DataRowView)_bindingSource.Current).Row;
        var name = $"{row.Field<string>("FirstName")} " +
                   $"row.Field<string>(\"FirstName\")}}";
    }
}

To persist row position

请参阅以下针对名为OrderDetails表的SQL.将添加该列并设置所有现有行的初始值.

运行此查询以添加新列

IF EXISTS
(
    SELECT *
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'OrderDetails'
          AND COLUMN_NAME = 'RowPosition'
)
BEGIN
    ALTER TABLE dbo.OrderDetails DROP COLUMN RowPosition;
END;

ALTER TABLE dbo.OrderDetails ADD RowPosition INT NULL;

然后运行此查询以填充值

UPDATE dbo.OrderDetails
SET @MaxSurrogateKey=RowPosition = @MaxSurrogateKey + 1
WHERE RowPosition IS NULL;

这给出了如何使用Dapper运行它们的 idea ,其中SqlStatements类具有上面的SQL.

public class Operations
{
    private readonly IDbConnection _cn = 
        new SqlConnection(DataConnections.Instance.MainConnection);

    public async Task ConfigureOrderDetailsForRowPosition()
    {
        await _cn.ExecuteAsync(SqlStatements.OrderDetailsConfiguration);
        await _cn.ExecuteAsync(SqlStatements.OrderDetailsPopulateRowPosition,
            new { MaxSurrogateKey = 0 });
    }
}

然后,在更新行位置的代码中,编写代码对DataTable中的每一行执行UPDATE语句.

注:我在微软TechNet上有一篇文章,但在这里发布链接并不是一个好主意,因为该网站将在两个月后关闭,

Csharp相关问答推荐

在Linq中调用需要limit和offset的方法''''

System. InvalidOperationException:无法将数据库中的字符串值i转换为映射的ItemType枚举中的任何值''''

Entity Framework Core 8 dbcontext—无法以多对多关系添加某些行'

如何阻止注释被包含在C#release build. exe中

将XPS转换为PDF C#

如何定义EFCore中的多个穿透

如何将不同类型的扩展参数的javascript函数转换成C#风格?

将现有字段映射到EFCore中的复杂类型

在.NET核心项目中创建Startup.cs比在Program.cs中注册服务好吗?

为什么无法将对象转换为泛型类型

如何实现有条件的自定义Json转换器隐藏属性

C#LINQ子字符串

工厂类是如何在.NET 8中注册的?

Linq SELECT的多条指令

并发表更新.EF核心交易

SignalR跨域

使用本地公共PEM文件加密字符串,使用Azure KayVault中的私钥解密

单位中快照的倾斜方向

使用ImmutableList时,DynamicData未按预期工作

XmlSerializer在遇到XML属性(命名空间)时崩溃