Skip to main content
A newer version of this page is available. .

How to: Perform Custom Actions When a Recurring Event's Exceptional Occurrence is Created

  • 6 minutes to read

XAF is shipped with the Scheduler Module. This module is used to display the IEvent objects’ List Views via controls that are specifically designed to present and manage scheduling information. In certain scenarios, it is necessary to create a custom class that implements the IEvent interface and an additional ISupportReccurrence interface to enable the Scheduler’s support for Recurring Events. In this instance, there is one peculiarity to be aware of. When an exceptional Event occurrence is created, you may notice that the additional properties, which are not defined in the IEvent interface, lose their values. In this topic, we will illustrate this in an example, explain why it happens, and provide a solution to this problem.

Note

Blazor applications do not support the Scheduler Module.

To illustrate the problem, we have an XAF applications solution, which contains a definition of the ExtendedEvent class. This class implements the IEvent and ISupportRecurrence interfaces and has an additional public property not defined in the IEvent interface - the Notes property. We could implement the ExtendedEvent class from scratch, but for the sake of simplicity it was inherited from the Event class.

[DefaultClassOptions]
public class ExtendedEvent : Event {
    public ExtendedEvent(Session session) : base(session) { }
    public string Notes {
        get { return GetPropertyValue<string>(nameof(Notes)); }
        set { SetPropertyValue<string>(nameof(Notes), value); }
    }
}

Let’s create a Recurring Event that represents a weekly meeting that starts at 10 a.m. and set its Notes property to “regular meetings”:

SchedulerCustomEvent1

SchedulerCustomEvent2

Now, let’s change the Event’s occurrence, so that is starts an hour earlier - at 9 a.m. To do so, we can either double-click on the occurrence and select “Edit this occurrence” or just drag the occurrence rectangle on the Scheduler’s timeline. Right now the choice does not matter, so let’s just drag it.

SchedulerCustomEvent3

Notice how the Event occurrence’s pictogram has become crossed. This indicates that the Event’s occurrence no longer matches the settings defined in the Recurrence Pattern. So, it is stored in the collection of exceptions. Now, let’s open the occurrence to check the additional Notes property we have introduced in the ExtendedEvent class.

SchedulerCustomEvent4

As you can see, the Notes property has an empty value. When creating an exceptional Event occurrence, the Scheduler takes into account the properties defined in the IEvent interface only. In the following code snippet, we illustrate how to resolve this problem by handling the SchedulerListEditorBase.ExceptionEventCreated event. This event occurs when an exceptional Event occurrence is created. The event handler’s argument supplies two properties.

In the simplest case, when additional properties do not require custom processing, you need to copy the additional properties’ values from the object returned by the PatternEvent to the object returned by the ExceptionEvent property. The following code snippet illustrates how this can be performed via a View Controller.

using DevExpress.ExpressApp.Scheduler;

//...

public partial class CustomEventController : ViewController {
    private SchedulerListEditorBase schedulerEditor;

    public CustomEventController() {
        InitializeComponent();
        this.TargetViewType = ViewType.ListView;
    }

    private void CustomEventController_Activated(object sender, EventArgs e) {
        schedulerEditor = ((ListView)View).Editor as SchedulerListEditorBase;
        if (schedulerEditor != null) {
            schedulerEditor.ExceptionEventCreated += 
                new EventHandler<ExceptionEventCreatedEventArgs>(
                   schedulerEditor_ExceptionEventCreated);
        }
    }

    private void CustomEventController_Deactivating(object sender, EventArgs e) {
        if (schedulerEditor != null) {
            schedulerEditor.ExceptionEventCreated -= 
                new EventHandler<ExceptionEventCreatedEventArgs>(
                   schedulerEditor_ExceptionEventCreated);
        }
    }

    void schedulerEditor_ExceptionEventCreated(object sender, ExceptionEventCreatedEventArgs e) {
        if (e.PatternEvent is ExtendedEvent && e.ExceptionEvent is ExtendedEvent) {
            ((ExtendedEvent)e.ExceptionEvent).Notes = ((ExtendedEvent)e.PatternEvent).Notes;
        }
    }
}

When the CustomEventController is activated, it checks whether the current List View’s List Editor derives from the SchedulerListEditorBase or not. If it does, the Controller subscribes to the SchedulerListEditorBase.ExceptionEventCreated event. In the event handler, the Controller checks whether or not the Scheduler is activated for the ExtendedEvent class. If it is, the Controller copies the Notes property’s value to the created exceptional Event occurrence. When the Controller is deactivated, it unsubscribes from the ExceptionEventCreated event.

Now, if we create a Recurring Event and change its occurrence, the Notes property will retain its original value.

SchedulerCustomEvent5

Note that you cannot decorate additional properties processed via the ExceptionEventCreated event with validation rules using the standard Save validation context. This context is checked when the IObjectSpace.Committing event is raised. However, property values are copied to an exceptional event occurrence when the IObjectSpace.ObjectSaving event is raised. The Committing event is raised before the ObjectSaving event and so such validation rules are checked before correct values are assigned to corresponding properties. In this case, use a custom validation context instead of the standard Save context.

using DevExpress.ExpressApp.Xpo;
using DevExpress.ExpressApp.Validation;
// ...
public class ExtendedEvent : Event {
    [RuleRequiredField("", "SchedulerValidation")]
    public string Notes {
    // ...
    protected override void OnSaving() {
        base.OnSaving();
        Validator.RuleSet.Validate(XPObjectSpace.FindObjectSpaceByObject(this), this, "SchedulerValidation");
    }
}

It also makes sense to trigger validation when additional event properties are filled with values.

using DevExpress.ExpressApp.Validation;
// ...
void schedulerEditor_ExceptionEventCreated(object sender, ExceptionEventCreatedEventArgs e) {
    if (e.PatternEvent is ExtendedEvent && e.ExceptionEvent is ExtendedEvent) {
        ((ExtendedEvent)e.ExceptionEvent).Notes = ((ExtendedEvent)e.PatternEvent).Notes;
        Validator.RuleSet.Validate(ObjectSpace, e.ExceptionEvent, "SchedulerValidation");
    }
}
See Also