(Sorry, the title should read "Appointment Changed Event in VB.NET" but I don't seem to be able to change it.)
The RadScheduler has several events:
- AppointmentAdded
- AppointmentDeleted
- AppointmentEditDialogShowing
However, I don't see an AppointmentChanged event or AppointmentEditDialogShown event (or something to let me know that the edit dialog has been closed and I can persist the changes to the database).
Is this by design?
I found in another thread a mention of the RadScheduler.Appoinments.CollectionChanged event but in order to use it I have to use an AddHandler statement, something I'm not accustomed to in VB.
It just seems that an AppointmentChanged event would be an obvious event to implement.
11 Answers, 1 is accepted

The code works fine if I call the code from a Save button as in your online documentation.
Here's the relavent code:
' Called from the form load event.
AddHandler rsMain.Appointments.CollectionChanged, AddressOf AppointmentChanged
Private Sub AppointmentChanged(sender As Object, e As Telerik.WinControls.Data.NotifyCollectionChangedEventArgs)
Me.CS_ScheduleInfoTableAdapter.Adapter.AcceptChangesDuringUpdate = False
CS_ScheduleInfoTableAdapter.Update(Me.BillingDataSet.CS_ScheduleInfo)
Me.BillingDataSet.AcceptChanges()
End Sub
I'd rather not have the user be forced to click on a save button.
I saw a suggestion to use the ApplySettingsToEvent event from the custom editor dialog (which I've already implemented to handle custom fields) but I don't know how to persist the data from there and I didn't see how to do it in the online documentation. The data adapter I've been using is on the main form so is unavailable in the custom editor dialog. Do I need to create a new adapter on this form?
I'd really rather perform all the updates from the main form. It just seems like a lot of trouble to go through to persist the data as it is changed when the code to persist using a button is so simple.
Thanks.

I subscribe to the RadScheduler.Appointments.CollectionChanged event and start a timer. In the Tick event code of the timer I persist the appointments to the database using the table adapter. By the time the Tick event is fired the DataReader has been closed and I'm allowed to save.
Kind of a hack so if you have a better idea I'd love to hear it.
Thank you for writing.
The proper way to listen about appointment changes is handling the CollectionChanged event. Also, using a timer is not recommended because it runs asynchronously and this might lead to unexpected behavior. The issue with "There is already an open DataReader" comes from the fact that the Update itself causes the CollectionChanged event to fire. You can protect this by using a flag to indicate that you are doing an update:
AddHandler
rsMain.Appointments.CollectionChanged,
AddressOf
AppointmentChanged
Private
updating as
Boolean
=
False
Private
Sub
AppointmentChanged(sender
As
Object
, e
As
Telerik.WinControls.Data.NotifyCollectionChangedEventArgs)
If
updating
Then
Return
End
If
Me
.updating =
True
Me
.CS_ScheduleInfoTableAdapter.Adapter.AcceptChangesDuringUpdate =
False
CS_ScheduleInfoTableAdapter.Update(
Me
.BillingDataSet.CS_ScheduleInfo)
Me
.BillingDataSet.AcceptChanges()
Me
.updating =
False
End
Sub
As to calling an update from the ApplySettingsToEvent override, you can expose a public Update method of your main form, then pass a reference to the main from in the constructor of your custom edit dialog, then just call that Update method from the ApplySettingsToEvent method. This way you will have your update logic in the main form and just call it from the dialog.
I hope you find this useful. If you have any other questions, do not hesitate to ask.
Kind regards,
Ivan Todorov
the Telerik team

Using the "updating" flag does prevent the error message but it also seems to be preventing an actual update. Adds and Deletes work fine.
The risk with the timer workaround is minimal since it's only enabled for one second and is disabled as soon as the tick event occurs (before anything is saved). Besides that, it's the only thing that has worked for updates so far.
As far as passing the form doing the calling into the form that is being called... I don't know, that just seems recursive and awkward. I tried it though. I could probably get it to work if I wasn't using table adapters but I was trying to keep in sync with the rest of the code. I put the code below in an UpdateEvent public sub and called it from the ApplySettingsToEvent override as you suggested. Was this not what you had in mind? It doesn't update anything.
Me
.CS_ScheduleInfoTableAdapter.Adapter.AcceptChangesDuringUpdate =
False
CS_ScheduleInfoTableAdapter.Update(
Me
.BillingDataSet.CS_ScheduleInfo)
Me
.BillingDataSet.AcceptChanges()
I am attaching a small sample project which demonstrates my previous suggestions. Note that using the "updating" flag works correctly in the sample. As to the ApplySettingsToEvent override, this is not applicable in all cases as this method is called before the newly created appointment is added to the collection. Using this method for performing updates can be useful only if you are managing your database directly with queries.
As to your solution with the timer, you can use it if you consider it safe. In fact, issues with it are extremely unlikely to occur although they are potentially possible due to the asynchronous execution when using timers. For example, you can trigger an update during another internal update in RadScheduler.
I hope I was able to help. If you have any other questions, do not hesitate to write back.
Regards,
Ivan Todorov
the Telerik team

The project will not compile. See attached image and snippet from vbproj file. Also, I am using VS 2010, not VS 2012.
I will correct the references and try to run the code. However, it looks pretty much like what I had.
<
ItemGroup
>
<
ProjectReference
Include
=
"..\..\RadControls\RadControlsUI.Design\Telerik.WinControls.UI.Design.csproj"
>
<
Project
>{47E6BA89-8E32-4BE0-BACA-E1D1A650766D}</
Project
>
<
Name
>Telerik.WinControls.UI.Design</
Name
>
</
ProjectReference
>
<
ProjectReference
Include
=
"..\..\RadControls\RadScheduler\Telerik.WinControls.Scheduler.csproj"
>
<
Project
>{72DCC7B6-6747-4DEE-B810-B5B02859E1D1}</
Project
>
<
Name
>Telerik.WinControls.Scheduler</
Name
>
</
ProjectReference
>
</
ItemGroup
>
Yes, usually when we send sample project, the client needs to correct the references to the Telerik dlls. This is needed because in some cases we use a developer environment to create and test the samples and in this case we use project references. All you need to do on your end is delete the missing references and add them again via the "Add Reference..." dialog of Visual Studio.
Let me know if you have further questions.
All the best,
Ivan Todorov
the Telerik team

In my opinion, if you supply a sample product to your client you should try to make sure it works. At least don't reference a project you know is not on your clients machine.
Still doesn't work after I fixed your incorrect reference:
System.InvalidOperationException was unhandled
HResult=-2146233079
Message=An error occurred creating the form. See Exception.InnerException for details. The error is: Unable to cast object of type 'Telerik.WinControls.UI.SchedulerBindingDataSource' to type 'System.ComponentModel.ISupportInitialize'.
Source=WindowsApplication11
StackTrace:
at WindowsApplication11.My.MyProject.MyForms.Create__Instance__[T](T Instance) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 190
at WindowsApplication11.My.MyProject.MyForms.get_Form1()
at WindowsApplication11.My.MyApplication.OnCreateMainForm() in C:\Users\Timmie\Documents\Visual Studio 2010\Projects\SchedExample\My Project\Application.Designer.vb:line 35
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
at WindowsApplication11.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: System.InvalidCastException
HResult=-2147467262
Message=Unable to cast object of type 'Telerik.WinControls.UI.SchedulerBindingDataSource' to type 'System.ComponentModel.ISupportInitialize'.
Source=WindowsApplication11
StackTrace:
at WindowsApplication11.Form1.InitializeComponent() in C:\Users\Timmie\Documents\Visual Studio 2010\Projects\SchedExample\Form1.Designer.vb:line 36
at WindowsApplication11.Form1..ctor() in C:\Users\Timmie\Documents\Visual Studio 2010\Projects\SchedExample\Form1.vb:line 5
InnerException:
These lines which cast schedulerBindingDataSource1 to ISupportInitialize were incorrectly serialized in the designer file on my end. You can just try to remove them or you can try running the modified project attached to this message.
If you still need assistance, please let me know.
Regards,
Ivan Todorov
the Telerik team

Hi Ivan-
Will post a C# version of how to create the Collection Changed event handler?
Thank you.
-Scott
Thank you for writing.
Here is the C# code snippet of the Appointments.CollectionChanged event:
private
bool
updating =
false
;
this
.radScheduler1.Appointments.CollectionChanged += AppointmentChanged;
private
void
AppointmentChanged(
object
sender, Telerik.WinControls.Data.NotifyCollectionChangedEventArgs e)
{
if
(updating) {
return
;
}
this
.updating =
true
;
this
.CS_ScheduleInfoTableAdapter.Adapter.AcceptChangesDuringUpdate =
false
;
CS_ScheduleInfoTableAdapter.Update(
this
.BillingDataSet.CS_ScheduleInfo);
this
.BillingDataSet.AcceptChanges();
this
.updating =
false
;
}
I would like to note that in the latest version of the suite when a change in an appointment's property occurs, the AppointmentChanged event is fired. The AppointmentChangedEventArgs gives you access to the exact Appointment and the PropertyName that has been modified.
I hope this information helps. Should you have further questions I would be glad to help.
Regards,
Dess
Telerik by Progress