How to: Perform Custom Actions When an Exception is Added to a Recurring Event
- 5 minutes to read
XAF ships with the Scheduler Module designed to manage scheduling information. This module uses integrated DevExpress controls to display a List View of IEvent
objects. Each object is an event that can occur once or follow a recurrence pattern.
If you use a custom class that implements the IEvent
and ISupportReccurrence
interfaces, any custom properties that are not defined in the IEvent
interface lose their values when you create an exception for a recurring event.
This topic explains the reason behind this behavior and demonstrates how to preserve the values of such properties.
Step-by-Step Instructions
In the YourSolutionName.Module\BusinessObjects folder, create a new class and call it
ExtendedEvent
. Inherit the class fromDevExpress.Persistent.BaseImpl.EF.Event
(for EF Core) orDevExpress.Persistent.BaseImpl.Event
(for XPO) to implement theIEvent
andISupportRecurrence
interfaces and add a public property not defined in theIEvent
interface.using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl.EF; //... [DefaultClassOptions] public class ExtendedEvent : Event { public virtual string Notes { get; set; } } // Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.
Run the application. Create a weekly meeting that starts at 9:00 AM and set its
Notes
property to “regular meetings” (note the recurring event icon in the lower-right corner of this event):Set the start time for a single event from the series to 8:00 AM. Note that the recurring event icon is crossed out, which means that this event no longer matches the recurrence pattern.
Open the edited event and check the
Notes
property value. As you can see, it is empty.When you edit a single event in the recurring series, the Scheduler only duplicates properties defined in the
IEvent
interface. To include custom properties, you need to handle the SchedulerListEditorBase.ExceptionEventCreated event. This event occurs when you create an exception. The event handler’s argument has two properties.- ExceptionEventCreatedEventArgs.PatternEvent - the original event occurrence that you changed.
- ExceptionEventCreatedEventArgs.ExceptionEvent - the modified event you created (the exception).
In the YourSolutionName.Module\Controllers folder, create a new View Controller and handle the ExceptionEventCreated event as displayed in the following code snippet:
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Scheduler; using DevExpress.Persistent.Validation; using MySolution.Module.BusinessObjects; namespace MySolution.Module.Controllers { public class CustomEventController : ViewController<ListView> { private SchedulerListEditorBase schedulerEditor; protected override void OnActivated() { base.OnActivated(); schedulerEditor = View.Editor as SchedulerListEditorBase; if (schedulerEditor != null) { schedulerEditor.ExceptionEventCreated += schedulerEditor_ExceptionEventCreated; } } protected override void OnDeactivated() { base.OnDeactivated(); if (schedulerEditor != null) { schedulerEditor.ExceptionEventCreated -= schedulerEditor_ExceptionEventCreated; } } void schedulerEditor_ExceptionEventCreated(object sender, ExceptionEventCreatedEventArgs e) { if (e.PatternEvent is ExtendedEvent patternEvent && e.ExceptionEvent is ExtendedEvent exceptionEvent) { exceptionEvent.Notes = patternEvent.Notes; } } } }
The Controller checks whether the current List View’s List Editor derives from the SchedulerListEditorBase. If it does, the Controller subscribes to the ExceptionEventCreated event. In the event handler, the Controller checks whether the Scheduler is activated for the
ExtendedEvent
class. If so, the Controller copies theNotes
property value from the object returned by thePatternEvent
property to the object returned by theExceptionEvent
property. Upon deactivation, it unsubscribes from theExceptionEventCreated
event.Run the application and set the start time for a single event from the series to 8:00 AM again. Open the edited event and check the
Notes
property value. It should be preserved.
Validate Custom Properties in Recurrence Exceptions
When you apply validation rules to custom properties processed by the ExceptionEventCreated event, you cannot use the standard Save
validation context. XAF checks this context when it raises the IObjectSpace.Committing event. However, it copies custom property values to an exception event later, when it raises the IObjectSpace.ObjectSaving event.
To implement validation rules for custom properties, define a custom validation context in the ExtendedEvent
class, as shown in the following code snippet:
//...
using DevExpress.Persistent.Validation;
using Microsoft.Extensions.DependencyInjection;
namespace YourSolutionName.Module.BusinessObjects {
[DefaultClassOptions]
public class ExtendedEvent : Event {
// ...
public override void OnSaving() {
base.OnSaving();
var validator = ObjectSpace.ServiceProvider.GetRequiredService<IValidator>();
validator.RuleSet.Validate(ObjectSpace, this, "SchedulerValidation");
}
}
}
// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.
You can also trigger validation when you specify a custom property value. In the CustomEventController
class, modify the handler of the ExceptionEventCreated event as displayed in the code snippet below:
// ...
using DevExpress.Persistent.Validation;
using Microsoft.Extensions.DependencyInjection;
namespace MySolution.Module.Controllers {
public class CustomEventController : ViewController<ListView> {
// ...
void schedulerEditor_ExceptionEventCreated(object sender, ExceptionEventCreatedEventArgs e) {
if (e.PatternEvent is ExtendedEvent patternEvent && e.ExceptionEvent is ExtendedEvent exceptionEvent) {
exceptionEvent.Notes = patternEvent.Notes;
var validator = Application.ServiceProvider.GetRequiredService<IValidator>();
validator.RuleSet.Validate(ObjectSpace, this, "SchedulerValidation");
}
}
}
}