C# - 如何使用单击按钮将数据从 dataGridView1 传递到另一个?
C# - How to pass the data from dataGridView1 to another using a button click?
我有一个 dataGridView1
、dataGridView2
和一个 ButtonAdd
在一个表格中。
用户将:
1- select 任何一个 "Cell" 或 "entire Row".
2-select 多行
然后:
单击按钮时,数据 selected 将从 dataGridView1 移动到 dataGridView2。这就是我需要做的。
我的尝试:
经过多次搜索,我尝试了这个解决方案,它几乎完成了,但有一个小问题我无法处理:
完整代码:
private const string strconneciton = @"YourConnectionString";
SqlConnection con = new SqlConnection(strconneciton);
SqlCommand cmd = new SqlCommand();
DataTable dataTable;
private void loadDataIntoGridView1()
{
try
{
con.Open();
cmd.CommandText = "SELECT id, accNum, accName FROM Employees";
cmd.Connection = con;
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = cmd;
dataTable = new DataTable();
adapter.Fill(dataTable);
BindingSource bSource = new BindingSource();
bSource.DataSource = dataTable;
dataGridView1.DataSource = bSource;
//i don't know if this line is useful...
dataGridView2.DataSource = dataTable.Clone();
adapter.Update(dataTable);
con.Close();
}
catch (Exception ed)
{
con.Close();
MessageBox.Show(ed.Message);
}
}//end loadDataIntoGridView1
private void buttonSend_Click(object sender, EventArgs e)
{
if (dataGridView1.SelectedCells.Count > 0)
{
foreach (DataGridViewCell oneCell in dataGridView1.SelectedCells)
{
if (oneCell.Selected)
{
//this should add the rows that is selected from dataGridView1 and,
//pass it to dataGridView2
var currentRow = ((DataRowView)dataGridView1.CurrentRow.DataBoundItem).Row;
((DataTable)dataGridView2.DataSource).ImportRow(currentRow);
//this will remove the rows you have selected from dataGridView1
dataGridView1.Rows.RemoveAt(oneCell.RowIndex);
}//end if
}//end foreach
}//end if
}//end button click
让我们调试:
只是注意开始前的一件事:
- 删除行(多行或单行)的方法在所有情况下都工作正常。
- 添加到 DGV2 的方法是问题所在,我从 here 中获取它...当 select 是单行而不是多行时,它工作正常。
1- 如果您 select 编辑了一个 cell/row 它将被成功添加和删除。
2- 如果你 select 编辑了多行,比如第一行和第二行,它会添加第二行和第三行,然后肯定会删除它们,但只添加了一行..
为什么?!
因为这里
var currentRow = ((DataRowView)dataGridView1.CurrentRow.DataBoundItem).Row;
((DataTable)dataGridView2.DataSource).ImportRow(currentRow);
获取 DGV1 中 现有行 的当前索引并迭代到 selecting 行的数量并将它们添加到 DGV2。
截图:
该过程如何完成的图片:
.
我需要做什么:
应该如何解决这个问题?
而不是
ImportRow(currentRow)
使用这样的东西:
table.Rows.Add(currentRow);
如果可行,请告诉我!
虽然 marco 有一点,但该行的所有权属于 table 作为抛出的异常。要绕过这个,你可能想这样做......
// 根据您即将创建的 table 创建一个新行
// 插入具有相同结构的 INTO
var copyRow = table.NewRow();
copyRow.ItemArray = currentRow.ItemArray;
table.Rows.Add( copyRow );
ItemArray 是 table 的所有列属性的列表,没有显式引用行 ["someColumn"]。因此,将数组复制到新行可以获得所有列。这是 - 如果两个 table 结构相同 - 并且似乎来自您提供的场景。
澄清
上面的代码只做一行,将根据你的循环应用
if (oneCell.Selected)
您每行选择了多列,因此导致您的循环有些混乱。您实际上多次点击同一行。无论如何,我发现您实际上是在 Windows 应用程序而不是 WPF 中执行此操作。我创建了一个表单并在下面发布了代码。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
loadDataIntoGridView1();
}
public DataTable tblFrom { get; set; }
public DataTable tblTo { get; set; }
private void loadDataIntoGridView1()
{
tblFrom = new DataTable();
tblFrom.Columns.Add("Col1", typeof(string));
tblFrom.Columns.Add("Col2", typeof(string));
tblTo = tblFrom.Clone();
DataRow tmp;
while (tblFrom.Rows.Count < 20)
{
tmp = tblFrom.NewRow();
tmp["Col1"] = "my row " + tblFrom.Rows.Count;
tmp["Col2"] = "testing";
tblFrom.Rows.Add(tmp);
}
dataGridView1.AutoGenerateColumns = true;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView2.AutoGenerateColumns = true;
dataGridView2.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.DataSource = tblFrom;
dataGridView2.DataSource = tblTo;
}
private void button1_Click(object sender, System.EventArgs e)
{
// if no ROWS selected, get out.
if (dataGridView1.SelectedRows.Count == 0)
return;
foreach( DataGridViewRow vr in dataGridView1.SelectedRows)
{
var currentRow = ((DataRowView)vr.DataBoundItem).Row;
((DataTable)dataGridView2.DataSource).ImportRow(currentRow);
//this will remove the rows you have selected from dataGridView1
dataGridView1.Rows.RemoveAt(vr.Index);
}
}
}
在这里,我有一个表格,有两个类似于你的网格和一个按钮到 "Move" 记录(但只有一个方向),你必须调整一个/所有/从/ 方向。
一些变化。我更改了网格以强制选择模式到整个行。这将防止单行有多个条目,因为您有多个可用列。通过在单元格之间拖动或按住 Ctrl 键并单击各个行,仍然可以进行多项选择。这允许选择不在同一可视屏幕区域内的行。
我也刚刚创建了一个 table 来强制模拟 20 行数据以强制不是所有行都同时可见。
接下来点击事件...如果没有选择行,退出...如果有,则循环,但如果多列,则每行执行一次,而不是多次。获取绑定数据行,导入和删除...
否则你已经很接近了,不需要复制数组。我认为总体问题是您的列模式选择多次击中同一条记录。在第一个单元格的第 0 行的 remove-at 之后,第 1 行成为第 0 行并因此复制它,删除并且您现在不在列表中,因为只剩下一个记录要处理。在这里,无论选择了其中的哪一列,我们都会一次获得整行。
这是执行此操作的完整代码段。
在此示例中,我使用 2 BindingList
来实现您的要求。用户单击该按钮后,示例会将所选项目从 dgv1data
复制到 dgv2data
。然后它将从 dgv1data
.
中删除项目
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
namespace MoveDataBetweenDataGridView_47454256
{
public partial class Form1 : Form
{
static BindingList<dgventry> dgv1data = new BindingList<dgventry>();
static BindingList<dgventry> dgv2data = new BindingList<dgventry>();
DataGridView dgv1 = new DataGridView();
DataGridView dgv2 = new DataGridView();
Button btn = new Button();
public Form1()
{
InitializeComponent();
InitOurStuff();
for (int i = 0; i < 10; i++)
{
dgv1data.Add(new MoveDataBetweenDataGridView_47454256.dgventry
{
col1 = $"col1_{i}", col2 = $"col2_{i}", col3 = $"col3_{i}"});
}
}
private void InitOurStuff()
{
this.Controls.Add(dgv1);//add the DGV to the form
dgv1.DataSource = dgv1data;//bind our data to it
dgv1.Dock = DockStyle.Left;//place the DGV somewhere on the form
this.Controls.Add(dgv2);//add the DGV to the form
dgv2.DataSource = dgv2data;//bind out data to it
dgv2.Dock = DockStyle.Right;//place the DGV somewhere on the form
this.Controls.Add(btn);//add the Button to the form
btn.Dock = DockStyle.Bottom;//place the Button somewhere on the form
btn.Click += Btn_Click;//give the Button a event handler
}
private void Btn_Click(object sender, EventArgs e)
{
List<int> doneIndices = new List<int>();//this will keep track of the row indices we have dealt with
if (dgv1.SelectedCells.Count > 0)//if something is selected
{
foreach (DataGridViewCell item in dgv1.SelectedCells)//loop through the selected cells
{
if (!doneIndices.Contains(item.OwningRow.Index))//if this cell does not belong to a row index we already processed
{
//we haven't done this row yet
dgv2data.Add((dgventry)item.OwningRow.DataBoundItem);//add the DataBoundItem to the other DGV data
doneIndices.Add(item.OwningRow.Index);//put the current row index in our tracking list
}
else
{
//we have done this row already, move on to the next one
continue;
}
}
}
//remove all the duplicate entries
foreach (dgventry item in dgv2data)
{
dgv1data.Remove(item);
}
}
}
public class dgventry
{
public string col1 { get; set; }
public string col2 { get; set; }
public string col3 { get; set; }
}
}
我有一个 dataGridView1
、dataGridView2
和一个 ButtonAdd
在一个表格中。
用户将:
1- select 任何一个 "Cell" 或 "entire Row".
2-select 多行
然后:
单击按钮时,数据 selected 将从 dataGridView1 移动到 dataGridView2。这就是我需要做的。
我的尝试:
经过多次搜索,我尝试了这个解决方案,它几乎完成了,但有一个小问题我无法处理:
完整代码:
private const string strconneciton = @"YourConnectionString";
SqlConnection con = new SqlConnection(strconneciton);
SqlCommand cmd = new SqlCommand();
DataTable dataTable;
private void loadDataIntoGridView1()
{
try
{
con.Open();
cmd.CommandText = "SELECT id, accNum, accName FROM Employees";
cmd.Connection = con;
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = cmd;
dataTable = new DataTable();
adapter.Fill(dataTable);
BindingSource bSource = new BindingSource();
bSource.DataSource = dataTable;
dataGridView1.DataSource = bSource;
//i don't know if this line is useful...
dataGridView2.DataSource = dataTable.Clone();
adapter.Update(dataTable);
con.Close();
}
catch (Exception ed)
{
con.Close();
MessageBox.Show(ed.Message);
}
}//end loadDataIntoGridView1
private void buttonSend_Click(object sender, EventArgs e)
{
if (dataGridView1.SelectedCells.Count > 0)
{
foreach (DataGridViewCell oneCell in dataGridView1.SelectedCells)
{
if (oneCell.Selected)
{
//this should add the rows that is selected from dataGridView1 and,
//pass it to dataGridView2
var currentRow = ((DataRowView)dataGridView1.CurrentRow.DataBoundItem).Row;
((DataTable)dataGridView2.DataSource).ImportRow(currentRow);
//this will remove the rows you have selected from dataGridView1
dataGridView1.Rows.RemoveAt(oneCell.RowIndex);
}//end if
}//end foreach
}//end if
}//end button click
让我们调试:
只是注意开始前的一件事:
- 删除行(多行或单行)的方法在所有情况下都工作正常。
- 添加到 DGV2 的方法是问题所在,我从 here 中获取它...当 select 是单行而不是多行时,它工作正常。
1- 如果您 select 编辑了一个 cell/row 它将被成功添加和删除。
2- 如果你 select 编辑了多行,比如第一行和第二行,它会添加第二行和第三行,然后肯定会删除它们,但只添加了一行.. 为什么?!
因为这里
var currentRow = ((DataRowView)dataGridView1.CurrentRow.DataBoundItem).Row;
((DataTable)dataGridView2.DataSource).ImportRow(currentRow);
获取 DGV1 中 现有行 的当前索引并迭代到 selecting 行的数量并将它们添加到 DGV2。
截图:
该过程如何完成的图片:
我需要做什么:
应该如何解决这个问题?
而不是
ImportRow(currentRow)
使用这样的东西:
table.Rows.Add(currentRow);
如果可行,请告诉我!
虽然 marco 有一点,但该行的所有权属于 table 作为抛出的异常。要绕过这个,你可能想这样做......
// 根据您即将创建的 table 创建一个新行 // 插入具有相同结构的 INTO
var copyRow = table.NewRow();
copyRow.ItemArray = currentRow.ItemArray;
table.Rows.Add( copyRow );
ItemArray 是 table 的所有列属性的列表,没有显式引用行 ["someColumn"]。因此,将数组复制到新行可以获得所有列。这是 - 如果两个 table 结构相同 - 并且似乎来自您提供的场景。
澄清
上面的代码只做一行,将根据你的循环应用
if (oneCell.Selected)
您每行选择了多列,因此导致您的循环有些混乱。您实际上多次点击同一行。无论如何,我发现您实际上是在 Windows 应用程序而不是 WPF 中执行此操作。我创建了一个表单并在下面发布了代码。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
loadDataIntoGridView1();
}
public DataTable tblFrom { get; set; }
public DataTable tblTo { get; set; }
private void loadDataIntoGridView1()
{
tblFrom = new DataTable();
tblFrom.Columns.Add("Col1", typeof(string));
tblFrom.Columns.Add("Col2", typeof(string));
tblTo = tblFrom.Clone();
DataRow tmp;
while (tblFrom.Rows.Count < 20)
{
tmp = tblFrom.NewRow();
tmp["Col1"] = "my row " + tblFrom.Rows.Count;
tmp["Col2"] = "testing";
tblFrom.Rows.Add(tmp);
}
dataGridView1.AutoGenerateColumns = true;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView2.AutoGenerateColumns = true;
dataGridView2.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.DataSource = tblFrom;
dataGridView2.DataSource = tblTo;
}
private void button1_Click(object sender, System.EventArgs e)
{
// if no ROWS selected, get out.
if (dataGridView1.SelectedRows.Count == 0)
return;
foreach( DataGridViewRow vr in dataGridView1.SelectedRows)
{
var currentRow = ((DataRowView)vr.DataBoundItem).Row;
((DataTable)dataGridView2.DataSource).ImportRow(currentRow);
//this will remove the rows you have selected from dataGridView1
dataGridView1.Rows.RemoveAt(vr.Index);
}
}
}
在这里,我有一个表格,有两个类似于你的网格和一个按钮到 "Move" 记录(但只有一个方向),你必须调整一个/所有/从/ 方向。
一些变化。我更改了网格以强制选择模式到整个行。这将防止单行有多个条目,因为您有多个可用列。通过在单元格之间拖动或按住 Ctrl 键并单击各个行,仍然可以进行多项选择。这允许选择不在同一可视屏幕区域内的行。
我也刚刚创建了一个 table 来强制模拟 20 行数据以强制不是所有行都同时可见。
接下来点击事件...如果没有选择行,退出...如果有,则循环,但如果多列,则每行执行一次,而不是多次。获取绑定数据行,导入和删除...
否则你已经很接近了,不需要复制数组。我认为总体问题是您的列模式选择多次击中同一条记录。在第一个单元格的第 0 行的 remove-at 之后,第 1 行成为第 0 行并因此复制它,删除并且您现在不在列表中,因为只剩下一个记录要处理。在这里,无论选择了其中的哪一列,我们都会一次获得整行。
这是执行此操作的完整代码段。
在此示例中,我使用 2 BindingList
来实现您的要求。用户单击该按钮后,示例会将所选项目从 dgv1data
复制到 dgv2data
。然后它将从 dgv1data
.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
namespace MoveDataBetweenDataGridView_47454256
{
public partial class Form1 : Form
{
static BindingList<dgventry> dgv1data = new BindingList<dgventry>();
static BindingList<dgventry> dgv2data = new BindingList<dgventry>();
DataGridView dgv1 = new DataGridView();
DataGridView dgv2 = new DataGridView();
Button btn = new Button();
public Form1()
{
InitializeComponent();
InitOurStuff();
for (int i = 0; i < 10; i++)
{
dgv1data.Add(new MoveDataBetweenDataGridView_47454256.dgventry
{
col1 = $"col1_{i}", col2 = $"col2_{i}", col3 = $"col3_{i}"});
}
}
private void InitOurStuff()
{
this.Controls.Add(dgv1);//add the DGV to the form
dgv1.DataSource = dgv1data;//bind our data to it
dgv1.Dock = DockStyle.Left;//place the DGV somewhere on the form
this.Controls.Add(dgv2);//add the DGV to the form
dgv2.DataSource = dgv2data;//bind out data to it
dgv2.Dock = DockStyle.Right;//place the DGV somewhere on the form
this.Controls.Add(btn);//add the Button to the form
btn.Dock = DockStyle.Bottom;//place the Button somewhere on the form
btn.Click += Btn_Click;//give the Button a event handler
}
private void Btn_Click(object sender, EventArgs e)
{
List<int> doneIndices = new List<int>();//this will keep track of the row indices we have dealt with
if (dgv1.SelectedCells.Count > 0)//if something is selected
{
foreach (DataGridViewCell item in dgv1.SelectedCells)//loop through the selected cells
{
if (!doneIndices.Contains(item.OwningRow.Index))//if this cell does not belong to a row index we already processed
{
//we haven't done this row yet
dgv2data.Add((dgventry)item.OwningRow.DataBoundItem);//add the DataBoundItem to the other DGV data
doneIndices.Add(item.OwningRow.Index);//put the current row index in our tracking list
}
else
{
//we have done this row already, move on to the next one
continue;
}
}
}
//remove all the duplicate entries
foreach (dgventry item in dgv2data)
{
dgv1data.Remove(item);
}
}
}
public class dgventry
{
public string col1 { get; set; }
public string col2 { get; set; }
public string col3 { get; set; }
}
}