DataGridView(DGV)で選択した行を上下に移動するにはどうすればよいですか。 ListViewを使用してこれを以前に行いました。残念ながら、私にとってDGVの交換はオプションではありません(curses)。ちなみに、DGVデータソースはジェネリックコレクションです。
DGVの側面には、はい、上下の2つのボタンがあります。誰かが私を正しい方向に向けるのを手伝ってくれる?役立つ場合は、ListViewに使用したコードがあります(私には役立ちませんでした)。
コレクション内のアイテムの順序をプログラムで変更する場合、DGVはそれを自動的に反映する必要があります。
ずさんな、半分動作する例:
List<MyObj> foo = DGV.DataSource;
int idx = DGV.SelectedRows[0].Index;
int value = foo[idx];
foo.Remove(value);
foo.InsertAt(idx+1, value)
そのロジックの一部は間違っている可能性があり、これも最も効率的なアプローチではない可能性があります。また、複数の行の選択は考慮されません。
最後に、標準のリストまたはコレクションを使用している場合、これはそれほどスムーズにはいきません。リストとコレクションは、DGVがデータバインディングに役立つと判断したイベントを発行しません。コレクションを変更するたびにデータバインドを「ゲップ」することもできますが、System.ComponentModel.BindingListを使用する方がより良い解決策です。 BindingListの順序を変更すると、DGVは変更を自動的に反映するはずです。
Yoopergeekの答えを拡張するために、ここに私が持っているものがあります。私はDataSourceを使用していませんでした(フォームのクローズ時にレジストリにデータがドロップされ、フォームのロード時にリロードされます)
このサンプルは、行がグリッドの外に移動して失われるのを防ぎ、その人がいたセルも再選択します。
コピー/貼り付けを簡単にするために、コード全体で名前を変更するのではなく、「gridTasks」を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 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 { }
}
これはうまくいくはずです。リストを直接DataGridViewにバインドする代わりに、BindingSourceを使用します。
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; }
}
最初にデータグリッドビューに入力します。たとえば、3つの列を持つテーブルを取得します
DataTable table = new DataTable();
table.Columns.Add("col1");
table.Columns.Add("col2");
table.Columns.Add("col3");
foreach (var i in yourTablesource(db,list,etc))
{
table.Rows.Add(i.col1, i.col2, i.col2);
}
datagridview1.DataSource = table;
次に、ボタンをクリックしてクリックします
int rowIndex;
private void btnUp_Click(object sender, EventArgs e)
{
rowIndex = datagridview1.SelectedCells[0].OwningRow.Index;
DataRow row = table.NewRow();
row[0] = datagridview1.Rows[rowIndex].Cells[0].Value.ToString();
row[1] = datagridview1.Rows[rowIndex].Cells[1].Value.ToString();
row[2] = datagridview1.Rows[rowIndex].Cells[2].Value.ToString();
if (rowIndex > 0)
{
table.Rows.RemoveAt(rowIndex);
table.Rows.InsertAt(row, rowIndex - 1);
datagridview1.ClearSelection();
datagridview1.Rows[rowIndex - 1].Selected = true;
}
}
ボタンダウンについても同じことを行い、row index
メソッドでrowIndex - 1
をrowindex + 1
からbuttonDown_Click
に変更します。
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;
}
(私の意見では)ほとんどの投稿がここにあるはるかに簡単な方法があります。 「上へ」ボタンをクリックするためのアクションの実行は、基本的には上記のものと行を交換するだけです。 (質問が述べられたように)自分で値を制御している場合は、行の値を交換するだけです。早くて簡単!
注:これは、データグリッドで複数選択が無効になっている場合にのみ機能します。ご覧のとおり、SelectedRowsコレクションのインデックス0のアイテムにのみ注目しています。
これが私が使ったものです:
private void btnUp_Click(object sender, EventArgs e)
{
var row = dgvExportLocations.SelectedRows[0];
if (row != null && row.Index > 0)
{
var swapRow = dgvExportLocations.Rows[row.Index - 1];
object[] values = new object[swapRow.Cells.Count];
foreach (DataGridViewCell cell in swapRow.Cells)
{
values[cell.ColumnIndex] = cell.Value;
cell.Value = row.Cells[cell.ColumnIndex].Value;
}
foreach (DataGridViewCell cell in row.Cells)
cell.Value = values[cell.ColumnIndex];
dgvExportLocations.Rows[row.Index - 1].Selected = true;//have the selection follow the moving cell
}
}
「ダウン」クリックを実行するには、反対、同じロジックを行うことができます
これは私が問題に対して見つけた最も短い解決策であり、私は見つけたコードを少しリファクタリングしました:
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>
そして背後にあるコードで...
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();
}
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)return; int col = grid.SelectedCells [0] .OwningColumn.Index; DataGridViewRowCollection rows = grid.Rows; DataGridViewRow行=行[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;
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 { }
}
複数選択をサポートするデータバインドソリューション。SharpDevelop4.4を使用してC#に変換します。
<Extension()>
Sub MoveSelectionUp(dgv As DataGridView)
If dgv.CurrentCell Is Nothing Then Exit Sub
dgv.CurrentCell.OwningRow.Selected = True
Dim items = DirectCast(dgv.DataSource, BindingSource).List
Dim selectedIndices = dgv.SelectedRows.Cast(Of DataGridViewRow).Select(Function(row) row.Index).Sort
Dim indexAbove = selectedIndices(0) - 1
If indexAbove = -1 Then Exit Sub
Dim itemAbove = items(indexAbove)
items.RemoveAt(indexAbove)
Dim indexLastItem = selectedIndices(selectedIndices.Count - 1)
If indexLastItem = items.Count Then
items.Add(itemAbove)
Else
items.Insert(indexLastItem + 1, itemAbove)
End If
End Sub
<Extension()>
Sub MoveSelectionDown(dgv As DataGridView)
If dgv.CurrentCell Is Nothing Then Exit Sub
dgv.CurrentCell.OwningRow.Selected = True
Dim items = DirectCast(dgv.DataSource, BindingSource).List
Dim selectedIndices = dgv.SelectedRows.Cast(Of DataGridViewRow).Select(Function(row) row.Index).Sort
Dim indexBelow = selectedIndices(selectedIndices.Count - 1) + 1
If indexBelow >= items.Count Then Exit Sub
Dim itemBelow = items(indexBelow)
items.RemoveAt(indexBelow)
Dim indexAbove = selectedIndices(0) - 1
items.Insert(indexAbove + 1, itemBelow)
End Sub
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;
}
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();
}
下部にこれらの3行を追加すると、選択も移動し(bindingSourceとdataGridViewの両方)、下部を連続的にクリックして行を上に移動できるようになります。
下に移動するには、単にbs.MoveNext()を呼び出します。
(私はまだコメントとして投稿するのに十分な評判がありません)
このUP/DOWNボタンのものを探していて、これを見つけて嬉しかったです。戻り値の後にbs.RaiseListChangedEvents = falseステートメントを置くと、常に機能しません。
C#3.0では、次のように2つの拡張メソッドを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);
}
}
最後に、これらすべての悪いStringの例の代わりに拡張メソッドの良い使い方.. ;-)