Click here to Skip to main content
15,879,535 members
Articles / Programming Languages / C#
Article

How to drag information from a DataGridView control

Rate me:
Please Sign up or sign in to vote.
4.41/5 (25 votes)
28 Dec 20054 min read 208.3K   73   24
Sample code that shows how to drag bound information from the DataGridView control to another control (i.e. ListBox).

Introduction

While doing some recent home-work, I needed to figure out how to implement drag-and-drop from a DataGridView control. I had two main controls on the form: a ListBox that contained a list of categories, and a DataGridView control that contained a list of products associated with that category. To keep things simple, I wanted to be able to drag a product from the Grid to the ListBox to change a product's category.

Starting the Drag-and-Drop

The first thing I did was to attach an event handler to the DataGridView's MouseDown event. Because the DataGridView monopolizes the left mouse button, and it is very efficient at performing updates, inserts, and deletes, I decided to use the right mouse button for drag-and-dropping. I didn't need context menus. (Otherwise, I would have considering RMB + Alt/Shift/Ctrl clicking).

C#
void grdCampaigns_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
      DataGridView.HitTestInfo info = grdCampaigns.HitTest(e.X, e.Y);
      if (info.RowIndex >= 0)
      {
        DataRowView view = (DataRowView)
               grdCampaigns.Rows[info.RowIndex].DataBoundItem;
        if (view != null)
          grdCampaigns.DoDragDrop(view, DragDropEffects.Copy);
    }
  }
}

The code tests for the right mouse Button. If the RMB was pressed, I performed a HitTest using the x and y components of the MouseEventArgs. Because the RMB does not natively interact with the DataGridView, clicking the RMB will not select a row. If the user clicks the fourth row, and the first row was selected (from before), they will unwittingly drag the first row, rather than the fourth row. It was not intuitive at all.

So I used the information returned by HitTest to ensure I was working with the row and the column under the mouse pointer, rather than the previously selected row, which made the program much more intuitive.

After checking to make sure the data was valid, I passed the DataRowView into the DoDragDrop event, which started the drag-and-drop operation.

Preparing for the Drop

All the above preparation is useless without having a target to drop the information in. To that end, you need to prepare a drop target. If you are working with standard data types, this may not be necessary. Some support may be there already. This is especially true of strings. For more complex data types, however, such as a DataRowView (with which I was working), you will need to provide the plumbing yourself.

This is actually rather easy. First, you need to tell the target it is available for drag-and-drop operations. This is done by setting the AllowDrop property of most controls to true. Secondly, you need to add code to the DragEnter event of the control.

C#
void lstCategories_DragEnter(object sender, DragEventArgs e)
{
  e.Effect = DragDropEffects.Copy;
}

You can use whatever effect you want, but it should match the effect you used in the DoDragDrop method called earlier, when starting the drag. When I tried drag-and-drop without this line of code, it did not work.

Implementing the Drop

The last step is to implement the DragDrop event of the target control, and manipulate the data.

C#
void lstCategories_DragDrop(object sender, DragEventArgs e)
{
  if (e.Data.GetDataPresent(typeof(DataRowView)))
  {
    // Determine which category the item was draged to
    Point p = lstCategories.PointToClient(new Point(e.X,e.Y));
    int index = lstCategories.IndexFromPoint(p);
    if (index >= 0)
    {
      // Get references to the category and campaign
      DataRowView category = (DataRowView)lstCategories.Items[index];
      DataRowView campaign = (DataRowView)
                              e.Data.GetData(typeof(DataRowView));
      // Get the old and new category ids
      int newID = (int)category[0];
      int oldID = (int)campaign[1];
      // Make sure the two do not match
      if (oldID != newID)
      {
        campaign.BeginEdit();
        campaign[1] = newID;
        campaign.EndEdit();
      }
    }
  }
}

The first step I performed in the drag-drop was to ensure the type of data being dropped was the type I expected to receive. This can be done through the GetDataPresent method, which accepts as its parameter a data type, and returns true if that type is present.

Once I was sure I had valid data--or at least the right data type--I got screen coordinates where the DragDrop operation ended. Like the DataGridView control before it, I had no idea where the data was going. The user could drag the product on any visible category: I had to figure out which one.

That was accomplished through the IndexFromPoint method. However, documentation on this particular method is very poor, and Microsoft fails to note that you need CLIENT coordinates for this to work, not SCREEN coordinates. So, before you can call IndexFromPoint, you need to convert coordinates from screen to client coordinates using the appropriately named PointToClient method.

