none
DataGridView上でレコードの順番をマウスで変更したい・・・ RRS feed

  • 質問

  • DatGridViewに表示しているレコードの順番(Row)を

    マウスで変えることはできないでしょうか?

    RowHeaderをクリックして、移動先にドロップするイメージなのですが・・・

    [番号]項目を作っているのでドロップ先が分かればできそうな気がするのですが。

    よろしくお願いします。

     

    2006年5月16日 8:46

すべての返信

  • こちらを参考にして下さい。

    Drag & Drop Reorder of Row
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=201079&SiteID=1

    DataGridView FAQ.docは以下から落とせます。
    http://www.windowsforms.net/Samples/download.aspx?PageId=1&ItemId=220&tabindex=4

    2006年5月17日 3:25
    モデレータ
  • trapemiya様 いつもありがとうございます。

    参考のリンク先をさっそく見たのですが・・・日本語じゃなく、VBでもない。
    FAQ.docの[How do I perform drag and drop reorder of rows?]を
    VBに直してみたのですがよく分かりませんでした。
    (C言語系はまったく知らないので・・・)

    いつもお願いしてばかりで申し訳ないのですが、
    矢印の2箇所を教えてください。
    それ以外にも間違いがたくさんあると思いますのでご指摘お願いします。

        Dim dragBoxFromMouseDown As Rectangle
        Dim rowIndexFromMouseDown As Integer
        Dim rowIndexOfItemUnderMouseToDrop As Integer

        Private Sub DataGridView1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DataGridView1.DragDrop
            Dim clientPoint As Point = DataGridView1.PointToClient(New Point(e.X, e.Y))
            rowIndexOfItemUnderMouseToDrop = DataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex
            If (e.Effect = DragDropEffects.Move) Then
              DataGridViewRow rowToMove = e.Data.GetData(typeof(DataGridViewRow)) as DataGridViewRow ←ここ教えてください
                →Dim rowToMove As DataGridViewRow = e.Data.GetData(TypeOf DataGridViewRow Is DataGridViewRow)???
                DataGridView1.Rows.RemoveAt(rowIndexFromMouseDown)
                DataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove)
            End If
        End Sub

        Private Sub DataGridView1_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DataGridView1.DragOver
            e.Effect = DragDropEffects.Move
        End Sub

        Private Sub DataGridView1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DataGridView1.MouseDown
            rowIndexFromMouseDown = DataGridView1.HitTest(e.X, e.Y).RowIndex
            If (rowIndexFromMouseDown <> -1) Then
                Dim dragSize As Size = SystemInformation.DragSize
                dragBoxFromMouseDown = New Rectangle(New Point(e.X - (dragSize.Width / 2), e.Y - (dragSize.Height / 2)), dragSize)
            Else
                dragBoxFromMouseDown = Rectangle.Empty
            End If
        End Sub

        Private Sub DataGridView1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DataGridView1.MouseMove
     if ((e.Button & MouseButtons.Left) == MouseButtons.Left) ←ここ教えてください
     →左ボタンが押されている状態???
                If Not (dragBoxFromMouseDown.IsEmpty) And Not dragBoxFromMouseDown.Contains(e.X, e.Y) Then
                    Dim dropEffect As DragDropEffects = DataGridView1.DoDragDrop(DataGridView1.Rows(rowIndexFromMouseDown), DragDropEffects.Move)
                End If
            End If
        End Sub

    2006年5月17日 7:53
  • VB6はやってたんでVB.NETが全くわからないわけではないんですが、得意ではないんです。(^^;
    時間があれば実際にVB.NETでも動かしてみようと思いますが、とりあえず早急に、
    いつもの

    C# to VB.NET ranslator
    http://authors.aspalliance.com/aldotnet/examples/translate.aspx

    で、実際に私が動かしてみたC#をVB.NETに変換したのが以下のコードです。
    これで動くかしらん?

    
    Private dragBoxFromMouseDown As Rectangle
    Private rowIndexFromMouseDown As Integer
    Private rowIndexOfItemUnderMouseToDrop As Integer
    
    Private Sub dataGridView1_MouseMove(sender As Object, e As MouseEventArgs)
       If(e.Button And MouseButtons.Left) = MouseButtons.Left Then
          ' If the mouse moves outside the rectangle, start the drag.
          If dragBoxFromMouseDown <> Rectangle.Empty And Not dragBoxFromMouseDown.Contains(e.X, e.Y) Then
             
             ' Proceed with the drag and drop, passing in the list item.                    
             Dim dropEffect As DragDropEffects = dataGridView1.DoDragDrop(dataGridView1.Rows(rowIndexFromMouseDown), DragDropEffects.Move)
          End If
       End If
    End Sub 'dataGridView1_MouseMove
    
    
    Private Sub dataGridView1_MouseDown(sender As Object, e As MouseEventArgs)
       ' Get the index of the item the mouse is below.
       rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex
       
       If rowIndexFromMouseDown <> - 1 Then
          ' Remember the point where the mouse down occurred. 
          ' The DragSize indicates the size that the mouse can move 
          ' before a drag event should be started.                
          Dim dragSize As Size = SystemInformation.DragSize
          
          ' Create a rectangle using the DragSize, with the mouse position being
          ' at the center of the rectangle.
          dragBoxFromMouseDown = New Rectangle(New Point(e.X - dragSize.Width / 2, e.Y - dragSize.Height / 2), dragSize)
       ' Reset the rectangle if the mouse is not over an item in the ListBox.
       Else
          dragBoxFromMouseDown = Rectangle.Empty
       End If
    End Sub 'dataGridView1_MouseDown
     
    Private Sub dataGridView1_DragOver(sender As Object, e As DragEventArgs)
       e.Effect = DragDropEffects.Move
    End Sub 'dataGridView1_DragOver
    
    
    Private Sub dataGridView1_DragDrop(sender As Object, e As DragEventArgs)
       ' The mouse locations are relative to the screen, so they must be 
       ' converted to client coordinates.
       Dim clientPoint As Point = dataGridView1.PointToClient(New Point(e.X, e.Y))
       
       ' Get the row index of the item the mouse is below. 
       rowIndexOfItemUnderMouseToDrop = dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex
       
       ' If the drag operation was a move then remove and insert the row.
       If e.Effect = DragDropEffects.Move Then
    'データセットにバインドしていない場合
          ' DataGridViewRow rowToMove = e.Data.GetData(
         ' typeof(DataGridViewRow)) as DataGridViewRow;
         ' dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);
         ' dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);
                 
    'データセットにバインドしている場合
          ' get the row data from row before removing and add to new row
          Dim rowArray As Object() = testdbDataSet.TEST.Rows(rowIndexFromMouseDown).ItemArray
          Dim row As DataRow = testdbDataSet.TEST.NewRow()
          row.ItemArray = rowArray
          
          ' remove old row and insert new row
          testdbDataSet.TEST.Rows.RemoveAt(rowIndexFromMouseDown)
          testdbDataSet.TEST.Rows.InsertAt(row, rowIndexOfItemUnderMouseToDrop)
       End If 
    End Sub 'dataGridView1_DragDrop
    
    2006年5月18日 1:25
    モデレータ
  • trapemiya 様 ありがとうございます。

    教えて頂いたコードで下記のようにして動かすことができました。
    あと複数の行を一度に移動させたいのですが、
    RowIndexでRemoveAtとInsertAtしてるので難しいのでしょうか???

    よろしくお願いします。

        Private dragBoxFromMouseDown As Rectangle
        Private rowIndexFromMouseDown As Integer
        Private rowIndexOfItemUnderMouseToDrop As Integer

        Private Sub DataGridView1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles DataGridView1.MouseMove

            If (e.Button And Windows.Forms.MouseButtons.Left) = Windows.Forms.MouseButtons.Left Then

                ' If the mouse moves outside the rectangle, start the drag.
                If dragBoxFromMouseDown <> Rectangle.Empty And Not dragBoxFromMouseDown.Contains(e.X, e.Y) Then

                    ' Proceed with the drag and drop, passing in the list item.                   
                    Dim dropEffect As DragDropEffects = DataGridView1.DoDragDrop(DataGridView1.Rows(rowIndexFromMouseDown), DragDropEffects.Move)
                End If
            End If
        End Sub 'dataGridView1_MouseMove

        Private Sub DataGridView1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles DataGridView1.MouseDown

            ' Get the index of the item the mouse is below.
            rowIndexFromMouseDown = DataGridView1.HitTest(e.X, e.Y).RowIndex

            If rowIndexFromMouseDown <> -1 Then
                ' Remember the point where the mouse down occurred.
                ' The DragSize indicates the size that the mouse can move
                ' before a drag event should be started.               
                Dim dragSize As Size = SystemInformation.DragSize

                ' Create a rectangle using the DragSize, with the mouse position being
                ' at the center of the rectangle.
                dragBoxFromMouseDown = New Rectangle(New Point(e.X - dragSize.Width / 2, e.Y - dragSize.Height / 2), dragSize)
                ' Reset the rectangle if the mouse is not over an item in the ListBox.
            Else
                dragBoxFromMouseDown = Rectangle.Empty
            End If
        End Sub 'dataGridView1_MouseDown

        Private Sub DataGridView1_DragOver(ByVal sender As Object, ByVal e As DragEventArgs) Handles DataGridView1.DragOver

            e.Effect = DragDropEffects.Move

        End Sub 'dataGridView1_DragOver

        Private Sub DataGridView1_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) Handles DataGridView1.DragDrop

            ' The mouse locations are relative to the screen, so they must be
            ' converted to client coordinates.
            Dim clientPoint As Point = DataGridView1.PointToClient(New Point(e.X, e.Y))

            ' Get the row index of the item the mouse is below.
            rowIndexOfItemUnderMouseToDrop = DataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex

            If rowIndexOfItemUnderMouseToDrop <> -1 Then
                ' If the drag operation was a move then remove and insert the row.
                If e.Effect = DragDropEffects.Move Then

                    'データセットにバインドしている場合…複数行一度に移動したいが…
                    ' get the row data from row before removing and add to new row
                    Dim rowArray As Object() = testdbDataSet.TEST.Rows(rowIndexFromMouseDown).ItemArray
                    Dim row As DataRow = testdbDataSet.TEST.NewRow()
                    row.ItemArray = rowArray

                    ' remove old row and insert new row
                    testdbDataSet.TEST.Rows.RemoveAt(rowIndexFromMouseDown)
                    testdbDataSet.TEST.Rows.InsertAt(row, rowIndexOfItemUnderMouseToDrop)
                End If
            End If

        End Sub 'dataGridView1_DragDrop

    コードの色分けはどのようにするのかなぁ…これじゃぁ見難いですよね

    2006年5月18日 6:39
  • VB.NETへの変換は、ジェネリックが対応していないためらしく、先のWebページでは失敗しました。Orz
    仕方がないので、C#のコードをそのまま載せます。ざくっと書いているので、検証は十分ではありません。(^^;
    それから色つきのコードですが、CodeToHTMLというツールを使っています。
    そのツールで作成されたHTMLコードを、HTMLモードにして貼り付けて下さい。
    ただ、それだとフォントが小さくなってしまうようなので、私は、<font size=2> ~ </font>で、
    <pre>タグの内側のコード全体を囲んでいます。
    private Rectangle dragBoxFromMouseDown;
    private int rowIndexFromMouseDown;
    private int rowIndexOfItemUnderMouseToDrop;
    List<int> listRowIndexSelect = new List<int>();    //選択された複数の行を保持します。
    
    private void tESTDataGridView_MouseMove(object sender, MouseEventArgs e)
    {
        if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
        {
            // If the mouse moves outside the rectangle, start the drag.
            if (dragBoxFromMouseDown != Rectangle.Empty &&
                !dragBoxFromMouseDown.Contains(e.X, e.Y))
            {
    
                // Proceed with the drag and drop, passing in the list item.
                DragDropEffects dropEffect = tESTDataGridView.DoDragDrop(
                tESTDataGridView.Rows[rowIndexFromMouseDown],
                DragDropEffects.Move);
            }
        }
    }
    
    private void tESTDataGridView_MouseDown(object sender, MouseEventArgs e)
    {
        // Get the index of the item the mouse is below.
        rowIndexFromMouseDown = tESTDataGridView.HitTest(e.X, e.Y).RowIndex;
    
        if (rowIndexFromMouseDown != -1)
        {
            listRowIndexSelect.Clear();
    
            foreach (DataGridViewRow dgvr in tESTDataGridView.Rows)
            {
                if (dgvr.Selected)
                    listRowIndexSelect.Add(dgvr.Index);
            }
    
            if (! tESTDataGridView.Rows[rowIndexFromMouseDown].Selected)
                    listRowIndexSelect.Add(rowIndexFromMouseDown);
    
            // Remember the point where the mouse down occurred. 
            // The DragSize indicates the size that the mouse can move 
            // before a drag event should be started.                
            Size dragSize = SystemInformation.DragSize;
    
            // Create a rectangle using the DragSize, with the mouse position being
            // at the center of the rectangle.
            dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
                                                           e.Y - (dragSize.Height / 2)),
                                dragSize);
        }
        else
            // Reset the rectangle if the mouse is not over an item in the ListBox.
            dragBoxFromMouseDown = Rectangle.Empty;
    }
    
    private void tESTDataGridView_DragOver(object sender, DragEventArgs e)
    {
        e.Effect = DragDropEffects.Move;
    }
    
    private void tESTDataGridView_DragDrop(object sender, DragEventArgs e)
    {
        // The mouse locations are relative to the screen, so they must be 
        // converted to client coordinates.
        Point clientPoint = tESTDataGridView.PointToClient(new Point(e.X, e.Y));
    
        // Get the row index of the item the mouse is below. 
        rowIndexOfItemUnderMouseToDrop =
            tESTDataGridView.HitTest(clientPoint.X, clientPoint.Y).RowIndex;
    
        // If the drag operation was a move then remove and insert the row.
        if (e.Effect == DragDropEffects.Move)
        {
            // get the row data from row before removing and add to new row
            List<DataRow> listDataRow = new List<DataRow>();    //挿入する行を作成し、保持します。
    
            foreach (int rowIndex in listRowIndexSelect)
            {
                object[] rowArray = testdbDataSet.TEST.Rows[rowIndex].ItemArray;
                DataRow row = testdbDataSet.TEST.NewRow();
                row.ItemArray = rowArray;
                listDataRow.Add(row);
            }
    
            //  remove old row and insert new row
    
            int index = 0;
            int delcntBeforeRowIndexOfItemUnderMouseToDrop = 0;    //ドロップ先の行以前に存在する選択された行数
    
            //選択された行を削除します。
            foreach (int rowIndex in listRowIndexSelect)
            {
                //行を削除する度に行インデックスが一つ減るので、それを調整しながら削除
                testdbDataSet.TEST.Rows.RemoveAt(rowIndex - index);
                index++;
    
                if (rowIndex <= rowIndexOfItemUnderMouseToDrop)
                    delcntBeforeRowIndexOfItemUnderMouseToDrop++;
            }
            
            //行を挿入します。ドロップ先の行以前にある行数分、ドロップ先行のインデックスが減ります。
            //なぜなら、すぐ上で行を削除しているからです。
            for (int i = listDataRow.Count - 1; i >= 0; i--)
            {
                testdbDataSet.TEST.Rows.InsertAt(listDataRow[i], rowIndexOfItemUnderMouseToDrop
                                                        - delcntBeforeRowIndexOfItemUnderMouseToDrop);
            }
        }
    }
    
    2006年5月18日 9:43
    モデレータ
  • C#からVB.NETへの変換は、ジェネリックの部分のみで発生していると思われるため、部分的に切り貼りして変換してあげれば、その部分に関してはうまくいくと思います。
    申し訳ないのですが、それでなんとか変換してみて下さい。基本的には前回のコードとそんなには変わっていません。

    #上のコードを編集するとたぶん文字が化けるので(全部?になる)、追記をここにしました。早く文字化けしないように直して下さいませ。

    2006年5月18日 9:50
    モデレータ
  • ええいっ、自分でやってみました。(^^;
    
    Private dragBoxFromMouseDown As Rectangle
    Private rowIndexFromMouseDown As Integer
    Private rowIndexOfItemUnderMouseToDrop As Integer
    Dim listRowIndexSelect As List(Of Integer) = New List(Of Integer) '選択された複数の行を保持します。
    
    Private Sub tESTDataGridView_MouseMove(sender As Object, e As MouseEventArgs)
       If(e.Button And MouseButtons.Left) = MouseButtons.Left Then
          ' If the mouse moves outside the rectangle, start the drag.
          If dragBoxFromMouseDown <> Rectangle.Empty And Not dragBoxFromMouseDown.Contains(e.X, e.Y) Then
             
             ' Proceed with the drag and drop, passing in the list item.
             Dim dropEffect As DragDropEffects = tESTDataGridView.DoDragDrop(tESTDataGridView.Rows(rowIndexFromMouseDown), DragDropEffects.Move)
          End If
       End If
    End Sub 'tESTDataGridView_MouseMove
    
    
    Private Sub tESTDataGridView_MouseDown(sender As Object, e As MouseEventArgs)
       ' Get the index of the item the mouse is below.
       rowIndexFromMouseDown = tESTDataGridView.HitTest(e.X, e.Y).RowIndex
       
       If rowIndexFromMouseDown <> - 1 Then
          listRowIndexSelect.Clear()
          
          Dim dgvr As DataGridViewRow
          For Each dgvr In  tESTDataGridView.Rows
             If dgvr.Selected Then
                listRowIndexSelect.Add(dgvr.Index)
             End If
          Next dgvr 
          If Not tESTDataGridView.Rows(rowIndexFromMouseDown).Selected Then
             listRowIndexSelect.Add(rowIndexFromMouseDown)
          End If 
          ' Remember the point where the mouse down occurred. 
          ' The DragSize indicates the size that the mouse can move 
          ' before a drag event should be started.                
          Dim dragSize As Size = SystemInformation.DragSize
          
          ' Create a rectangle using the DragSize, with the mouse position being
          ' at the center of the rectangle.
          dragBoxFromMouseDown = New Rectangle(New Point(e.X - dragSize.Width / 2, e.Y - dragSize.Height / 2), dragSize)
       ' Reset the rectangle if the mouse is not over an item in the ListBox.
       Else
          dragBoxFromMouseDown = Rectangle.Empty
       End If
    End Sub 'tESTDataGridView_MouseDown
     
    Private Sub tESTDataGridView_DragOver(sender As Object, e As DragEventArgs)
       e.Effect = DragDropEffects.Move
    End Sub 'tESTDataGridView_DragOver
    
    
    Private Sub tESTDataGridView_DragDrop(sender As Object, e As DragEventArgs)
       ' The mouse locations are relative to the screen, so they must be 
       ' converted to client coordinates.
       Dim clientPoint As Point = tESTDataGridView.PointToClient(New Point(e.X, e.Y))
       
       ' Get the row index of the item the mouse is below. 
       rowIndexOfItemUnderMouseToDrop = tESTDataGridView.HitTest(clientPoint.X, clientPoint.Y).RowIndex
       
       ' If the drag operation was a move then remove and insert the row.
       If e.Effect = DragDropEffects.Move Then
          ' get the row data from row before removing and add to new row
          Dim listDataRow As List(Of DataRow) = New List(Of DataRow)  '挿入する行を作成し、保持します。
          Dim rowIndex As Integer
          For Each rowIndex In  listRowIndexSelect
             Dim rowArray As Object() = testdbDataSet.TEST.Rows(rowIndex).ItemArray
             Dim row As DataRow = testdbDataSet.TEST.NewRow()
             row.ItemArray = rowArray
             listDataRow.Add(row)
          Next rowIndex
          
          '  remove old row and insert new row
          Dim index As Integer = 0
          Dim delcntBeforeRowIndexOfItemUnderMouseToDrop As Integer = 0 'ドロップ先の行以前に存在する選択された行数
          '選択された行を削除します。
          Dim rowIndex As Integer
          For Each rowIndex In  listRowIndexSelect
             '行を削除する度に行インデックスが一つ減るので、それを調整しながら削除
             testdbDataSet.TEST.Rows.RemoveAt((rowIndex - index))
             index += 1
             
             If rowIndex <= rowIndexOfItemUnderMouseToDrop Then
                delcntBeforeRowIndexOfItemUnderMouseToDrop += 1
             End If
          Next rowIndex 
          '行を挿入します。ドロップ先の行以前にある行数分、ドロップ先行のインデックスが減ります。
          'なぜなら、すぐ上で行を削除しているからです。
          Dim i As Integer
          For i = listDataRow.Count - 1 To 0 Step -1
             testdbDataSet.TEST.Rows.InsertAt(listDataRow(i), rowIndexOfItemUnderMouseToDrop - delcntBeforeRowIndexOfItemUnderMouseToDrop)
          Next i
       End If
    End Sub 'tESTDataGridView_DragDrop
    
    2006年5月18日 10:01
    モデレータ
  • trapemiya様 コードまで書き直して頂いて申し訳ありません。

    コピーして無事に動き、ひとりで感動しています。

    あれっ、レコードが消える・・・選択してレコードの上でDropすると。

    コピー間違えたかなぁ、もう少しコードの内容を確認して結果報告します。

    ありがとうございました。

     

    2006年5月18日 13:37
  • あれっ、レコードが消える・・・選択してレコードの上でDropすると。
    十分に精査してないもので(^^;
    こちらで試したら、消えるというよりも一つ上に移動してしまったので、
    DragDropイベントにおける
    rowIndexOfItemUnderMouseToDrop = tESTDataGridView.HitTest(clientPoint.X, clientPoint.Y).RowIndex
    の次に、以下のコードを入れると良いと思います。
    If rowIndexFromMouseDown = rowIndexOfItemUnderMouseToDrop Then
       Return
    End If
    あと、MouseDownイベントにおける以下のコードは必要ないようです。
    If Not tESTDataGridView.Rows(rowIndexFromMouseDown).Selected Then
         listRowIndexSelect.Add(rowIndexFromMouseDown)
    End If
    2006年5月19日 1:55
    モデレータ
  • trapemiya様、ありがとうございます。

    コードを試しているのですが、シフトキーを押しながら

    最初と最後のレコードを選択して複数のレコードを選択した場合、

    最初と最後のIndexがlistRowIndexSelectに保持されるみたいです。

    途中のIndexが抜けているかもと思い、

    tESTDataGridView_SelectionChangedで保持できないかと考えています。

    MouseDownイベント発生時にはまだ選択されてないのでしょうか???

    If Not tESTDataGridView.Rows(rowIndexFromMouseDown).Selected Then
         listRowIndexSelect.Add(rowIndexFromMouseDown)
    

    このコードで最後のレコードが選択されているような・・・

    間違っていたらすみません、まだ確認中ですので。

     

    2006年5月19日 3:04
  • >途中のIndexが抜けているかもと思い、

    Console.WriteLineとかして確認してみて下さい。こちらでは、シフトを押しながらでも、コントロールを押しながらでもうまく動いています。

    >このコードで最後のレコードが選択されているような・・・

    すみません。自分でコードを書いていながら、私の勘違いでした。
    おっしゃるとおり、MouseDownイベント発生時にはその行はまだSelected状態になっていないため、やはり上記のコードは必要でした。訂正いたします。m(_ _)m

    2006年5月19日 4:34
    モデレータ
  • trapemiya様、返事遅くなり申し訳ありません。

    自分で何とかしようと思ったのですが・・・自分の力では無理だと感じだので1つ質問させてください。

    DataGridView上でShiftキーを押して複数選択する場合、

    たとえば、2行目をクリック、Shiftキーを押して4行目をクリックすると

          For Each dgvr In  tESTDataGridView.Rows
             If dgvr.Selected Then
                listRowIndexSelect.Add(dgvr.Index)
             End If
          Next dgvr

    上記のコードで、dgvr.Index = 1をlistRowIndexSelectにAddして

         If Not tESTDataGridView.Rows(rowIndexFromMouseDown).Selected Then
             listRowIndexSelect.Add(rowIndexFromMouseDown)
          End If

    上記のコードで、dgvr.Index = 3をlistRowIndexSelectにAddしてしまいます。

    2行目と4行目の間にある3行目のdgvr.Index = 2 が取得できません。

    DataGridViewのプロパティはAllowDrop = Trueと設定しています。

    listRowIndexSelectにAddされたIndexのみが移動の対象になると思っているのですが・・・あってますでしょうか???

    何度もすみませんが助けてください、お願いします。

     

     

     

     

    2006年5月22日 1:28
  • 原因は、MouseDownイベント時にはまだ行が選択状態になっていないためのようです。したがって、選択されている行を取得するルーチンを、MouseDownイベントから、DragDropイベントへ移動すれば良いかと思います。ちょっと私の検証が足りませんでした。ごめんなさい。これで動くかな・・・(ドキドキ)

    Private dragBoxFromMouseDown As Rectangle
    Private rowIndexFromMouseDown As Integer
    Private rowIndexOfItemUnderMouseToDrop As Integer
    Dim listRowIndexSelect As List(Of Integer) = New List(Of Integer) '選択された複数の行を保持します。

    Private Sub tESTDataGridView_MouseMove(sender As Object, e As MouseEventArgs)
       If(e.Button And MouseButtons.Left) = MouseButtons.Left Then
          ' If the mouse moves outside the rectangle, start the drag.
          If dragBoxFromMouseDown <> Rectangle.Empty And Not dragBoxFromMouseDown.Contains(e.X, e.Y) Then
            
             ' Proceed with the drag and drop, passing in the list item.
             Dim dropEffect As DragDropEffects = tESTDataGridView.DoDragDrop(tESTDataGridView.Rows(rowIndexFromMouseDown), DragDropEffects.Move)
          End If
       End If
    End Sub 'tESTDataGridView_MouseMove


    Private Sub tESTDataGridView_MouseDown(sender As Object, e As MouseEventArgs)
       ' Get the index of the item the mouse is below.
       rowIndexFromMouseDown = tESTDataGridView.HitTest(e.X, e.Y).RowIndex
      
       If rowIndexFromMouseDown <> - 1 Then
          ' Remember the point where the mouse down occurred.
          ' The DragSize indicates the size that the mouse can move
          ' before a drag event should be started.               
          Dim dragSize As Size = SystemInformation.DragSize
         
          ' Create a rectangle using the DragSize, with the mouse position being
          ' at the center of the rectangle.
          dragBoxFromMouseDown = New Rectangle(New Point(e.X - dragSize.Width / 2, e.Y - dragSize.Height / 2), dragSize)
       ' Reset the rectangle if the mouse is not over an item in the ListBox.
       Else
          dragBoxFromMouseDown = Rectangle.Empty
       End If
    End Sub 'tESTDataGridView_MouseDown

    Private Sub tESTDataGridView_DragOver(sender As Object, e As DragEventArgs)
       e.Effect = DragDropEffects.Move
    End Sub 'tESTDataGridView_DragOver


    Private Sub tESTDataGridView_DragDrop(sender As Object, e As DragEventArgs)

          listRowIndexSelect.Clear()
         
          Dim dgvr As DataGridViewRow
          For Each dgvr In  tESTDataGridView.Rows
             If dgvr.Selected Then
                listRowIndexSelect.Add(dgvr.Index)
             End If
          Next dgvr 

       ' 以下の3行は好み。行が反転されている場合のみ移動対象にする場合は以下の2行はコメントアウト。
       'そうではなく、行が反転されているかどうかにかかわらず、最後にクリックした行を移動させる場合は、以下の3行を生かす。
          If Not tESTDataGridView.Rows(rowIndexFromMouseDown).Selected Then
             listRowIndexSelect.Add(rowIndexFromMouseDown)
          End If 

       ' The mouse locations are relative to the screen, so they must be
       ' converted to client coordinates.
       Dim clientPoint As Point = tESTDataGridView.PointToClient(New Point(e.X, e.Y))
      
       ' Get the row index of the item the mouse is below.
       rowIndexOfItemUnderMouseToDrop = tESTDataGridView.HitTest(clientPoint.X, clientPoint.Y).RowIndex
      
       ' If the drag operation was a move then remove and insert the row.
       If e.Effect = DragDropEffects.Move Then
          ' get the row data from row before removing and add to new row
          Dim listDataRow As List(Of DataRow) = New List(Of DataRow'挿入する行を作成し、保持します。
          Dim rowIndex As Integer
          For Each rowIndex In  listRowIndexSelect
             Dim rowArray As Object() = testdbDataSet.TEST.Rows(rowIndex).ItemArray
             Dim row As DataRow = testdbDataSet.TEST.NewRow()
             row.ItemArray = rowArray
             listDataRow.Add(row)
          Next rowIndex
         
          '  remove old row and insert new row
          Dim index As Integer = 0
          Dim delcntBeforeRowIndexOfItemUnderMouseToDrop As Integer = 0 'ドロップ先の行以前に存在する選択された行数
          '選択された行を削除します。
          Dim rowIndex As Integer
          For Each rowIndex In  listRowIndexSelect
             '行を削除する度に行インデックスが一つ減るので、それを調整しながら削除
             testdbDataSet.TEST.Rows.RemoveAt((rowIndex - index))
             index += 1
            
             If rowIndex <= rowIndexOfItemUnderMouseToDrop Then
                delcntBeforeRowIndexOfItemUnderMouseToDrop += 1
             End If
          Next rowIndex
          '行を挿入します。ドロップ先の行以前にある行数分、ドロップ先行のインデックスが減ります。
          'なぜなら、すぐ上で行を削除しているからです。
          Dim i As Integer
          For i = listDataRow.Count - 1 To 0 Step -1
             testdbDataSet.TEST.Rows.InsertAt(listDataRow(i), rowIndexOfItemUnderMouseToDrop - delcntBeforeRowIndexOfItemUnderMouseToDrop)
          Next i
       End If
    End Sub 'tESTDataGridView_DragDrop

    2006年5月22日 2:27
    モデレータ
  • trapemiya様、ありがとうございます。

    希望通り動くようになりました。とても感謝ですmm(__)mm

    そうそう、行を挿入する時に、Indexが-1になるみたいなので太字のコード追加しました

    もっとスマートに書けたら良いのですが・・・・これあってますかねぇ

    例).1行から3行を選択して間違って3行目にDropしてしまった場合、

    rowIndexOfItemUnderMousToDrop = 2, delcntBeforeRowIndexOfItemUnderMouseToDrop = 3

    '行を挿入します。ドロップ先の行以前にある行数分、ドロップ先行のインデックスが減ります。
    'なぜなら、すぐ上で行を削除しているからです。
    Dim i As Integer
    For i = listDataRow.Count - 1 To 0 Step -1
         If rowIndexOfItemUnderMouseToDrop - delcntBeforeRowIndexOfItemUnderMouseToDrop <= -1 Then
              delcntBeforeRowIndexOfItemUnderMouseToDrop = rowIndexOfItemUnderMouseToDrop
          End If
          TestdbDataSet.TEST.Rows.InsertAt(listDataRow(i), rowIndexOfItemUnderMouseToDrop - delcntBeforeRowIndexOfItemUnderMouseToDrop)
    Next i

    2006年5月22日 9:26
  • >そうそう、行を挿入する時に、Indexが-1になるみたいなので太字のコード追加しました

    おっ、そうですね。確かに負の数になることありますね。(^^;

    >もっとスマートに書けたら良いのですが・・・・これあってますかねぇ

    基本的な考え方は良いと思いますが、
    rowIndexOfItemUnderMouseToDrop - delcntBeforeRowIndexOfItemUnderMouseToDrop
    の部分はForループの中で毎回計算する必要はないので(一度計算してしまえば良い)、Forループに入る手前で計算しておけばよいでしょう。
    私の最初のコードが悪いんですが。(^^;


    あと、全行選択された場合に困るので、ドロップした位置の行がセレクト状態である場合は、移動をキャンセル処理を入れた方が良いと思います。

    If tESTDataGridView.Rows(rowIndexOfItemUnderMouseToDrop).Selected Then
       Return
    End If
    2006年5月23日 1:02
    モデレータ
  • trapemiya様、ありがとうございました。

    作成中のプログラムに教えて頂いたコードを記述して

    無事に動きました。感動\(^o^)/

    またわからない事が出てきたときはよろしくお願いします。

     

     

     

    2006年5月23日 8:35