C# DataGridView 选中的行上下移动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1012708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DataGridView Selected Row Move UP and DOWN
提问by Silly Rabbit
How can I allow selected rows in a DataGridView (DGV) to be moved up or down. I have done this before with a ListView. Unfortunetly, for me, replacing the DGV is not an option (curses). By the way, the DGV datasource is a Generic Collection.
如何允许向上或向下移动 DataGridView (DGV) 中的选定行。我以前用 ListView 做过这个。不幸的是,对我来说,更换 DGV 不是一种选择(curses)。顺便说一下,DGV 数据源是一个通用集合。
The DGV has two buttons on the side, yes, UP & Down. Can anyone help point me in the right direction. I do have the code that I used for the ListView if it'll help (it did not help me).
DGV 侧面有两个按钮,是的,向上和向下。任何人都可以帮助我指出正确的方向。如果有帮助,我确实有用于 ListView 的代码(它没有帮助我)。
采纳答案by Yoopergeek
If you programatically change the ordering of the items in your collection, the DGV should reflect that automatically.
如果您以编程方式更改集合中项目的顺序,DGV 应自动反映该顺序。
Sloppy, half-working example:
马虎,半工作的例子:
List<MyObj> foo = DGV.DataSource;
int idx = DGV.SelectedRows[0].Index;
int value = foo[idx];
foo.Remove(value);
foo.InsertAt(idx+1, value)
Some of that logic may be wrong, and this may not be the most efficient approach either. Also, it doesn't take into account multiple row selections.
其中一些逻辑可能是错误的,这也可能不是最有效的方法。此外,它不考虑多行选择。
Hmm, one last thing, if you're using a standard List or Collection this isn't going to go as smoothly. List and Collection on't emit events that the DGV finds useful for databinding. You could 'burp' the databinding every time you change the collection, but a better solution would be for you to use a System.ComponentModel.BindingList. When you change the ordering of the BindingList the DGV should reflect the change automatically.
嗯,最后一件事,如果您使用标准列表或集合,这将不会那么顺利。列表和集合不会发出 DGV 认为对数据绑定有用的事件。您可以在每次更改集合时“打嗝”数据绑定,但更好的解决方案是使用 System.ComponentModel.BindingList。当您更改 BindingList 的顺序时,DGV 应自动反映更改。
回答by Jürgen Steinblock
This should work. I use a BindingSource instead of binding my List directly to the DataGridView:
这应该有效。我使用 BindingSource 而不是将我的 List 直接绑定到 DataGridView:
private List<MyItem> items = new List<MyItem> {
new MyItem {Id = 0, Name = "Hello"},
new MyItem {Id = 1, Name = "World"},
new MyItem {Id = 2, Name = "Foo"},
new MyItem {Id = 3, Name = "Bar"},
new MyItem {Id = 4, Name = "Scott"},
new MyItem {Id = 5, Name = "Tiger"},
};
private BindingSource bs;
private void Form1_Load(object sender, EventArgs e)
{
bs = new BindingSource(items, string.Empty);
dataGridView1.DataSource = bs;
}
private void button1_Click(object sender, EventArgs e)
{
if (bs.Count <= 1) return; // one or zero elements
int position = bs.Position;
if (position <= 0) return; // already at top
bs.RaiseListChangedEvents = false;
MyItem current = (MyItem)bs.Current;
bs.Remove(current);
position--;
bs.Insert(position, current);
bs.Position = position;
bs.RaiseListChangedEvents = true;
bs.ResetBindings(false);
}
private void button2_Click(object sender, EventArgs e)
{
if (bs.Count <= 1) return; // one or zero elements
int position = bs.Position;
if (position == bs.Count - 1) return; // already at bottom
bs.RaiseListChangedEvents = false;
MyItem current = (MyItem)bs.Current;
bs.Remove(current);
position++;
bs.Insert(position, current);
bs.Position = position;
bs.RaiseListChangedEvents = true;
bs.ResetBindings(false);
}
public class MyItem
{
public int Id { get; set; }
public String Name { get; set; }
}
回答by Jürgen Steinblock
Was looking for this UP/DOWN button thing and glad that I found this. Better to put the bs.RaiseListChangedEvents = false statement after the return or it doesn't work all the time.
正在寻找这个向上/向下按钮的东西,很高兴我找到了这个。最好在返回后放置 bs.RaiseListChangedEvents = false 语句,否则它不会一直工作。
And in C#3.0 you can add two extension methods to the BindingSource like this:
在 C#3.0 中,您可以像这样向 BindingSource 添加两个扩展方法:
public static class BindingSourceExtension
{
public static void MoveUp( this BindingSource aBindingSource )
{
int position = aBindingSource.Position;
if (position == 0) return; // already at top
aBindingSource.RaiseListChangedEvents = false;
object current = aBindingSource.Current;
aBindingSource.Remove(current);
position--;
aBindingSource.Insert(position, current);
aBindingSource.Position = position;
aBindingSource.RaiseListChangedEvents = true;
aBindingSource.ResetBindings(false);
}
public static void MoveDown( this BindingSource aBindingSource )
{
int position = aBindingSource.Position;
if (position == aBindingSource.Count - 1) return; // already at bottom
aBindingSource.RaiseListChangedEvents = false;
object current = aBindingSource.Current;
aBindingSource.Remove(current);
position++;
aBindingSource.Insert(position, current);
aBindingSource.Position = position;
aBindingSource.RaiseListChangedEvents = true;
aBindingSource.ResetBindings(false);
}
}
Finally a good use for extension methods instead of all those bad String examples.. ;-)
最后,很好地使用了扩展方法,而不是所有那些糟糕的 String 示例.. ;-)
回答by user411188
DataGridViewRow BeginingRow = new DataGridViewRow();
int BeginingRowIndex ;
private void DataGridView1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button != MouseButtons.Left ||e.RowIndex < 0 ) return;
if (BeginingRowIndex > e.RowIndex)
{
DataGridView1.Rows.Insert(e.RowIndex);
foreach (DataGridViewCell cellules in BeginingRow.Cells)
{
DataGridView1.Rows[e.RowIndex].Cells[cellules.ColumnIndex].Value = cellules.Value;
}
DataGridView1.Rows.RemoveAt(BeginingRowIndex + 1);
}
else
{
DataGridView1.Rows.Insert(e.RowIndex +1);
foreach (DataGridViewCell cellules in BeginingRow.Cells)
{
DataGridView1.Rows[e.RowIndex+1].Cells[cellules.ColumnIndex].Value = cellules.Value;
}
DataGridView1.Rows.RemoveAt(BeginingRowIndex);
}
DataGridView1.RowsDefaultCellStyle.ApplyStyle(BeginingRow.DefaultCellStyle);
DataGridView1.Rows[e.RowIndex].Selected = true;
}
private void DataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button != MouseButtons.Left ||e.RowIndex < 0 ) return;
BeginingRowIndex = e.RowIndex;
BeginingRow = DataGridView1.Rows[BeginingRowIndex];
BeginingRow.DefaultCellStyle = DataGridView1.Rows[BeginingRowIndex].DefaultCellStyle;
}
回答by Para
Just to expand on Yoopergeek's answer, here's what I have. I was not using a DataSource (data is being dropped to registry on form close, and reload on form load)
只是为了扩展 Yoopergeek 的答案,这就是我所拥有的。我没有使用数据源(数据在表单关闭时被删除到注册表,并在表单加载时重新加载)
This sample will keep rows from being moved off the grid and lost, and reselect the cell the person was in as well.
此示例将防止行移出网格和丢失,并重新选择该人所在的单元格。
To make things simpler for copy / paste, I modified so you need only change "gridTasks" to your DataGridView's name, rather than renaming it throughout the code.
为了使复制/粘贴更简单,我进行了修改,因此您只需将“gridTasks”更改为 DataGridView 的名称,而不是在整个代码中对其进行重命名。
This solution works only for single cell/row selected.
此解决方案仅适用于选定的单个单元格/行。
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 btnDown_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 == totalRows - 1 )
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 { }
}
回答by namco
private void butUp_Click(object sender, EventArgs e)
{
DataTable dtTemp = gridView.DataSource as DataTable;
object[] arr = dtTemp.Rows[0].ItemArray;
for (int i = 1; i < dtTemp.Rows.Count; i++)
{
dtTemp.Rows[i - 1].ItemArray = dtTemp.Rows[i].ItemArray;
}
dtTemp.Rows[dtTemp.Rows.Count - 1].ItemArray = arr;
}
private void butDown_Click(object sender, EventArgs e)
{
DataTable dtTemp = gridView.DataSource as DataTable;
object[] arr = dtTemp.Rows[dtTemp.Rows.Count - 1].ItemArray;
for (int i = dtTemp.Rows.Count - 2; i >= 0; i--)
{
dtTemp.Rows[i + 1].ItemArray = dtTemp.Rows[i].ItemArray;
}
dtTemp.Rows[0].ItemArray = arr;
}
回答by jortizromo
this is the shortest solution I have found to the problem and I just refactored a little bit the code found in:
这是我找到的最短解决方案,我只是重构了一点在以下位置找到的代码:
http://dotnetspeaks.net/post/Moving-GridView-Rows-Up-Down-in-a-GridView-Control.aspx
http://dotnetspeaks.net/post/Moving-GridView-Rows-Up-Down-in-a-GridView-Control.aspx
<body>
<form id="form1" runat="server">
<asp:GridView ID="GridView1" Font-Names="Verdana" Font-Size="9pt" runat="server" OnRowCreated="GridView1_RowCreated"
AutoGenerateColumns="False" CellPadding="4" BorderColor="#507CD1" BorderStyle="Solid">
<Columns>
<asp:TemplateField HeaderText="First Name">
<ItemTemplate>
<asp:Label ID="txtFirstName" runat="server" Text='<%# Eval("FirstName") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" />
</asp:GridView>
<asp:Button ID="btnUp" runat="server" Text="Up" OnClick="btnUp_Click"/>
<asp:Button ID="btnDown" runat="server" Text="Down" OnClick="btnDown_Click" />
</form>
and with code behind...
和背后的代码......
public int SelectedRowIndex { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//Test Records
GridView1.DataSource = Enumerable.Range(1, 5).Select(a => new
{
FirstName = String.Format("First Name {0}", a),
LastName = String.Format("Last Name {0}", a),
});
GridView1.DataBind();
}
}
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onmouseover"] = "this.style.cursor='pointer'";
e.Row.ToolTip = "Click to select row";
e.Row.Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(GridView1, "Select$" + e.Row.RowIndex);
}
}
protected void btnUp_Click(object sender, EventArgs e)
{
var rows = GridView1.Rows.Cast<GridViewRow>().Where(a => a != GridView1.SelectedRow).ToList();
//If First Item, insert at end (rotating positions)
if (GridView1.SelectedRow.RowIndex.Equals(0))
{
rows.Add(GridView1.SelectedRow);
SelectedRowIndex = GridView1.Rows.Count -1;
}
else
{
SelectedRowIndex = GridView1.SelectedRow.RowIndex - 1;
rows.Insert(GridView1.SelectedRow.RowIndex - 1, GridView1.SelectedRow);
}
RebindGrid(rows);
}
protected void btnDown_Click(object sender, EventArgs e)
{
var rows = GridView1.Rows.Cast<GridViewRow>().Where(a => a != GridView1.SelectedRow).ToList();
//If Last Item, insert at beginning (rotating positions)
if (GridView1.SelectedRow.RowIndex.Equals(GridView1.Rows.Count - 1))
{
rows.Insert(0, GridView1.SelectedRow);
SelectedRowIndex = 0;
}
else
{
SelectedRowIndex = GridView1.SelectedRow.RowIndex + 1;
rows.Insert(GridView1.SelectedRow.RowIndex + 1, GridView1.SelectedRow);
}
RebindGrid(rows);
}
private void RebindGrid(IEnumerable<GridViewRow> rows)
{
GridView1.DataSource = rows.Select(a => new
{
FirstName = ((Label)a.FindControl("txtFirstName")).Text,
}).ToList();
GridView1.SelectedIndex = SelectedRowIndex;
GridView1.DataBind();
}
回答by vahid ghezelvand
Try this:
尝试这个:
private void buttonX9_Click(object sender, EventArgs e)//up
{
DataGridViewX grid = dataGridViewX1;
try
{
int totalRows = grid.Rows.Count;
int idx = grid.SelectedCells[0].OwningRow.Index;
if (idx == 0)
return;
int col = grid.SelectedCells[0].OwningColumn.Index;
DataGridViewRowCollection rows = grid.Rows;
DataGridViewRow row = rows[idx];
rows.Remove(row);
rows.Insert(idx - 1, row);
grid.ClearSelection();
grid.Rows[idx - 1].Cells[col].Selected = true;
}
catch { }
}
回答by vahid ghezelvand
Header 3
标题 3
private void buttonX8_Click(object sender, EventArgs e)//down { DataGridViewX grid = dataGridViewX1; try { int totalRows = grid.Rows.Count; int idx = grid.SelectedCells[0].OwningRow.Index; if (idx == totalRows - 1 ) return; int col = grid.SelectedCells[0].OwningColumn.Index; DataGridViewRowCollection rows = grid.Rows; DataGridViewRow row = rows[idx]; rows.Remove(row); rows.Insert(idx + 1, row); grid.ClearSelection(); grid.Rows[idx + 1].Cells[col].Selected = true;
private void buttonX8_Click(object sender, EventArgs e)//down { DataGridViewX grid = dataGridViewX1; 尝试 { int totalRows = grid.Rows.Count; int idx = grid.SelectedCells[0].OwningRow.Index; if (idx == totalRows - 1 ) 返回;int col = grid.SelectedCells[0].OwningColumn.Index; DataGridViewRowCollection rows = grid.Rows; DataGridViewRow row = rows[idx]; 行。删除(行);行。插入(idx + 1,行);grid.ClearSelection(); grid.Rows[idx + 1].Cells[col].Selected = true;
private void buttonX8_Click(object sender, EventArgs e)//down
{
DataGridViewX grid = dataGridViewX1;
try
{
int totalRows = grid.Rows.Count;
int idx = grid.SelectedCells[0].OwningRow.Index;
if (idx == totalRows - 1 )
return;
int col = grid.SelectedCells[0].OwningColumn.Index;
DataGridViewRowCollection rows = grid.Rows;
DataGridViewRow row = rows[idx];
rows.Remove(row);
rows.Insert(idx + 1, row);
grid.ClearSelection();
grid.Rows[idx + 1].Cells[col].Selected = true;
}
catch { }
}
回答by Yang Chi-En
SchlaWiener's answer worked well, and I just wanna add something to it:
SchlaWiener 的回答效果很好,我只想添加一些内容:
private void button1_Click(object sender, EventArgs e) //The button to move up
{
int position = bs.Position;
//.......neglected.......
dataGridView1.ClearSelection();
dataGridView1.Rows[position].Selected = true;
bs.MovePrevious();
}
Adding those 3 lines at the bottom to also make the selection move (both bindingSource and dataGridView), so that we can continuously click the bottom to move a row up.
在底部添加这 3 行也使选择移动(bindingSource 和 dataGridView),以便我们可以连续单击底部向上移动一行。
For moving down just call bs.MoveNext()
向下移动只需调用 bs.MoveNext()
(I have not enough reputation to post as comment yet)
(我还没有足够的声誉作为评论发表)