Skip to main content

Customizing Event and Event recurrence dialogs

  • 8 minutes to read

This topic describes how to build custom Event and Event recurrence dialogs. The ways of creating the custom fields are described for bound and unbound data modes:

  • Bound Mode – the data is stored in a database.

  • Unbound Mode – the data is stored in a file system.

Custom fields enable the data to be transferred between custom controls and storage. To specify custom fields, the TcxSchedulerDBStorage.CustomFields and TcxSchedulerStorage.CustomFields properties are used. The first property is required when the scheduler works in Bound Mode and the latter when it works in Unbound Mode.

Bound Mode

The cxSchedulerTable.db table was created in Paradox® format using the BDE toolset. To learn how to set up a connection to the data store, refer to the Bound Mode help topic.

Add four fields to the cxSchedulerTable.db table: FName, LName, Gender and Comments.

Field Name

Type

Size

1

ActualFinish

TIntegerField

2

ActualStart

TIntegerField

3

Caption

TStringField

255

4

EventType

TIntegerField

5

Finish

TDateTimeField

or TSQLTimeStampField

6

GroupID

TIntegerField

or GUID

7

ID

TIntegerField

(Autoincrement)

or GUID

8

LabelColor

TIntegerField

9

Location

TStringField

255

10

Message

TStringField

255

11

Options

TIntegerField

12

ParentID

TIntegerField

or GUID

13

RecurrenceIndex

TIntegerField

14

RecurrenceInfo

TBlobField

15

ReminderDate

TDateTimeField

or TSQLTimeStampField

16

ReminderMinutesBeforeStart

TIntegerField

17

ReminderResourcesData

TBlobField

18

ResourceID

TIntegerField

or TBlobField

19

Start

TDateTimeField

or TSQLTimeStampField

20

State

TIntegerField

21

TaskCompleteField

TIntegerField

22

TaskIndexField

TIntegerField

23

TaskLinksField

TBlobField

24

TaskStatusField

TIntegerField

25

FName

TStringField

255

26

LName

TStringField

255

27

Gender

TStringField

6

28

Comments

TStringField

255

These fields are used to persist the custom fields’ data. The FName, LName and Gender fields store the data edited by an end-user in the teFirstName, teLastName and cbGender custom editing controls (described later in this topic) located in the custom Event dialog. The Comments field stores the data edited in the teComments custom editing control located in the custom Event recurrence dialog.

To work in Bound Mode, bind the TcxSchedulerDBStorage component to the scheduler via the TcxScheduler.Storage property.

Using the Object Inspector, click the ellipsis button next to the TcxSchedulerDBStorage.CustomFields property to open the collection editor. In the collection editor, create four custom fields and bind them to the dataset fields, as shown in the following image below:

Unbound Mode

To work in Unbound Mode, bind the TcxSchedulerStorage to the scheduler via the TcxScheduler.Storage property.

Using the Object Inspector, click the ellipsis button next to the TcxSchedulerStorage.CustomFields property to open the collection editor. In the collection editor, create four custom fields, name them and then define the type of each custom field, as shown in the following image:

Note that you must pass custom field names, as they were defined in the Object Inspector, as arguments to the TcxSchedulerEvent.GetCustomFieldValueByName and TcxSchedulerEvent.SetCustomFieldValueByName methods.

Implement the TCustomForm.OnCreate and TCustomForm.OnDestroy event handlers in the main unit (the form where the scheduler is located), to use the data across multiple sessions, as shown in the following example:

unit CustomDialogsUnit;
// ...
procedure TUnboundForm.FormCreate(Sender: TObject);
const
  DlgMsg = 'There was no file found';
  FileName = 'c:\unbound.dat';
begin
  if FileExists(FileName) then
    // load the data from the file when the application starts up
    Storage.LoadFromFile(FileName) 
  else
    ShowMessage(DlgMsg);
end;
procedure TUnboundForm.FormDestroy(Sender: TObject; var Action: TCloseAction);
const
  FileName = 'c:\unbound.dat';
begin
  // save the data to the file when the application exits
  Storage.SaveToFile(FileName); 
end;

