Skip to main content

VGridControlBase.StartDragRow Event

Fires before a row is dragged by an end-user.

Namespace: DevExpress.XtraVerticalGrid

Assembly: DevExpress.XtraVerticalGrid.v23.2.dll

NuGet Packages: DevExpress.Win.Navigation, DevExpress.Win.VerticalGrid

Declaration

public event StartDragRowEventHandler StartDragRow

Event Data

The StartDragRow event's data class is StartDragRowEventArgs. The following properties provide information specific to this event:

Property Description
Effect Gets or sets an effect available for the processed drag and drop operation. Inherited from DragRowEventArgs.
Row Gets the processed row. Inherited from RowEventArgs.
ScreenLocation Gets a point representing the current mouse cursor position. Inherited from DragRowEventArgs.
Source Gets a value indicating where the processed drag operation starts.

Remarks

The vertical grid allows custom row dragging to be implemented (for instance, dragging rows to external controls). This implies processing row drag and drop operations by handling a set of native drag-specific events that are introduced by the vertical grid.

These events occur in the following order:

For detailed information, see Dragging Rows.

Example

This example demonstrates how you can handle native drag specific grid events in order to combine a dragged row with the targeted one in a single multi-editor row. The example implies that an editor row dragged from the Customization Form can only be dropped onto the headers of editor or multi-editor rows. In a case when the target is a multi-editor row, a dropped row is inserted as a new row item for the target row. When dropping a row onto the header cell of the targeted editor row, both rows (dropped and target) are deleted from the grid and a multi-editor row with two row items is created instead. The created row items copy base row settings from the deleted rows. The position of the drop point inside the header cell of the target row (row item) affects the index of the new row item created for the dropped row.

Note that the example uses information from the BaseViewInfo object available via the VGridControlBase.ViewInfo property in order to properly calculate the targeted header cell’s bounds. The following picture illustrates the base view info notions used in the example.

Native_DragDrop_ViewInfos

The image below displays the process of handling row drag & drop operations using the code in this example.

anim_NativeDragDrop

If you want to split a multi-editor row into several editor rows you can use the code provided by the Dragging Rows topic.

using DevExpress.XtraVerticalGrid.Rows;
using DevExpress.XtraVerticalGrid.Events;

 private void vGridControl1_ProcessDragRow(object sender, DragRowEventArgs e) {
    VGridControl vGrid = (sender as VGridControl);
    // checking whether a row is dragged from the Customization Form
    if (!((vGrid.CustomizationForm != null) && (vGrid.CustomizationForm.PressedRow != null))) 
        return;
    // checking whether an editor row is dragged
    if (!(e.Row is EditorRow)) return;
    // obtaining information about a point under the mouse cursor
    VGridHitInfo hitInfo = vGrid.CalcHitInfo(vGrid.PointToClient(e.ScreenLocation)); 
    // checking whether a row is dragged over the Customization Form or over a category row
    if (!((hitInfo.HitInfoType != HitInfoTypeEnum.CustomizationForm) && (hitInfo.Row != null) && 
       (!(hitInfo.Row is CategoryRow)))) {
        e.Effect = RowDragEffect.None;
        return;
    }
    // obtaining specific custom information about the mouse cursor point
    PointInfo pInfo = GetPointInfo(hitInfo.Row, e.ScreenLocation); 
    // allowing row dropping is a point belongs to target row's header
    if (pInfo.IsContained) e.Effect = RowDragEffect.InsertBefore; 
    // restricting row dropping in the other case
    else e.Effect = RowDragEffect.None; 
}

private void vGridControl1_EndDragRow(object sender, EndDragRowEventArgs e) {
    VGridControl vGrid = (sender as VGridControl);
    // checking whether a row from the Customization Form is dropped
    if (!((vGrid.CustomizationForm != null) && (vGrid.CustomizationForm.PressedRow != null))) 
        return;
    // checking whether an editor row is dropped
    if (!(e.Row is EditorRow)) return;
    // obtaining information about a point under the mouse cursor
    VGridHitInfo hitInfo = vGrid.CalcHitInfo(vGrid.PointToClient(e.ScreenLocation)); 
    // checking whether a row is dropped onto the Customization Form or a category row
    if (!((hitInfo.HitInfoType != HitInfoTypeEnum.CustomizationForm) && 
        (hitInfo.Row != null) && (!(hitInfo.Row is CategoryRow)))) {
        e.Effect = RowDragEffect.None;
        return;
    }
    BaseRow targetRow = hitInfo.Row;
    // obtaining specific custom information about the mouse cursor point
    PointInfo pInfo = GetPointInfo(hitInfo.Row, e.ScreenLocation); 
    if (!(pInfo.IsContained)) {
        // if the header rectangle does not contain the drop point, 
        // a drop operation is not processed
        e.Effect = RowDragEffect.None; 
        return;
    }
    // specifying the cursor feedback for the processed drop operation
    e.Effect = RowDragEffect.InsertBefore; 
    // preserving children of the dropped row from being deleted
    if (e.Row.HasChildren) PreserveChildren(e.Row); 
    switch (targetRow.XtraRowTypeID){
        case 1: // the target is an editor row
            // preserving children of the target row from being deleted
            if (targetRow.HasChildren) PreserveChildren(targetRow); 
            // substituting the dropped and target rows with a new multi-editor row
            CreateMERow(e.Row, targetRow, pInfo.DroppedBefore); 
            break;
        case 2: // the target is a multi-editor row
            // inserting the dropped row as a new row item to the target multi-editor row
            InsertRowItem(e.Row, (targetRow as MultiEditorRow), pInfo.RowItemIndex, pInfo.DroppedBefore); 
            break;
    }
}