Once I determined (and verified) the category, I cast references to data items for both the category and the product (campaign). To save unnecessary processing, I checked to make sure the category was in fact different.

I should point out at this time that I was working with a strongly-typed DataSet, with two tables: Categories and Campaigns. Both contained the column CategoryID; CategoryID is the primary key of Categories, and was used for reference in Campaigns. The ListBox used in the examples was bound to the Categories table in the dataset. Whenever the Categories list selection changed, a DataView of child rows was retrieved from the DataSet, and bound to the DataGridView control.

The significance of this point is that when I edit the CategoryID of the campaign DataRowView in the example above, the associated product listing is removed from the grid, because the CategoryID no longer qualifies the product to be in the grid (it is no longer a child of the current category). When the user clicks on the category to which the product was moved, however, the product will appear in that listing, instead.

All in all, the code performed exactly what I wanted: it was simple, it worked, and it was intuitive for the user. I doubt I could have duplicated the results with less code or time any other way.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 3 Pin
vasim sajad26-Sep-12 18:35
vasim sajad26-Sep-12 18:35 
QuestionDidn't understand anything ... Source code? Pin
zahid7821-Oct-09 12:00
zahid7821-Oct-09 12:00 
GeneralDragging multiple items on left mouse Pin
Ian M Spencer1-Sep-09 13:30
Ian M Spencer1-Sep-09 13:30 
QuestionDraging one column to another datagridview Pin
Pappan28-May-09 23:01
Pappan28-May-09 23:01 
GeneralI wanted to be able to drag a product from the ListView to the Grid Pin
Natashasv14-Jan-09 19:40
Natashasv14-Jan-09 19:40 
GeneralI think this way would be better Pin
Member 434214220-Nov-08 4:33
Member 434214220-Nov-08 4:33 
QuestionHas anyone VB.NET version? Pin
Jo Raleigh12-Nov-08 5:41
Jo Raleigh12-Nov-08 5:41 
AnswerRe: Has anyone VB.NET version? Pin
MarioRDJ3-Sep-09 6:08
MarioRDJ3-Sep-09 6:08 
GeneralUsability Pin
mr_lasseter9-Oct-07 11:01
mr_lasseter9-Oct-07 11:01 
General.Net 2003 dataGrid component Pin
N3CAT13-Jul-07 4:48
N3CAT13-Jul-07 4:48 
GeneralHelp please Pin
noha8613-Jun-07 10:49
noha8613-Jun-07 10:49 
QuestionHow u people Resize the rows if we give Mouse button Lef Pin
winheart3-Apr-07 19:09
winheart3-Apr-07 19:09 
GeneralDragging using the left mouse button Pin
jjerry8330-Mar-07 0:20
jjerry8330-Mar-07 0:20 
GeneralRe: Dragging using the left mouse button Pin
Yves Goergen3-Feb-08 0:33
Yves Goergen3-Feb-08 0:33 
Sorry, but it doesn't work. It has the same problem that any other DataGridView drag&drop code I've seen by now has: The selection is always reduced to the row that was clicked on to start dragging. Dragging multiple selected rows is not possible with it.
GeneralRe: Dragging using the left mouse button Pin
neminem14-Feb-11 10:30
neminem14-Feb-11 10:30 
GeneralDataGridViewSelectedRows Pin
César de Souza17-Feb-07 14:59
professionalCésar de Souza17-Feb-07 14:59 
QuestionOne issue about right button Pin
micblues5-Feb-07 19:53
micblues5-Feb-07 19:53 
GeneralThanks Pin
Josh Smith19-Jan-07 10:55
Josh Smith19-Jan-07 10:55 
GeneralRe: Thanks Pin
Jacquers9-Sep-07 21:31
Jacquers9-Sep-07 21:31 
GeneralSource please.... :( Pin
Nuno Agapito11-Dec-06 12:05
Nuno Agapito11-Dec-06 12:05 
GeneralVery good example! Pin
loizzi16-Jun-06 15:11
loizzi16-Jun-06 15:11 
GeneralDatagridview rotate Pin
horvat9-May-06 19:55
horvat9-May-06 19:55 
Generalnamespace problem Pin
idreesbadshah30-Jan-06 8:02
idreesbadshah30-Jan-06 8:02 
GeneralRe: namespace problem Pin
renzea30-Jan-06 12:59
renzea30-Jan-06 12:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.