This is a migrated thread and some comments may be shown as answers.

Drop on an appointment

8 Answers 185 Views
ScheduleView
This is a migrated thread and some comments may be shown as answers.
Ioan Crisan
Top achievements
Rank 1
Ioan Crisan asked on 27 Oct 2012, 02:05 PM
Hi there,

I have the following problem: I have a list of persons and a ScheduleView displaying appointments. I need to drag persons over an appointment to associate those persons with the appointment. I tried to search for solutions to this problem but at no avail. The ScheduleView wants always to add a new appointment, which I actually want to forbid.

Could you please provide me an example of how can I solve this requirement?

Thanks,
Ioan

8 Answers, 1 is accepted

Sort by
0
Yana
Telerik team
answered on 31 Oct 2012, 01:57 PM
Hello Ioan,

First, I would suggest to use RadListBox to hold the Person objects. Then you can easily implement drag and drop between RadListBox and RadScheduleView - the approach is explained in details here.

Also you can use the approach demonstrated in this Code Library (it's the same for Silverlight) to find whether the destination slot contains any appointments. If there is an appointment, update the needed properties.

Please try it and if you have any additional issues, contact us again.

All the best,
Yana
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
A
Top achievements
Rank 1
answered on 14 Nov 2012, 03:47 AM
Hello loan

did you find any solution? i am facing same kind of problem and i want to add resources to appointments by dropping them from RadListView to the appointment itself in RadScheduleView.

please let us know if you succeed in implementing the solution.

Thx

Ali
0
Ioan Crisan
Top achievements
Rank 1
answered on 14 Nov 2012, 08:05 PM
Hi Ali,
I have a partial solution, which is not satisfactory for the end customer. I mean I can drop persons in the scheduler, but if there are more appointments scheduled at the same time I did not find any way to differentiate among them. By the way: do not forget to add a behavior to the person list also (in my case) so that the items are not removed on move. Below you have the code snippets.

@Yana: Could you provide me a code snippet to differentiate among the slots the user dropped the item? There is no information whatsoever in the method arguments to be able to do that. Moreover, it is somehow funny to check in all available slots if there are intersecting appointments - a property in the DragDropState indicating on which appointments is dropped would be ideal.

using System.Linq;
using Primary.StudioAssistant.Contacts.Domain.Default;
using Telerik.Windows.DragDrop.Behaviors;
 
namespace Primary.StudioAssistant.Core.Studio.Views.Default
{
    public class AttendancesListDragDropBehavior : ListBoxDragDropBehavior
    {
        /// <summary>
        /// Returns true if the dragged items should be removed from the source list, otherwise false.
        /// </summary>
        /// <param name="state">DragDropState that provides context for the current operation.</param>
        protected override bool IsMovingItems(DragDropState state)
        {
            return false;
        }
    }
}

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Kephas;
using Kephas.Model;
using Primary.StudioAssistant.Contacts.Domain.Default;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.ScheduleView;
using Telerik.Windows.DragDrop.Behaviors;
using DragDropState = Telerik.Windows.Controls.DragDropState;
using Resource = Telerik.Windows.Controls.Resource;
 
namespace Primary.StudioAssistant.Scheduling.Views.Default
{
    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class AssociatePersonDragDropBehavior : ScheduleViewDragDropBehavior
    {
        public override IEnumerable<IOccurrence> ConvertDraggedData(object data)
        {
            var payload = data as IDragPayload;
            if (payload == null)
                return new IOccurrence[0];
 
            var format = typeof(IStudentAttendance).FullName;
            var attendances = payload.GetData(format) as IEnumerable;
            if (attendances == null)
                return new IOccurrence[0];
 
            var attendance = attendances.OfType<IStudentAttendance>().FirstOrDefault();
            if (attendance == null)
                return new IOccurrence[0];
 
            // create dummy new appointment with a duration of 1 minute. It should display as a line.
            var appointment = new Appointment
                {
                    Subject = attendance.Person.ToString(),
                    RecurrenceRule = null,
                    Start = DateTime.Today,
                    End = DateTime.Today.AddMinutes(1),
                };
            appointment.Resources.Add(new TaggedResource { Tag = attendance });
 
            return new IOccurrence[] { appointment };
        }
 
        public override bool CanDrop(DragDropState state)
        {
            var canDrop = state.DestinationAppointmentsSource
                .OfType<IAppointment>()
                .Where(a => !state.DraggedAppointments.Contains(a))
                .Any(a => state.DestinationSlots.Any(s => ConflictChecking.AreOverlapping(a, s)));
            return canDrop;
        }
 
        public override bool CanResize(DragDropState state)
        {
            return state.DestinationAppointmentsSource
                .OfType<IAppointment>()
                .Where(a => a != state.Appointment)
                .All(a => state.DestinationSlots.All(s => ConflictChecking.AreOverlapping(a, s)));
        }
 
        public override void Drop(DragDropState state)
        {
            state.IsControlPressed = true;
            var newAppointment = state.DraggedAppointments.OfType<IAppointment>().FirstOrDefault();
            if (newAppointment == null)
                return;
 
            // get the appointments on which the data is dropped
            var droppedOnAppointments = state.DestinationAppointmentsSource
                .OfType<IAppointment>()
                .Where(a => a != newAppointment)
                .Where(a => state.DestinationSlots.Any(s => ConflictChecking.AreOverlapping(a, s)))
                .ToList();
            // the drop did not occur on an appointment
            if (droppedOnAppointments.Count == 0)
                return;
            // bad luck: multiple appointments are scheduled at the same time.
            // Currently there is no way of telling on which the user dropped the item
            if(droppedOnAppointments.Count > 1)
            {
                Ambience.Services.Resolve<INotificationService>().NotifyMessage(Resources.Strings.AmbiguousAppointmentsWarningMessage.FormatWith(droppedOnAppointments.Select(a => a.ToString()).Join(Environment.NewLine)));
                return;
            }
            // custom code: identify the persistent appointment based on custom data and add the person to the appointment
            var appointmentId = ((IResource)droppedOnAppointments[0].Resources[1]).ResourceName;
            var attendance = ((TaggedResource)newAppointment.Resources[0]).Tag as IStudentAttendance;
            if(attendance != null)
                SchedulerHelper.AddPersonAppointment(appointmentId, attendance);
             
            // do not call the base so that no appointment is added
            //base.Drop(state);
        }
    }
 
    public static class ConflictChecking
    {
        public static bool AreOverlapping(IAppointment appointment, Slot slot)
        {
            // just test that the time interval is intersecting
            return appointment.Start <= slot.End && appointment.End >= slot.Start;
        }
    }
}
0
Yana
Telerik team
answered on 21 Nov 2012, 10:01 AM
Hi Ioan,

I am afraid that currently you cannot get the exact appointment where the dragged appointment is dropped - you can get only the slot as demonstrated in the code library.  This feature is already added to our future plans, but at the moment we cannot commit to a specific timeframe for implementing it.

We're sorry for the inconvenience.

Regards,
Yana
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Accepted
Sandi Markon
Top achievements
Rank 1
answered on 22 Nov 2012, 12:19 PM
My solution was something like this:

IEnumerable<AppointmentItem> items =
VisualTreeHelper.FindElementsInHostCoordinates
(currentPoint,
 currentScheduleView)
 .OfType<AppointmentItem>();

The parameter currentScheduleView is the RadScheduleView, which you can obtain, for example, in the override CanStartDrag:

public override bool CanStartDrag(DragDropState state)
        {
            // ...
 
                currentScheduleView = state.ServiceProvider.GetService<IDialogProvider>() as RadScheduleView;
 
           // ....
 
        }

In order to get the currentPoint parameter (that is, the current drag point, relative to the RadScheduleView), you can pick it up in the DragOver event handler. I used: 

public ScheduleViewCustomDragDropBehavior()
{
       DragDropManager.RemoveDragOverHandler(Application.Current.RootVisual, OnDragOver);
       DragDropManager.AddDragOverHandler(Application.Current.RootVisual, OnDragOver, true);
}
 
void OnDragOver(object sender, DragEventArgs e)
{
        currentPoint = e.GetPosition(Application.Current.RootVisual);
}


<!--This way you can get all the appointments, that intersect with the one, you are trying to drop, so all you need to do, is to decide on which appointment you want to drop it (or associate data in the dragged payload with). -->

EDIT: Ignore the above sentence. By using this method you only get the appointment directly under your mouse cursor!! :)

Hope this helps.
0
Yana
Telerik team
answered on 22 Nov 2012, 03:52 PM
Hi Sandi,

Thank you for sharing your solution.

Kind regards,
Yana
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Ioan Crisan
Top achievements
Rank 1
answered on 01 Dec 2012, 08:26 AM
Hi Sandi,
thank you for your solution, it worked!

@Yana: I hope Sandi gets some points for the solution.

Best regards,
Ioan
0
Yana
Telerik team
answered on 03 Dec 2012, 03:15 PM
Hello Sandi,

We've updated your points for the involvement.

All the best,
Yana
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Tags
ScheduleView
Asked by
Ioan Crisan
Top achievements
Rank 1
Answers by
Yana
Telerik team
A
Top achievements
Rank 1
Ioan Crisan
Top achievements
Rank 1
Sandi Markon
Top achievements
Rank 1
Share this question
or