Skip to main content

Drag-and-Drop Appointments

  • 8 minutes to read

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.

image

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.

Drag Specific Appointments Only

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;
}

Note

Even if the SchedulerControl.OptionsCustomization.AllowAppointmentDrag option is enabled, users cannot drag appointments if the SchedulerControl.OptionsCustomization.AllowAppointmentEdit option is disabled.

Prevent Appointments from Being Dragged Between Resources

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.

image

Options and Events

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.

    You can also specify additional appointments that will be dragged with the primary appointment.

  • 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.

Drag Data from Other Controls

You can allow users to drag data from other controls or applications and create appointments based on dragged data.

image

View Example

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 event handler creates a DataObject instance object that contains dragged rows. This object is then passed to the grid control’s DoDragDrop method and can be retrieved in the target control.

  • 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;
    }
}

Drag Data from Scheduler to Grid

You can enable users to drag appointments from a SchedulerControl to GridControl and create grid rows based on the dragged appointments.

image

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);
        }
    }
}