Previous Section  < Day Day Up >  Next Section

7.8. Using Drag and Drop with Controls

The ability to drag data from one control and drop it onto another has long been a familiar feature of GUI programming. .NET supports this feature with several classes and enumerations that enable a control to be the target and/or source of the drag-and-drop operation.

Overview of Drag and Drop

The operation requires a source control that contains the data to be moved or copied, and a target control that receives the dragged data. The source initiates the action in response to an event梪sually a MouseDown event. The source control's event handler begins the actual operation by invoking its DoDragDrop method. This method has two parameters: the data being dragged and a DragDropEffects enum type parameter that specifies the effects or actions the source control supports (see Table 7-4).

Table 7-4. DragDropEffects Enumeration

Member

Description

All

The data is moved to the target control, and scrolling occurs in the target control to display the newly positioned data.

Copy

Data is copied from target to source.

Link

Data from the source is linked to the target.

Move

The data is moved from the source to the target control.

None

The target control refuses to accept data.

Scroll

Scrolling occurs or will occur on the target control.


As the mouse moves across the form, the DoDragDrop method determines the control under the current cursor location. If this control has its AllowDrop property set to TRue, it is a valid drop target and its DragEnter event is raised. The DragEnter event handler has two tasks: to verify that the data being dragged is an acceptable type and to ensure the requested action (Effect) is acceptable. When the actual drop occurs, the destination control raises a DragDrop event. This event handler is responsible for placing the data in the target control (see Figure 7-18).

Figure 7-18. Sequence of events in drag-and-drop operation


After the DragDrop event handler finishes, the source control performs any cleanup operations. For example, if the operation involves moving data梐s opposed to copying梩he data must be removed from the source control.

To demonstrate these ideas, let's create an application that assigns players to a team from a roster of available players (see Figure 7-19). Team A is created by dragging names from the Available Players to the Team A list. Both lists are implemented with list boxes, and the Available Players list is set for single selection.

Figure 7-19. Drag-and-drop example


A name is selected by pressing the right mouse button and dragging the name to the target list. To add some interest, holding the Ctrl key copies a name rather than moving it.

After the form and controls are created, the first step is to set up the source control (lstPlayers) to respond to the MouseDown event and the target control (lstTeamA) to handle the DragEnter and DragDrop events:


lstPlayers.MouseDown += 

      new MouseEventHandler(Players_MouseDown);

lstTeamA.DragEnter   += new DragEventHandler(TeamA_DragEnter);

lstTeamA.DragDrop    += new DragEventHandler(TeamA_Drop);


The next step is to code the event handlers on the source and target control(s) that implement the drag-and-drop operation.

Source Control Responsibilities

The MouseDown event handler for the source ListBox first checks to ensure that an item has been selected. It then calls DoDragDrop, passing it the value of the selected item as well as the acceptable effects: Move and Copy. The DragDropEffects enumeration has a FlagsAttribute attribute, which means that any bitwise combination of its values can be passed. The value returned from this method is the effect that is actually used by the target. The event handler uses this information to perform any operations required to implement the effect. In this example, a move operation means that the dragged value must be removed from the source control.

Listing 7-7. Initiating a Drag-and-Drop Operation from the Source Control

private void Players_MouseDown(object sender, MouseEventArgs e)

{

   if ( lstPlayers.SelectedIndex >=0)

   {

      string players;

      int ndx = lstPlayers.SelectedIndex;

      DragDropEffects effect;

      players = lstPlayers.Items[ndx].ToString();

      if(players != "")

      {

         // Permit target to move or copy data

         effect = lstPlayers.DoDragDrop(players, 

               DragDropEffects.Move | DragDropEffects.Copy);

         // Remove item from ListBox since move occurred

         if (effect == DragDropEffects.Move) 

         lstPlayers.Items.RemoveAt(ndx);

      }

   }

}


Target Control Responsibilities

The destination control must implement the event handlers for the DragEnter and DragDrop events. Both of these events receive a DragEventArgs type parameter (see Table 7-5) that contains the information required to process the drag-and-drop event.

Table 7-5. DragEventArgs Properties

Member

Description

AllowedEffect

The effects that are supported by the source control.

Example to determine if Move is supported:


if ((e.AllowedEffect & DragDropEffects.Move) ==

   DragDropEffects.Move)


Data

Returns the IDataObject that contains data associated with this operation. This object implements methods that return information about the data. These include Getdata, which fetches the data, and GeTDataPresent, which checks the data type.

Effect

Gets or sets the target drop effect.

KeyState

Returns the state of the Alt key, Ctrl key, Shift key, and mouse buttons as an integer:

1桳eft mouse button

8桟trl key

2桼ight mouse button

16桵iddle mouse button

4桽hift key

32桝lt key

X, Y

x and y coordinates of the mouse pointer.


The Data, Effect, and KeyState members are used as follows:

  • Data.GetDataPresent is used by the DragEnter event handler to ensure that the data is a type the target control can process.

  • The DragDrop event handler uses Data.GetData to access the data being dragged to it. The parameter to this method is usually a static field of the DataFormats class that specifies the format of the returned data.

  • The DragEnter event handler uses KeyState to determine the status of the mouse and keys in order to determine the effect it will use to process the data. Recall that in this example, pressing the Ctrl key signals that data is to copied rather than moved.

  • Effect is set by the DragEnter event handler to notify the source as to how梠r if梚t processed the data. A setting of DragDropEffects.None prevents the DragDrop event from firing.

Listing 7-8 shows the code for the two event handlers.

Listing 7-8. Handling the DragEnter and DragDrop Events

[FlagsAttribute]

enum KeyPushed

{

   // Corresponds to DragEventArgs.KeyState values

   LeftMouse   = 1,

   RightMouse  = 2,

   ShiftKey    = 4,

   CtrlKey     = 8,

   MiddleMouse = 16,

   AltKey      = 32,

}

private void TeamA_DragEnter(object sender, DragEventArgs e)

{

   KeyPushed kp = (KeyPushed) e.KeyState;

   // Make sure data type is string

   if (e.Data.GetDataPresent(typeof(string)))

   {

      // Only accept drag with left mouse key

      if ( (kp & KeyPushed.LeftMouse) == KeyPushed.LeftMouse) 

      {

         if ((kp & KeyPushed.CtrlKey) == KeyPushed.CtrlKey)

         {

            e.Effect = DragDropEffects.Copy;    // Copy

         }

         else

         {

            e.Effect = DragDropEffects.Move;  // Move 

         }

      }

      else  // Is not left mouse key

      {

         e.Effect = DragDropEffects.None;

      }

   } else    // Is not a string

   {

      e.Effect = DragDropEffects.None;

   }

}

// Handle DragDrop event

private void TeamA_Drop(object sender, DragEventArgs e)

{

   // Add dropped data to TextBox

   lstTeamA.Items.Add( 

      (string) e.Data.GetData(DataFormats.Text));

}


An enum is created with the FlagsAttributes attribute to make checking the KeyState value easier and more readable. The logical "anding" of KeyState with the value of the CtrlKey (8) returns a value equal to the value of the CtrlKey if the Ctrl key is pressed.

A control can serve as source and target in the same application. You could make this example more flexible by having the list boxes assume both roles. This would allow you to return a player from lstTeamA back to the lstPlayers ListBox. All that is required is to add the appropriate event handlers.

Core Note

Drag and drop is not just for text. The DataFormats class predefines the formats that can be accepted as static fields. These include Bitmap, PenData, WaveAudio, and numerous others.


    Previous Section  < Day Day Up >  Next Section