Hi!
I'm using the RadScheduleView with custom appointments as described in the referenced article on your documentation. But unfortunately I'm facing some troubles using the Appointment as suggested. What I want to achieve:
I have a complex object for storing time tracking information (let's call it TimeTrack) with a start, end (DateTime), name and references to other child objects storing additional information. I wanted to display those TimeTrack objects in a schedule view so user can easily modify start, end or even create a copy of that object with using the [CTRL] key. Therefor I created a TimeTrackAppointmentProxy class in this way:
public class TimeTrackAppointmentProxy : Appointment
{
}
6 Answers, 1 is accepted
... continued (hit wrong button :-))
public class TimeTrackAppointmentProxy : Appointment
{
public TimeTrack myTimeTrack { get; set; }
.....
}
where i add additional properties and also was trying to overwrite the getters/setters for Start, End and Subject to be populated with values from my TimeTrack object. Like:
public override DateTime Start
{
get => TimeTrack.Start ?? default;
set
{
base.Start = value;
TimeTrack.Start = value;
}
}
public override DateTime End
{
get => TimeTrack.End ?? default;
set
{
base.End = value;
TimeTrack.End = value;
}
}
public override string Subject
{
get => TimeTrack.Title ?? default;
set => TimeTrack.Title = value;
}
Also prepared the Copy() and CopyFrom() in the way it is suggested (although i have to admit, i haven't found any specific information on how the Copy() and CopyFrom() must be implemented - only some very old forum posts).
public override IAppointment Copy()
{
var newAppointment = new TimeTrackAppointmentProxy();
newAppointment.CopyFrom(this);
newAppointment.IsCopy = true;
return newAppointment;
}
public override void CopyFrom(IAppointment other)
{
if (other is TimeTrackAppointmentProxy timeTrackingAppointmentProxy)
{
this.TimeTrack = timeTrackingAppointmentProxy.TimeTrack;
base.CopyFrom(other);
}
}
Since things didn't work as expected, i started debugging the code and found out that Copy() and CopyFrom() are called multiple times during a drag to copy operation. Empty objects where created, CopyFrom() gets called at least three times during operation when the "other" parameter sometimes contains an empty object (not null but just initialized with defaults), then again the destination appointment but not the source appointment (as i would it expect to be). Everything rather confusing I have to say.
Since i couldn't figure out what's really happening i prepared a small sample project for investigation with a simple class deriving from Appointment that just has a flag (IsCopy) and a Name (to be used for display as the Subject) and a custom behavior for handling the finished drag and drop operation to access the state.Appointment (which interestingly contains the source and not the newly created appointment, as I would expect after the drag and drop is finished, but this is another story :-) ).
I will put a download link at the end for the sample. My questions are:
- Why are Copy() and CopyFrom() called so many times for modifying an appointment (changing start/end time or doing drag to copy with [CTRL]) and why is the IAppointment other parameter not just holding the reference to the source appointment?
- Why is Copy() and CopyFrom() called even when i just drag the start or end time? How can i then distinguish if the user want's to create a copy or just modify the time?
- Is it a problem for the ScheduleView control if i overwrite one of their properties (like Start, End or Subject) because then the behavior seems strange although i don't do anything too fancy.
Here is the link to the sample application wich i used to track those issues: https://rminnovation1-my.sharepoint.com/:u:/g/personal/martin_beinhart_rminnovation_net/ESZZgV0_pNlKkGXjmuhV5lgB8zpnil8RJ09Zb89ZfbIrQw?e=DnjG93
Regards, Martin
Hello Martin,
I will check the project and see what happens a bit later today.
Regards,
Martin Ivanov
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.
Hello Martin,
All of the described behaviors are coming from the fact that the Appointment's base class implements the IEditableObject interface. This way we can store the state of the annotation before the editing starts and then restore it if the edit operation is cancelled. The implementation of this feature requires to copy the annotation in different states of its lifecycle, like changing of its properties or drag drop with copy operation. This is why the methods are called during those operations.
About the overriding of the Start, End, etc, properties of the Appointment, those execute some custom logic related to the IEditableObject implementation,. However, if you call the "base" implementation of the property, the default logic should get executed and the Appointment should work as expected. Can you tell me what are the exact issues with the properties? Also, can you tell me why do you need to override the Copy and CopyFrom methods?
Regards,
Martin Ivanov
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.
Thank you Martin, for providing some technical background information. You asked why I need to override the Copy() and the CopyFrom() method. Well because it's strictly recommended in the documentation for creating custom appointments:
https://docs.telerik.com/devtools/wpf/controls/radscheduleview/features/appointments/custom-appointment
There it says: "It is very important to provide your own implementations for the Copy and CopyFrom methods as they are used intensively in the editing process of the ScheduleView control."
So what i was trying to achieve with my implementation (see sample project) is that after i create a copy of an appointment, the subject should have an "_Copy" suffix. So I'm overwriting the Subject property to use the Name property of my custom appointment for displaying text:
public override string Subject
{
get => Name;
set
{
Name = value;
base.Subject = value;
}
}
In the Copy() and CopyFrom() I'm sticking to the recommendations from the documentation and to postings I found here in the forum:
public override IAppointment Copy()
{
var newAppointment = new MyTask();
newAppointment.CopyFrom(this);
return newAppointment;
}
public override void CopyFrom(IAppointment other)
{
var otherTask = other as MyTask;
if (otherTask != null)
{
this.IsCopy = true;
this.Subject = otherTask.Name + "_Copy";
}
base.CopyFrom(other);
}
When I put the base.CopyFrom(other) at the end, as recommended, I get an empty Subject in the copied appointment. Although the original appointment had "Task 1" in the Subject.
If I put the base.CopyFrom(other) at the beginning, like
public override void CopyFrom(IAppointment other)
{
base.CopyFrom(other);
var otherTask = other as MyTask;
if (otherTask != null)
{
this.IsCopy = true;
this.Subject = otherTask.Name + "_Copy";
}
}
then I get "_Copy_Copy" as Subject for the copied appointment although my source appointment had "Task 1" in the Subject. My expectation would be that I should get "Task1_Copy" as result in the subject. But because CopyFrom() is called multiple times during the operation (with empty, source, destination appointment as "other" parameter) the Subject gets messed up.
That's the "issue" - but really not an issue - only because the naming of the methods suggest, that there is the right location to put custom logic. But like you explained, the methods get called several times to preserve the annotation. It's only confusing since the documentation requests implementing our own version of Copy() and CopyFrom() without explaining HOW they should be used best or what should be considered. Maybe my approach is not the best way to utilize custom appointments?
Regards, Martin
Hello Martin,
Thank you for the additional information.
I can agree that the documentation needs update on the matter. As for your requirement, you can use the custom drag/drop behavior. In the Drop override, you can add the "_Copy" part in the Subject. You can see this approach in the attached project. I hope this helps.
Regards,
Martin Ivanov
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.
Thank you. I have already utilized DragDropCompleted() in my custom ScheduleViewDragDropBehavior and there i can make all the changes that I need, similar as you recommend.
Regards,
Martin