Back to Devexpress

VerticalGrid as the Source of Drag and Drop

windowsforms-490-controls-and-libraries-vertical-grid-drag-and-drop-ole-drag-and-drop-verticalgrid-as-the-source-of-drag-and-drop.md

latest17.6 KB
Original Source

VerticalGrid as the Source of Drag and Drop

  • Oct 29, 2020
  • 11 minutes to read

This topic provides an example of using a vertical grid as a source for OLE drag and drop operations. It shows how to customize the grid so that end-users can drag data records to different controls. For a general OLE drag and drop overview, please refer to the OLE Drag and Drop Overview topic.

Dragging Records from the Vertical Grid. A Detailed Description

You can use the code listed in this section to allow end-users to drag data records to other controls or applications. The code will handle the vertical grid’s MouseMove event to initiate dragging. The following main tasks are performed by the event handler:

  • Determine the element located under the mouse cursor. If the element is not a value cell, dragging is not initialized. Otherwise, the cell owner’s record index is obtained.
  • Obtain the values for the record located underneath the mouse cursor. Row header captions and their corresponding cell values are written to a string variable.
  • Initiate dragging. This is performed by using the DoDragDrop method call, the previously constructed string is now passed to this method as dragged data. The method enables copy and move operations to be performed by the target control.
  • Determine the results of the drag and drop operation. If the data needs to be moved, then the record is deleted from the vertical grid control’s data source.

Let’s consider the implementation of each step in detail. After they are all described, the code will be listed in its entirety.

First of all it is necessary to determine when the drag and drop operation should start. For this purpose, the MouseDown and MouseMove events will be handled. The MouseDown event handler will store the click point to a variable. The MouseMove event handler determines the mouse cursor’s offset position relative to the point stored in the MouseDown handler. If the offset does not exceed 10 pixels either horizontally or vertically, no further processing will occur. Note that the vertical grid should be set to a read only state when the mouse button is pressed, otherwise the current cell’s editor will be activated. So, the MouseUp event handler must be used to make the grid editable again.

csharp
Point startDragPoint;
bool dragging = false;

private void vGridControl1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   startDragPoint = new Point(e.X, e.Y);
   dragging = true;
   vGrid.OptionsBehavior.Editable = false;
}

private void vGridControl1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   dragging = false;
   vGrid.OptionsBehavior.Editable = true;
}

private void vGridControl1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
   if (!dragging) return;
   int deltaX = e.X - startDragPoint.X;
   int deltaY = e.Y - startDragPoint.Y;
   if ((Math.Abs(deltaX) < 10) && (Math.Abs(deltaY) < 10)) return;
   // ...
}
vb
Dim StartDragPoint As Point
Dim Dragging As Boolean = False
Private Sub VGridControl1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseDown
   Dim vGrid As VGridControl = sender
   StartDragPoint = New Point(e.X, e.Y)
   Dragging = True
   vGrid.OptionsBehavior.Editable = False
End Sub

Private Sub VGridControl1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseUp
   Dim vGrid As VGridControl = sender
   Dragging = False
   vGrid.OptionsBehavior.Editable = True
End Sub

Private Sub VGridControl1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseMove
   If Not Dragging Then Exit Sub
   Dim DeltaX As Integer = e.X - StartDragPoint.X
   Dim DeltaY As Integer = e.Y - StartDragPoint.Y
   If Math.Abs(DeltaX) < 10 And Math.Abs(DeltaY) < 10 Then Exit Sub
   ' ...
End Sub

To determine the element located underneath the mouse cursor, you will need to use the VGridControlBase.CalcHitInfo method. This method accepts a point as a parameter and returns an object containing information about what resides at the point passed to it. This object’s properties can be used to determine the element type which resides at the specified coordinates and determine the row, record, cell and band where the point is located. Please refer to the Obtain Hit Information topic for details on using this VGridControlBase.CalcHitInfo method and the object returned.

The sample code below is part of the MouseMove event handler which is used to determine the record located under the drag and drop starting point.

csharp
private void vGridControl1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   // ...
   VGridHitInfo hitInfo = vGrid.CalcHitInfo(startDragPoint);
   int recordIndex = hitInfo.RecordIndex;
   if (recordIndex == -1) return;
   // ...
}
vb
Private Sub VGridControl1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseMove
   Dim vGrid As VGridControl = sender
   ' ...
   Dim HitInfo As VGridHitInfo = vGrid.CalcHitInfo(StartDragPoint)
   Dim RecordIndex As Integer = HitInfo.RecordIndex
   If RecordIndex = -1 Then Exit Sub
   ' ...
End Sub

The next step to perform is to construct a string to represent the dragged data. This string is constructed of row captions and their corresponding cell values separated by a carriage return. For multi-editor rows captions and values for each row item are separated from each other using the ‘|’ character. To construct such a string, it is necessary to visit each row within the control. This is performed by means of the Rows Iterator.

The code below shows how to construct the desired string. The operation class used to obtain cell values is declared. Then a portion of the MouseMove event handler is listed. It uses the rows iterator to execute the declared operation.