Creating custom dialogs

The event dialogs hierarchy was designed, so that a developer can use the blank dialog and populate it with the custom editing controls or benefit from the full-featured event dialog and just make minor changes to it, if required.

To use the blank event dialog or blank recurrence dialog, derive from the TcxSchedulerCustomEventEditor or TcxSchedulerCustomRecurrenceEventEditor classes.

To create custom dialogs based on the scheduler’s dialogs, create descendants of the TcxSchedulerEventEditor and TcxSchedulerRecurrenceEventEditor classes, which are responsible for the Event and Event recurrence dialog forms, respectively.

To notify the application that the custom Event and Event recurrence dialogs are to be invoked at runtime, use the cxEventEditorClass (the cxSchedulerDialogs unit) and cxRecurrenceEventEditorClass (the cxSchedulerDialogs unit) constants. See the code shown below in this topic that demonstrates how to bind descendants using these constants.

First, create the custom Event dialog:

1.To facilitate the task of building the custom Event dialog form, add the cxSchedulerEventEditor.pas (cxSchedulerEventEditor.dcu) file (in which the TcxSchedulerEventEditor class is defined) to the project, using the Add to Project dialog. To open this dialog use the Shift+F11 keys or go to the main menu and select the Project -> Add to Project… item.

2.Then create the new dialog form using the TcxSchedulerEventEditor‘s template form stored in the Object Repository. Go File -> New -> Other… in the main menu to open the New Items dialog and activate the page of your currently opened project by clicking the tab which has your project’s name, in this case CustomDialogs:

Select the cxSchedulerEventEditor icon and click the OK button. The new Event dialog form appears with its features inherited from the TcxSchedulerEventEditor parent class.

3.In the Component Palette select and drop the TcxGroupBox control (located on the Express Utilities page), three TcxLabel controls, two TcxTextEdit controls and the TcxComboBox control (located on the Express Editors page) onto the form created.

4.Using the Object Inspector, set the Caption and Name properties of the TcxGroupBox control to the Client and gbClient values, respectively. The Caption and Name properties of the three TcxLabel controls to First Name and lbFirstName, Last Name and lbLastName, Gender: and lbGender values, respectively. The Name property of the two TcxTextEdit controls to teFirstName and teLastName values, and lastly, the Name property of the TcxComboBox control to cbGender and add the female and male values to the TcxComboBoxProperties.Items property.

The following example implements the custom Event dialog:

unit CustomizedEventEditorForm;
// ...
type
  TcxSchedulerEventEditorCustomized = class(TcxSchedulerEventEditor)
    gbClient: TcxGroupBox;
    lbFirstName: TcxLabel;
    teFirstName: TcxTextEdit;
    lbLastName: TcxLabel;
    teLastName: TcxTextEdit;
    lbGender: TcxLabel;
    cbGender: TcxComboBox;
  private
    { Private declarations }
  protected
    procedure LoadEventValuesIntoControls; override;
    procedure UpdateEventValuesFromControls; override;
  public
    { Public declarations }
  end;
var
  cxSchedulerEventEditorCustomized: TcxSchedulerEventEditorCustomized;
implementation
uses
  cxSchedulerDialogs;
{$R *.dfm}
procedure TcxSchedulerEventEditorCustomized.LoadEventValuesIntoControls;
const
  CLRF = #13#10;
  DlgMsg = 'Can''t load data';
begin
  // invoke the parent's method to load the data into the inherited editing controls located on the form
  inherited LoadEventValuesIntoControls; 
  try
    // load the data into the custom editing controls
    // no checking for a null value is needed. The null value is automatically replaced with empty string in the editing controls
    teFirstName.EditValue := Event.GetCustomFieldValueByName('FName');
    teLastName.EditValue := Event.GetCustomFieldValueByName('LName');
    cbGender.EditValue := Event.GetCustomFieldValueByName('Gender');
  except
    on E: Exception do
      ShowMessage(DlgMsg + CLRF + E.Message);
  end;
end;
procedure TcxSchedulerEventEditorCustomized.UpdateEventValuesFromControls;
const
  CLRF = #13#10;
  DlgMsg = 'Can''t load data';
