VGridControlBase.StartDragRow Event
Fires before a row is dragged by an end-user.
Namespace: DevExpress.XtraVerticalGrid
Assembly: DevExpress.XtraVerticalGrid.v24.2.dll
Declaration
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.
The image below displays the process of handling row drag & drop operations using the code in this example.
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);
}