csharp
public class GetRecordValuesOperation : RowOperation {
   int recordIndex;
   VGridControl grid;
   string cellValues;
   public GetRecordValuesOperation(VGridControl grid, int recordIndex) : base() {
      this.recordIndex = recordIndex;
      this.grid = grid;
      this.cellValues = "";
   }
   public override void Execute(BaseRow row) {
      if (row is EditorRow)
         cellValues += row.Properties.Caption + ": " + grid.GetCellValue(row, recordIndex).ToString() + "\n";
      else if (row is MultiEditorRow) {
         MultiEditorRow meRow = row as MultiEditorRow;
         string meRowValues = "";
         foreach (MultiEditorRowProperties props in meRow.PropertiesCollection)
            meRowValues += props.Caption + ": " + grid.GetCellValue(props, recordIndex).ToString() + " | ";
         cellValues += meRowValues.Substring(0, meRowValues.Length - 3) + "\n";
      }
   }
   public string CellValues { get { return cellValues; } }
}

private void vGridControl1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   // ...
   GetRecordValuesOperation operation = new GetRecordValuesOperation(vGrid, recordIndex);
   vGrid.RowsIterator.DoOperation(operation);
   string dragData = operation.CellValues;
   // ...
}
vb
Public Class GetRecordValuesOperation
   Inherits RowOperation
   Dim RecordIndex As Integer
   Dim Grid As VGridControl
   Dim _CellValues As String
   Public Sub New(ByVal Grid As VGridControl, ByVal RecordIndex As Integer)
      MyBase.New()
      Me.RecordIndex = RecordIndex
      Me.Grid = Grid
      Me._CellValues = ""
   End Sub
   Public Overrides Sub Execute(ByVal Row As BaseRow)
      If TypeOf Row Is EditorRow Then
         _CellValues += Row.Properties.Caption + ": " + Grid.GetCellValue(Row, RecordIndex).ToString() + vbCrLf
      End If
      If TypeOf Row Is MultiEditorRow Then
         Dim MERow As MultiEditorRow = Row
         Dim MERowValues As String = ""
         Dim Props As MultiEditorRowProperties
         For Each Props In MERow.PropertiesCollection
            MERowValues += Props.Caption + ": " + Grid.GetCellValue(Props, RecordIndex).ToString() + " | "
         Next
         _CellValues += MERowValues.Substring(0, MERowValues.Length - 3) + vbCrLf
      End If
   End Sub
   Public ReadOnly Property CellValues() As String
      Get
         Return _CellValues
      End Get
   End Property
End Class

Private Sub VGridControl1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseMove
   Dim vGrid As VGridControl = sender
   ' ...
   Dim Operation As New GetRecordValuesOperation(vGrid, HitInfo.RecordIndex)
   vGrid.RowsIterator.DoOperation(Operation)
   Dim DragData As String = Operation.CellValues
   ' ...
End Sub

Once the data to drag has been obtained, the drag and drop operation can start. This is performed using the following line of code:

csharp
private void vGridControl1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   // ...
   DragDropEffects effect = vGrid.DoDragDrop(dragData, DragDropEffects.Copy | DragDropEffects.Move);
   // ...
}
vb
Private Sub VGridControl1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseMove
   Dim vGrid As VGridControl = sender
   ' ...
   Dim Effect As DragDropEffects = vGrid.DoDragDrop(DragData, DragDropEffects.Copy Or DragDropEffects.Move)
   ' ...
End Sub

The DoDragDrop method called in the line of code above returns a value after the drag and drop operation completes. This value needs to be evaluated since it determines the type of action performed, either copying or moving data. If the data has been moved, the dragged record needs to be deleted. The code below shows how this can be performed. It assumes that a DataTable object is used as the vertical grid control’s data source.

csharp
private void vGridControl1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   // ...
   if (effect == DragDropEffects.Move) {
      (vGrid.DataSource as DataTable).Rows.RemoveAt(recordIndex);
      oleDbDataAdapter1.Update(vGrid.DataSource as DataTable);
   }
}
vb
Private Sub VGridControl1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseMove
   Dim vGrid As VGridControl = sender
   ' ...
   If Effect = DragDropEffects.Move Then
      Dim SourceTable As DataTable = vGrid.DataSource
      SourceTable.Rows.RemoveAt(RecordIndex)
      OleDbDataAdapter1.Update(SourceTable)
   End If
End Sub

Please refer to the Adding and Deleting Records topic for details on how to delete records in the VGridControl control.

Dragging Records from the Vertical Grid. The Complete Code

Below is the entire code needed to drag records from the VGridControl control.

csharp
using DevExpress.XtraVerticalGrid;
using DevExpress.XtraVerticalGrid.Rows;
// ...
Point startDragPoint;
bool dragging = false;

private void vGridControl1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   startDragPoint = new Point(e.X, e.Y);
   dragging = true;
   vGrid.OptionsBehavior.Editable = false;
}

private void vGridControl1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   dragging = false;
   vGrid.OptionsBehavior.Editable = true;
}