begin
  // invoke the parent's method to post the data from the inherited editing controls located on the form 
inherited UpdateEventValuesFromControls; 
  try
    // post the data from the custom editing controls
    Event.SetCustomFieldValueByName('FName', teFirstName.EditValue);
    Event.SetCustomFieldValueByName('LName', teLastName.EditValue);
    Event.SetCustomFieldValueByName('Gender', cbGender.EditValue);
    FModified := True;
  except
    on E: Exception do
      ShowMessage(DlgMsg + CLRF + E.Message);  
  end;
end;
initialization
  // to use the cxEventEditorClass constant, specify the cxSchedulerDialogs unit in the uses clause
  // indicate that the new Event dialog will be invoked at runtime
  cxEventEditorClass := TcxSchedulerEventEditorCustomized;

Note

to synchronize changes made by an end-user in the Event dialog with the storage, set the TcxSchedulerEventEditorCustomized.FModified property to True.

Repeat the above steps from 1 through to 2 to create the custom Event recurrence dialog. The TcxSchedulerRecurrenceEventEditor class is defined in the cxSchedulerRecurrenceEditor.pas (cxSchedulerRecurrenceEditor.dcu) file.

Next, drop from the Component Palette the TcxGroupBox control (located on the Express Utilities page), the TcxLabel control and the TcxTextEdit control (located on the Express Editors page) onto the form created.

Using the Object Inspector, set the Caption and Name properties of the TcxGroupBox control to the Other and gbOther values, respectively. The Caption and Name properties of the TcxLabel control to the Comments: and lbComments values, respectively and the TcxTextEdit.Name property to teComments.

The following example implements the custom Event recurrence dialog:

unit CustomizedRecurrenceEventEditorForm;
// ...
type
  TcxSchedulerRecurrenceEventEditorCustomized = class(TcxSchedulerRecurrenceEventEditor)
    gbOther: TcxGroupBox;
    teComments: TcxTextEdit;
    lbComments: TLabel;
  private
    { Private declarations }
  protected
    procedure LoadEventValuesIntoControls; override;
    procedure UpdateEventValuesFromControls; override;
  public
    { Public declarations }
  end;
var
  cxSchedulerRecurrenceEventEditorCustomized: TcxSchedulerRecurrenceEventEditorCustomized;
implementation
uses
  cxSchedulerDialogs;
{$R *.dfm}
procedure TcxSchedulerRecurrenceEventEditorCustomized.LoadEventValuesIntoControls;
const
  CLRF = #13#10;
  DlgMsg = 'Can''t load data';
begin
  inherited LoadEventValuesIntoControls;
  try
    // load the data into the custom editing control
    // no checking for a null value is needed. The null value is automatically replaced with empty string in the editing controls
    teComments.EditValue := Event.GetCustomFieldValueByName('Comments');
  except
    on E: Exception do
      ShowMessage(DlgMsg + CLRF + E.Message);
  end;
end;
procedure TcxSchedulerRecurrenceEventEditorCustomized.UpdateEventValuesFromControls;
const
  CLRF = #13#10;
  DlgMsg = 'Can''t load data';
begin
  inherited UpdateEventValuesFromControls;
  try
    // send the data from the custom editing control
    Event.SetCustomFieldValueByName('Comments', teComments.EditValue);
    FModified := True;
  except
    on E: Exception do
      ShowMessage(DlgMsg + CLRF + E.Message);
  end;
end;
initialization
  // to use the cxRecurrenceEventEditorClass constant, specify the cxSchedulerDialogs unit in the uses clause
  // indicate that the new Event recurrence  dialog will be invoked at runtime
  cxRecurrenceEventEditorClass := TcxSchedulerRecurrenceEventEditorCustomized;

Note

to synchronize changes made by an end-user in the Event recurrence dialog with the storage, set the TcxSchedulerRecurrenceEventEditorCustomized.FModified property to True.

Note

if you need to invoke the Event dialog and the Event recurrence dialog programmatically, use the cxShowEventEditorEx and cxShowRecurrenceEditor routines, respectively.