Drag and Drop with RadScheduleView

RadScheduleView uses DragDropManager to implement drag and drop of appointments. In order to add some custom logic for drag and drop, you can inherit the Telerik.Windows.Controls.ScheduleViewDragDropBehavior class. The class provides several methods that you can override to implement custom drag and drop functionality. This article will demonstrate all of the available methods.

RadScheduleView - Drag And Drop

DragDropState Parameter

Each of the methods provided in the ScheduleViewDragDropBehavior class receives an object of type DragDropState. The object contains all the needed information in order to help you achieve the required drag and drop and resize functionality. The object provides the following properties:

  • Appointment - Holds a reference to the appointment that is held with the mouse.

  • DestinationAppointmentsSource - Holds a reference to the AppointmentsSource collection of the drag destination.

  • DestinationSlots - Gets a collection containing the new slots of the dragged Appointments.

  • DraggedAppointments - Contains all appointments that are being dragged, including the appointment that is selected while the user clicks and holds the mouse button. When resizing this property is null.

  • IsControlPressed - Gets or sets a value indicating the control key is pressed.

  • ServiceProvider - Gets the IServiceProvider associated with the current instance.

  • SlotDuration - Gets the duration between two minor ticks.

  • SourceAppointmentsSource - Holds a reference to the AppointmentsSource collection of the drag source.

  • SourceResources (available with Q2 2014 version of UI for Silverlight) - Gets a collection containing the original resources from which the dragging operation has started.

  • TargetedAppointment (available with Q2 2014 version of UI for Silverlight) - Holds a reference to the targeted appointment on which the drop operation will be performed.

ScheduleViewDragDropBehavior class

The following section will provide some detailed information about the following methods and properties of the ScheduleViewDragDropBehavior class:

Methods

Properties

CanDrop(DragDropState state)

The CanDrop(DragDropState state) method gets the value specifying whether the drag and drop operation can be finished or not. The method is called multiple times during the operation. On each call you can check if a requirement is fulfilled in order to prevent or allow the completion of the drop. For example, you can easily prevent copying Appointments when dragging them with the Control Key pressed by returning false if the key is pressed:

Example 1: Overriding the CanDrop method

public override bool CanDrop(DragDropState state) 
{ 
    if (state.IsControlPressed) 
    { 
        return false; 
    } 
 
    return base.CanDrop(state); 
} 

CanStartDrag(DragDropState state)

CanStartDrag(DragDropState state) - Gets the value specifying whether the drag operation can be performed or not. The method is called at the moment when the operation is starting. For example, if you need to prevent dragging of more than two Appointments, you can override the method the following way:

Example 2: Overriding the CanStartDrag method

public override bool CanStartDrag(DragDropState state) 
{ 
    if (state.DraggedAppointments.Count() > 2) 
    { 
        return false; 
    } 
 
    return base.CanStartDrag(state); 
}  

Drop(DragDropState state)

Drop(DragDropState state) - The method is called right after the Appointment is dropped and before the DragDropCompleted method is called. For example, if you want to add a Category to the just dropped Appointment, you can do it as shown below:

Example 3: Override the Drop method

public override void Drop(DragDropState state) 
{ 
    var appointment = state.Appointment as Appointment; 
 
    if (appointment.Category == null) 
    { 
        appointment.Category = new Category("Green Category", Brushes.Green); 
    } 
 
    base.Drop(state); 
} 

CanResize(DragDropState state)

CanResize(DragDropState state) - Gets the value specifying whether the resize operation can be finished or not. The method is called multiple times during the Resize operation and you can easily stop the operation by returning false. The following example demonstrates how to stop the resizing when the duration becomes more than two hours and less than half an hour.

Example 4: Override the CanResize method

public override bool CanResize(DragDropState state) 
{ 
    var destinationSlot = state.DestinationSlots.First() as Slot; 
    var duration = destinationSlot.End - destinationSlot.Start; 
 
    if (duration <= new TimeSpan(0, 30, 0) || duration > new TimeSpan(2, 0, 0)) 
    { 
        return false; 
    } 
 
    return base.CanResize(state); 
} 

CanStartResize(DragDropState state)

CanStartResize(DragDropState state) - Gets the value specifying whether the resize operation can be performed or not. The method is called at the moment when the operation is starting. For example, if you need to prevent the resizing of an Appointment that is marked with the Busy TimeMarker, you will need to do it the following way:

Example 5: Override the CanStartResize method

public override bool CanStartResize(DragDropState state) 
{ 
    var appointment = state.Appointment as Appointment; 
 
    if (appointment.TimeMarker != null && appointment.TimeMarker.Equals(TimeMarker.Busy)) 
    { 
        return false; 
    } 
 
    return base.CanStartResize(state); 
} 