private void vGridControl1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
   VGridControl vGrid = sender as VGridControl;
   if (!dragging) return;
   int deltaX = e.X - startDragPoint.X;
   int deltaY = e.Y - startDragPoint.Y;
   if ((Math.Abs(deltaX) < 10) && (Math.Abs(deltaY) < 10)) return;
   VGridHitInfo hitInfo = vGrid.CalcHitInfo(startDragPoint);
   int recordIndex = hitInfo.RecordIndex;
   if (recordIndex == -1) return;
   GetRecordValuesOperation operation = new GetRecordValuesOperation(vGrid, hitInfo.RecordIndex);
   vGrid.RowsIterator.DoOperation(operation);
   string dragData = operation.CellValues;
   DragDropEffects effect = vGrid.DoDragDrop(dragData, DragDropEffects.Copy | DragDropEffects.Move);      
   if (effect == DragDropEffects.Move) {
      (vGrid.DataSource as DataTable).Rows.RemoveAt(recordIndex);
      oleDbDataAdapter1.Update(vGrid.DataSource as DataTable);
   }
}

public class GetRecordValuesOperation : RowOperation {
   int recordIndex;
   VGridControl grid;
   string cellValues;
   public GetRecordValuesOperation(VGridControl grid, int recordIndex) : base() {
      this.recordIndex = recordIndex;
      this.grid = grid;
      this.cellValues = "";
   }
   public override void Execute(BaseRow row) {
      if (row is EditorRow)
         cellValues += row.Properties.Caption + ": " + grid.GetCellValue(row, recordIndex).ToString() + "\n";
      else if (row is MultiEditorRow) {
         MultiEditorRow meRow = row as MultiEditorRow;
         string meRowValues = "";
         foreach (MultiEditorRowProperties props in meRow.PropertiesCollection)
            meRowValues += props.Caption + ": " + grid.GetCellValue(props, recordIndex).ToString() + " | ";
         cellValues += meRowValues.Substring(0, meRowValues.Length - 3) + "\n";
      }
   }
   public string CellValues { get { return cellValues; } }
}
vb
Imports DevExpress.XtraVerticalGrid
Imports DevExpress.XtraVerticalGrid.Rows
' ...

Dim StartDragPoint As Point
Dim Dragging As Boolean = False
Private Sub VGridControl1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseDown
   Dim vGrid As VGridControl = sender
   StartDragPoint = New Point(e.X, e.Y)
   Dragging = True
   vGrid.OptionsBehavior.Editable = False
End Sub

Private Sub VGridControl1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseUp
   Dim vGrid As VGridControl = sender
   Dragging = False
   vGrid.OptionsBehavior.Editable = True
End Sub

Private Sub VGridControl1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles VGridControl1.MouseMove
   Dim vGrid As VGridControl = sender
   If Not Dragging Then Exit Sub
   Dim DeltaX As Integer = e.X - StartDragPoint.X
   Dim DeltaY As Integer = e.Y - StartDragPoint.Y
   If Math.Abs(DeltaX) < 10 And Math.Abs(DeltaY) < 10 Then Exit Sub
   Dim HitInfo As VGridHitInfo = vGrid.CalcHitInfo(StartDragPoint)
   Dim RecordIndex As Integer = HitInfo.RecordIndex
   If RecordIndex = -1 Then Exit Sub
   Dim Operation As New GetRecordValuesOperation(vGrid, HitInfo.RecordIndex)
   vGrid.RowsIterator.DoOperation(Operation)
   Dim DragData As String = Operation.CellValues
   Dim Effect As DragDropEffects = vGrid.DoDragDrop(DragData, DragDropEffects.Copy Or DragDropEffects.Move)
   If Effect = DragDropEffects.Move Then
      Dim SourceTable As DataTable = vGrid.DataSource
      SourceTable.Rows.RemoveAt(RecordIndex)
      OleDbDataAdapter1.Update(SourceTable)
   End If
End Sub

Public Class GetRecordValuesOperation
   Inherits RowOperation
   Dim RecordIndex As Integer
   Dim Grid As VGridControl
   Dim _CellValues As String
   Public Sub New(ByVal Grid As VGridControl, ByVal RecordIndex As Integer)
      MyBase.New()
      Me.RecordIndex = RecordIndex
      Me.Grid = Grid
      Me._CellValues = ""
   End Sub
   Public Overrides Sub Execute(ByVal Row As BaseRow)
      If TypeOf Row Is EditorRow Then
         _CellValues += Row.Properties.Caption + ": " + Grid.GetCellValue(Row, RecordIndex).ToString() + vbCrLf
      End If
      If TypeOf Row Is MultiEditorRow Then
         Dim MERow As MultiEditorRow = Row
         Dim MERowValues As String = ""
         Dim Props As MultiEditorRowProperties
         For Each Props In MERow.PropertiesCollection
            MERowValues += Props.Caption + ": " + Grid.GetCellValue(Props, RecordIndex).ToString() + " | "
         Next
         _CellValues += MERowValues.Substring(0, MERowValues.Length - 3) + vbCrLf
      End If
   End Sub
   Public ReadOnly Property CellValues() As String
      Get
         Return _CellValues
      End Get
   End Property
End Class

The image below shows an example of moving record values to a Microsoft Word document.