windowsforms-401540-controls-and-libraries-scheduler-drag-and-drop-operations.md
The control allows users to drag an appointment within the control bounds to reschedule the appointment and drag data from another control or application to create a new appointment based on the dragged data.
Note
Run the XtraScheduler demo and try to drag an appointment to a new time slot. Click Open Solution in the ribbon for the source codes.
The control allows users to drag any appointment. Use the SchedulerControl.OptionsCustomization.AllowAppointmentDrag property to disable drag-and-drop operations or enable them for non-recurring/recurring/specific appointments only:
The code below shows how to handle the AllowAppointmentDrag event to prevent all-day appointments from being dragged.
schedulerControl1.OptionsCustomization.AllowAppointmentDrag = UsedAppointmentType.Custom;
private void SchedulerControl1_AllowAppointmentDrag(object sender, AppointmentOperationEventArgs e) {
e.Allow = !e.Appointment.AllDay;
}
schedulerControl1.OptionsCustomization.AllowAppointmentDrag = UsedAppointmentType.Custom
Private Sub SchedulerControl1_AllowAppointmentDrag(ByVal sender As Object, ByVal e As AppointmentOperationEventArgs) _
Handles schedulerControl1.AllowAppointmentDrag
e.Allow = Not e.Appointment.AllDay
End Sub
Note
Even if the SchedulerControl.OptionsCustomization.AllowAppointmentDrag option is enabled, users cannot drag appointments if the SchedulerControl.OptionsCustomization.AllowAppointmentEdit option is disabled.
An appointment can have an associated resource. For example, in a car-sharing service — a resource is a vehicle. Resources are only displayed when appointments are grouped by resource or date. Use the SchedulerControl.GroupType property to group appointments.
Users can drag an appointment from one resource to another. Use the SchedulerControl.OptionsCustomization.AllowAppointmentDragBetweenResources property to disable this feature or enable it for non-recurring/recurring/specific appointments only. To allow users to drag a specific appointment, handle the SchedulerControl.AllowAppointmentDragBetweenResources event.
The figure below demonstrates a car rent scheduler that allows the user to change a rent time but not to change the rented vehicle.
The SchedulerControl.OptionsDragDrop property provides access to options that allow you to customize drag-and-drop operations. For example, you can specify whether the control is automatically scrolled when a user drags an appointment beyond the control’s top or bottom bound.
You can also handle the following events to customize drag-and-drop operations:
AppointmentDrag — fires repeatedly when an appointment is being dragged within the control bounds. Provides access to the previous appointment and the appointment that is about to be created. Allows you can cancel the operation.
AppointmentsDrag — fires after the last AppointmentDrag event was raised.
AppointmentDrop — fires when a user drops an appointment.
AppointmentsDrag — fires after all AppointmentDrag events.
PrepareDragData — fires when a user drags data into the control from another control and allows you to create appointments based on the dragged data.
You can allow users to drag data from other controls or applications and create appointments based on dragged data.
The example below shows how to create an application that allows users to drag a data row from a data grid to a scheduler. Users can also drag data from/to another application. The application automatically creates a new appointment based on the dragged data.
The code below handles the following events:
the grid view’s MouseDown event — the event handler retrieves the clicked visual element. If the user clicked a row, a GridHitInfo object that contains information about this row is assigned to a property on the form for the subsequent use.
the grid view’s MouseMove event — the event handler calls the grid control’s DoDragDrop to initiate a drag-and-drop operation if the left mouse button is not released within the DragSize rectangle.
the scheduler’s PrepareDragData event — the event handler creates a SchedulerDragData object that contains new appointments created based on the IDataObject instance received from the source control.
the scheduler’s AppointmentDrop event — the event handler shows a confirmation.
using DevExpress.XtraScheduler;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
GridHitInfo DownHitInfo { get; set; }
void OnGridViewTasksMouseDown(object sender, MouseEventArgs e) {
GridView view = sender as GridView;
this.DownHitInfo = null;
GridHitInfo hitInfo = view.CalcHitInfo(new Point(e.X, e.Y));
if (Control.ModifierKeys != Keys.None)
return;
if (e.Button == MouseButtons.Left && hitInfo.InRow && hitInfo.HitTest != GridHitTest.RowIndicator)
this.DownHitInfo = hitInfo;
}
void OnGridViewTasksMouseMove(object sender, MouseEventArgs e) {
GridView view = sender as GridView;
if (e.Button == MouseButtons.Left && this.DownHitInfo != null) {
Size dragSize = SystemInformation.DragSize;
Rectangle dragRect = new Rectangle(new Point(this.DownHitInfo.HitPoint.X - dragSize.Width / 2,
this.DownHitInfo.HitPoint.Y - dragSize.Height / 2), dragSize);
if (!dragRect.Contains(new Point(e.X, e.Y))) {
view.GridControl.DoDragDrop(GetDragData(view), DragDropEffects.All);
this.DownHitInfo = null;
}
}
}
IDataObject GetDragData(GridView view) {
int[] selection = view.GetSelectedRows();
if (selection == null)
return null;
List<AppointmentExchangeData> exchangeList = new List<AppointmentExchangeData>();
int count = selection.Length;
for (int i = 0; i < count; i++) {
int rowIndex = selection[i];
exchangeList.Add(new AppointmentExchangeData() {
Subject = (string)view.GetRowCellValue(rowIndex, "Subject"),
LabelKey = (int)view.GetRowCellValue(rowIndex, "Severity"),
StatusKey = (int)view.GetRowCellValue(rowIndex, "Priority"),
Start = DateTime.MinValue,
Duration = TimeSpan.FromHours((int)view.GetRowCellValue(rowIndex, "Duration")),
Description = (string)view.GetRowCellValue(rowIndex, "Description"),
});
}
return new DataObject(DataFormats.Serializable, exchangeList);
}
void OnSchedulerControlPrepareDragData(object sender, PrepareDragDataEventArgs e) {
object data = e.DataObject.GetData(DataFormats.Serializable);
AppointmentBaseCollection appointments = new AppointmentBaseCollection();
foreach (AppointmentExchangeData item in (IList)data) {
var apt = this.schedulerStorage.CreateAppointment(AppointmentType.Normal);
apt.Subject = item.Subject;
apt.Description = item.Description;
apt.Start = item.Start;
apt.Duration = item.Duration;
apt.LabelKey = item.LabelKey;
apt.StatusKey = item.StatusKey;
appointments.Add(apt);
}
SchedulerDragData schedulerDragData = new SchedulerDragData(appointments);
e.DragData = schedulerDragData;
}
void OnSchedulerControlAppointmentDrop(object sender, AppointmentDragEventArgs e) {
string createEventMsg = "Creating an event at {0} on {1}.";
string moveEventMsg = "Moving the event from {0} on {1} to {2} on {3}.";
DateTime srcStart = e.SourceAppointment.Start;
DateTime newStart = e.EditedAppointment.Start;
string msg = (srcStart == DateTime.MinValue) ? String.Format(createEventMsg, newStart.ToShortTimeString(), newStart.ToShortDateString()) :
String.Format(moveEventMsg, srcStart.ToShortTimeString(), srcStart.ToShortDateString(), newStart.ToShortTimeString(), newStart.ToShortDateString());
if (XtraMessageBox.Show(msg + "\r\nProceed?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) {
e.Allow = false;
}
}
Imports DevExpress.XtraScheduler
Imports DevExpress.XtraGrid.Views.Grid
Imports DevExpress.XtraGrid.Views.Grid.ViewInfo
Private Property DownHitInfo() As GridHitInfo
Private Sub OnGridViewTasksMouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles gridViewTasks.MouseDown
Dim view As GridView = TryCast(sender, GridView)
Me.DownHitInfo = Nothing
Dim hitInfo As GridHitInfo = view.CalcHitInfo(New Point(e.X, e.Y))
If Control.ModifierKeys <> Keys.None Then
Return
End If
If e.Button = MouseButtons.Left AndAlso hitInfo.InRow AndAlso hitInfo.HitTest <> GridHitTest.RowIndicator Then
Me.DownHitInfo = hitInfo
End If
End Sub
Private Sub OnGridViewTasksMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles gridViewTasks.MouseMove
Dim view As GridView = TryCast(sender, GridView)
If e.Button = MouseButtons.Left AndAlso Me.DownHitInfo IsNot Nothing Then
Dim dragSize As Size = SystemInformation.DragSize
Dim dragRect As New Rectangle(New Point(Me.DownHitInfo.HitPoint.X - dragSize.Width \ 2, Me.DownHitInfo.HitPoint.Y - dragSize.Height \ 2), dragSize)
If Not dragRect.Contains(New Point(e.X, e.Y)) Then
view.GridControl.DoDragDrop(GetDragData(view), DragDropEffects.All)
Me.DownHitInfo = Nothing
End If
End If
End Sub
Private Function GetDragData(ByVal view As GridView) As IDataObject
Dim selection() As Integer = view.GetSelectedRows()
If selection Is Nothing Then
Return Nothing
End If
Dim exchangeList As New List(Of AppointmentExchangeData)()
Dim count As Integer = selection.Length
For i As Integer = 0 To count - 1
Dim rowIndex As Integer = selection(i)
exchangeList.Add(New AppointmentExchangeData() With {
.Subject = CStr(view.GetRowCellValue(rowIndex, "Subject")),
.LabelKey = CInt(Math.Truncate(view.GetRowCellValue(rowIndex, "Severity"))),
.StatusKey = CInt(Math.Truncate(view.GetRowCellValue(rowIndex, "Priority"))),
.Start = Date.MinValue,
.Duration = TimeSpan.FromHours(CInt(Math.Truncate(view.GetRowCellValue(rowIndex, "Duration")))),
.Description = CStr(view.GetRowCellValue(rowIndex, "Description"))
})
Next i
Return New DataObject(DataFormats.Serializable, exchangeList)
End Function
Private Sub OnSchedulerControlPrepareDragData(ByVal sender As Object, ByVal e As PrepareDragDataEventArgs) Handles schedulerControl.PrepareDragData
Dim data As Object = e.DataObject.GetData(DataFormats.Serializable)
Dim appointments As New AppointmentBaseCollection()
For Each item As AppointmentExchangeData In DirectCast(data, IList)
Dim apt = Me.schedulerStorage.CreateAppointment(AppointmentType.Normal)
apt.Subject = item.Subject
apt.Description = item.Description
apt.Start = item.Start
apt.Duration = item.Duration
apt.LabelKey = item.LabelKey
apt.StatusKey = item.StatusKey
appointments.Add(apt)
Next item
Dim schedulerDragData As New SchedulerDragData(appointments)
e.DragData = schedulerDragData
End Sub
Private Sub OnSchedulerControlAppointmentDrop(ByVal sender As Object, ByVal e As AppointmentDragEventArgs) Handles schedulerControl.AppointmentDrop
Dim createEventMsg As String = "Creating an event at {0} on {1}."
Dim moveEventMsg As String = "Moving the event from {0} on {1} to {2} on {3}."
Dim srcStart As Date = e.SourceAppointment.Start
Dim newStart As Date = e.EditedAppointment.Start
Dim msg As String = If(srcStart = Date.MinValue, String.Format(createEventMsg, newStart.ToShortTimeString(), newStart.ToShortDateString()), String.Format(moveEventMsg, srcStart.ToShortTimeString(), srcStart.ToShortDateString(), newStart.ToShortTimeString(), newStart.ToShortDateString()))
If XtraMessageBox.Show(msg & vbCrLf & "Proceed?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.No Then
e.Allow = False
End If
End Sub
You can enable users to drag appointments from a SchedulerControl to GridControl and create grid rows based on the dragged appointments.
The code below handles the following events:
The data grid’s DragEnter event — the event handler notifies a user that they can drop data.
The data grid’s DragDrop event — the event handler creates grid rows based on the dragged appointment.
using DevExpress.XtraGrid;
using DevExpress.XtraScheduler;
using System.Data;
gridControl1.AllowDrop = true;
gridControl1.DragDrop += GridControl1_DragDrop;
gridControl1.DragEnter += GridControl1_DragEnter;
private void GridControl1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) {
e.Effect = System.Windows.Forms.DragDropEffects.All;
}
private void GridControl1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
GridControl gridControl = sender as GridControl;
SchedulerDragData data = e.Data.GetData(typeof(SchedulerDragData)) as SchedulerDragData;
if (data != null) {
foreach (var apt in data.Appointments) {
var row = apt.GetRow(schedulerControl.DataStorage) as DataRowView;
gridDataTable.Rows.Add(row.Row.ItemArray);
}
}
}
Imports DevExpress.XtraGrid
Imports DevExpress.XtraScheduler
Imports System.Data
gridControl1.AllowDrop = True
AddHandler gridControl1.DragDrop, AddressOf GridControl1_DragDrop
AddHandler gridControl1.DragEnter, AddressOf GridControl1_DragEnter
Private Sub GridControl1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs)
e.Effect = System.Windows.Forms.DragDropEffects.All
End Sub
Private Sub GridControl1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs)
Dim gridControl As GridControl = TryCast(sender, GridControl)
Dim data As SchedulerDragData = TryCast(e.Data.GetData(GetType(SchedulerDragData)), SchedulerDragData)
If data IsNot Nothing Then
For Each apt In data.Appointments
Dim row = TryCast(apt.GetRow(schedulerControl.DataStorage), DataRowView)
gridDataTable.Rows.Add(row.Row.ItemArray)
Next
End If
End Sub