Resize(DragDropState state)

Resize(DragDropState state) - The method is called right after the resize operation is finished. You can find the initial Appointment in the Appointment property of the DragDropState and the new information in the DestinationSlot property. So, for example, you can easily modify the Appointment subject after resizing in order to include the new duration as shown below:

Example 6: Override the Resize method

public override void Resize(DragDropState state) 
{ 
    var appointment = state.Appointment as Appointment; 
    var destinationSlot = state.DestinationSlots.First() as Slot; 
    var duration = destinationSlot.End - destinationSlot.Start; 
    appointment.Subject = "New duration: " + duration.ToString("h\:mm\:ss"); 
    base.Resize(state); 
} 

This is the result:

scheduleview features draganddrop 2

ConvertDraggedData(object data)

By default, the ConvertDraggedData method will be called constantly. This behavior can be modified through the CacheConvertedDragData property.

ConvertDraggedData(Object data) - This method is fired when you drag appointments from a different source (another control or application) and is used to convert the data to an appointment. For example, if you are dragging from a ListBox to ScheduleView and you have objects of type Customer as an ItemsSource of the ListBox, you can convert the dragged Customer object to an Appointment the following way:

Example 7: Override the ConvertDraggedData method

public override IEnumerable<IOccurrence> ConvertDraggedData(object data) 
{ 
    if (Telerik.Windows.DragDrop.Behaviors.DataObjectHelper.GetDataPresent(data, typeof(Meeting), false)) 
    { 
        var customers = Telerik.Windows.DragDrop.Behaviors.DataObjectHelper.GetData(data, typeof(Customer), true) as IEnumerable; 
        if (customers != null) 
        { 
            var newApp = customers.OfType<Customer>().Select(c => new Appointment { Subject = c.Name }); 
 
            return newApp; 
        } 
    } 
 
    return base.ConvertDraggedData(data); 
} 

This will create a new Appointment with the Subject being the Name of the dropped customer as shown below:

scheduleview features draganddrop 1

CoerceDraggedItems(DragDropState state)

CoerceDraggedItems(DragDropState state) - Initializes the drag operation. This method could be used to filter the selected appointments. This method allows adding or removing Appointments to the selection depending on a specific condition. For example, if you need to filter the dragged Appointments by the Resource in order to move all the Appointments with the current Resource, you do it the following way:

Example 8: Override the CoerceDraggedItems method

public override IEnumerable<IOccurrence> CoerceDraggedItems(DragDropState state) 
{ 
    var resource = (state.Appointment as Appointment).Resources.First(); 
    var allAppointments = state.SourceAppointmentsSource.Cast<IOccurrence>(); 
    var desiredAppointments = allAppointments.Where(a => (a as Appointment).Resources.Any(r => r == resource)); 
 
    return desiredAppointments; 
} 

DragDropCompleted(DragDropState state)

DragDropCompleted( DragDropState state) - This method is called when the drag-drop operation is finished.

DragDropCanceled(DragDropState state)

DragDropCanceled( DragDropState state) - The method is called whenever the execution of the operation has failed for some reason.

Setting the CustomDragDropBehavior

After the CustomDragDropBehavior is implemented, all you need is to set it as RadScheduleView.DragDropBehavior:

Example 9: Set the CustomDragDropBehavior

<telerik:RadScheduleView.DragDropBehavior> 
  <local:CustomDragDropBehavior /> 
</telerik:RadScheduleView.DragDropBehavior> 

ResizeCursor

The ResizeCursor property was introduced with Q1 2016 release of UI for Silverlight. Using it you can change the cursor that indicates a resize operation is happening. That could be done initially or while resizing an Appointment, for example, inside the CanResize method:

Example 10: Setting the ResizeCursor property

public override bool CanResize(DragDropState state) 
{ 
    var destinationSlot = state.DestinationSlots.First() as Slot; 
    var duration = destinationSlot.End - destinationSlot.Start; 
 
    if (duration <= new TimeSpan(0, 30, 0) || duration >= new TimeSpan(2, 0, 1)) 
    { 
        this.ResizeCursor = Cursors.Wait; 
        return false; 
    } 
 
    this.ResizeCursor = Cursors.SizeNS; 
    return base.CanResize(state); 
} 

The default cursor is represented by setting the ResizeCursor property value to null.

CacheConvertedDragData

As of R1 2017 SP1, ScheduleViewDragDropBehavior exposes the CacheConvertedDragData property. Its default value is False, meaning that the ConvertDraggedData method will be called repeatedly. When the property is set to True, the method will be called only once and the converted data will be cached.

Check out the online demo to see the RadScheduleView's Drag and Drop functionality in action.

In this article