public Rectangle CalcHeaderCellRect(BaseRow row, int cellIndex){
    // this function uses grid's view info to properly calculate a rectangle 
    // occupied by the target row header cell
    VGridControl grid = row.Grid;
    // obtaining the header cell rectangle of the processed row item specified by the index
    Rectangle headerCellRect = (grid.ViewInfo[row].headerInfo.CaptionsInfo[cellIndex] 
      as RowCaptionInfo).CaptionRect;
    if (cellIndex == 0){
        // obtaining the number of row indent elements
        int rowIndentsCount = grid.ViewInfo[row].headerInfo.RowIndents.Count; 
        if (rowIndentsCount != 0) {
            // recalculating the rectangle for the first header cell 
            // since it visually comprises the last row indent element
            int leftPos = grid.ViewInfo[row].headerInfo.RowIndents[rowIndentsCount - 1].Bounds.Left;
            headerCellRect.Width += headerCellRect.X - leftPos;        
            headerCellRect.X = leftPos;
        }
    }
    return headerCellRect;
}

public struct PointInfo {
    public bool IsContained;
    public int RowItemIndex;
    public bool DroppedBefore;
}

public PointInfo GetPointInfo(BaseRow row, Point point){
    PointInfo pInfo = new PointInfo();
    // transforming screen coordinates of the cursor position to grid client ones
    Point mouseClientPoint = row.Grid.PointToClient(point); 
    // checking whether the mouse cursor is positioned 
    // within a particular header cell of the processed row
    for (int i = 0; i < row.RowPropertiesCount; i++){
        // obtaining the header cell rectangle of the processed row item
        Rectangle headerCellRect = CalcHeaderCellRect(row, i); 
        // checking whether the header cell rectangle contains the drop point
        // collecting information about the point if it is contained in a header cell rectangle
        if (headerCellRect.Contains(mouseClientPoint)) { 
            pInfo.IsContained = true;
            // calculating the middle point of the target row's header cell
            int headerCellMiddle = (headerCellRect.Left + headerCellRect.Right) / 2; 
            // calculating whether the dropped row should be inserted before the processed row item
            pInfo.DroppedBefore = (mouseClientPoint.X < headerCellMiddle) ? true : false; 
            // specifying the index of the row item whose header cell contains the point
            pInfo.RowItemIndex = i; 
            return pInfo;
        }
    }
    // the specified point does not belong to the target row's header
    pInfo.IsContained = false; 
    return pInfo;
}

public void PreserveChildren(BaseRow row){
    // this procedure moves children of the specified row to the top-level row collection 
    // and hides them in the Customization Form
    ArrayList rowList = new ArrayList(row.ChildRows);
    foreach (BaseRow childRow in rowList){
        childRow.Grid.MoveRow(childRow, childRow.Grid.Rows[0],true);
        childRow.Visible = false;
    }
}

public void CreateMERow (BaseRow source, BaseRow dest, bool droppedFirst){
    // this procedure creates a new multi-editor row with two  row items initialized 
    //with corresponding rows' property values 
    MultiEditorRow meRow = new MultiEditorRow();
    MultiEditorRowProperties sourceRowItem = new MultiEditorRowProperties();
    CopyProperties(source.Properties, (sourceRowItem as RowProperties));
    MultiEditorRowProperties destRowItem = new MultiEditorRowProperties();
    CopyProperties(dest.Properties, (destRowItem as RowProperties));
    if (droppedFirst){
        meRow.PropertiesCollection.Add(sourceRowItem);
        meRow.PropertiesCollection.Add(destRowItem);
    }
    else {
        meRow.PropertiesCollection.Add(destRowItem);
        meRow.PropertiesCollection.Add(sourceRowItem);
    }
    // inserting the newly created multi-editor row to the target row's position
    if (dest.ParentRow != null){
        int index = dest.ParentRow.ChildRows.IndexOf(dest);
        dest.ParentRow.ChildRows.Insert(meRow, index);
    }
    else {
        int index = dest.Grid.Rows.IndexOf(dest);
        dest.Grid.Rows.Insert(meRow, index);
    }
    // deleting an instance of the target row
    dest.Dispose(); 
    // deleting an instance of the dropped row
    source.Dispose(); 
}

public void InsertRowItem (BaseRow source, MultiEditorRow dest, int itemIndex, 
bool droppedBefore){
    // this procedure creates a new row item, initializes it with the values of the dropped row
    // and inserts the item at a specific position within the target row
    MultiEditorRowProperties newRowItem = new MultiEditorRowProperties();
    CopyProperties(source.Properties, (newRowItem as RowProperties));
    if (droppedBefore) dest.PropertiesCollection.Insert(itemIndex, newRowItem);
    else {
        if (itemIndex == dest.PropertiesCollection.Count) 
          dest.PropertiesCollection.Add(newRowItem);
        else 
          dest.PropertiesCollection.Insert(itemIndex + 1, newRowItem);
    } 
    // deleting an instance of the dropped row
    source.Dispose(); 
}

public void CopyProperties(RowProperties source, RowProperties dest){
    // this procedure copies the public row properties of one row to another
   source.AssignTo(dest);
}
See Also