Drop on an appointment

9 posts, 1 answers
  1. Ioan Crisan
    Ioan Crisan avatar
    8 posts
    Member since:
    Jul 2012

    Posted 27 Oct 2012 Link to this post

    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
  2. Yana
    Admin
    Yana avatar
    4554 posts

    Posted 31 Oct 2012 Link to this post

    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.

  3. DevCraft banner
  4. A
    A avatar
    1 posts
    Member since:
    Oct 2012

    Posted 13 Nov 2012 Link to this post

    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
  5. Ioan Crisan
    Ioan Crisan avatar
    8 posts
    Member since:
    Jul 2012

    Posted 14 Nov 2012 Link to this post

    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;
            }
        }
    }
  6. Yana
    Admin
    Yana avatar
    4554 posts

    Posted 21 Nov 2012 Link to this post

    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.

  7. Answer
    Sandi Markon
    Sandi Markon avatar
    101 posts
    Member since:
    Jul 2012

    Posted 22 Nov 2012 Link to this post

    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.
  8. Yana
    Admin
    Yana avatar
    4554 posts

    Posted 22 Nov 2012 Link to this post

    Hi Sandi,

    Thank you for sharing your solution.

    Kind regards,
    Yana
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  9. Ioan Crisan
    Ioan Crisan avatar
    8 posts
    Member since:
    Jul 2012

    Posted 01 Dec 2012 Link to this post

    Hi Sandi,
    thank you for your solution, it worked!

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

    Best regards,
    Ioan
  10. Yana
    Admin
    Yana avatar
    4554 posts

    Posted 03 Dec 2012 Link to this post

    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.

Back to Top
DevCraft banner