| |
 |
How to: Customize the Appointment Dialog using View Model API (working with custom fields)
Note
The information in this topic applies to DevExpress ASP.NET Scheduler version 17.2 and later.
As a follow-up to How to: Customize the Appointment Dialog using View Model API (simple customization), this topic provides a step-by-step tutorial about advanced Appointment Dialog customization (working with custom fields).
In this tutorial, cascading combo boxes are used to edit the two hierarchical custom fields. The first combo box (with the "meeting", "travel", "phone call" values) replaces the "Subject" text box. When an end-user selects the "phone call" item from the editor's dropdown, the "Company" and "Contact" combo boxes appear in the dialog.
To use this tutorial, start with a sample project in which the Scheduler extension is bound to a collection of custom objects: How to bind MVC Scheduler to a collection of custom objects (List).
Then, follow the steps below:

Step 1 - Update Data Source
Add two integer properties (“CompanyID” and “ContactID”) to the CustomAppointment class:
C# |
public int CompanyID { get { return m_company_id; } set { m_company_id = value; } }
public int ContactID { get { return m_conact_id; } set { m_conact_id = value; } }
|
VB |
Public Property CompanyID() As Integer
Get
Return m_company_id
End Get
Set(ByVal value As Integer)
m_company_id = value
End Set
End Property
Public Property ContactID() As Integer
Get
Return m_conact_id
End Get
Set(ByVal value As Integer)
m_conact_id = value
End Set
End Property
|

Step 2 - Specify Custom Field Mappings
Add custom field mappings to the previously created fields at runtime using the following code:
C# |
appointmentStorage.CustomFieldMappings.Add(new DevExpress.Web.ASPxScheduler.ASPxAppointmentCustomFieldMapping("AppointmentCompany", "CompanyID"));
appointmentStorage.CustomFieldMappings.Add(new DevExpress.Web.ASPxScheduler.ASPxAppointmentCustomFieldMapping("AppointmentContact", "ContactID"));
|
VB |
appointmentStorage.CustomFieldMappings.Add(New DevExpress.Web.ASPxScheduler.ASPxAppointmentCustomFieldMapping("AppointmentCompany", "CompanyID"))
appointmentStorage.CustomFieldMappings.Add(New DevExpress.Web.ASPxScheduler.ASPxAppointmentCustomFieldMapping("AppointmentContact", "ContactID"))
|

Step 3 - Create a custom AppointmentEditDialogViewModel descendant
The AppointmentEditDialogViewModel descendant allows changing predefined editors, remove unnecessary editors and add new editors (fields) using the Load method overload.
Replace the “Subject” text box with a combo box by calling the Load method overload. In the following code, use the SetEditorTypeFor method to specify the type of the editor used for editing a specific field, and the SetDataItemsFor method to generate items for the editors intended to work with collections.
C# |
base.Load(appointmentController);
SetEditorTypeFor(m => m.Subject, DialogFieldEditorType.ComboBox);
SetDataItemsFor(m => m.Subject, (addItemDelegate) => {
addItemDelegate("meeting", "meeting");
addItemDelegate("travel", "travel");
addItemDelegate("phone call", "phonecall");
});
|
VB |
MyBase.Load(appointmentController)
SetEditorTypeFor(Function(m) m.Subject, DialogFieldEditorType.ComboBox)
SetDataItemsFor(Function(m) m.Subject, Sub(addItemDelegate)
addItemDelegate("meeting", "meeting")
addItemDelegate("travel", "travel")
addItemDelegate("phone call", "phonecall")
End Sub)
|
Add two combo boxes to edit the “Company” and “Contact” custom fields. For this, declare two corresponding properties in the CustomAppointmentEditDialogViewModel object. Note that the properties names should be the same as in the “custom field” mappings to save and load the custom field values correctly. In the code, the DialogFieldViewSettings parameters allow specifying the editor type used for editing a property value, as well as the editor caption.
C# |
[DialogFieldViewSettings(Caption = "Company", EditorType = DialogFieldEditorType.ComboBox)]
public int AppointmentCompany { get; set; }
[DialogFieldViewSettings(Caption = "Contact", EditorType = DialogFieldEditorType.ComboBox)]
public int AppointmentContact { get; set; }
|
VB |
<DialogFieldViewSettings(Caption := "Company", EditorType := DialogFieldEditorType.ComboBox)> _
Public Property AppointmentCompany() As Integer
<DialogFieldViewSettings(Caption := "Contact", EditorType := DialogFieldEditorType.ComboBox)> _
Public Property AppointmentContact() As Integer
|
Generate items for the cascading combo boxes using the SetDataItemsFor method within the AppointmentEditDialogViewModel.Load method.
C# |
List<Company> companies = Company.GenerateCompanyDataSource();
SetDataItemsFor((CustomAppointmentEditDialogViewModel m) => m.AppointmentCompany, (addItemDelegate) => {
foreach(Company comp in companies) {
addItemDelegate(comp.CompanyName, comp.CompanyID);
}
});
|
VB |
Dim companies As List(Of Company) = Company.GenerateCompanyDataSource()
SetDataItemsFor(Function(m As CustomAppointmentEditDialogViewModel) m.AppointmentCompany, Sub(addItemDelegate)
For Each comp As Company In companies
addItemDelegate(comp.CompanyName, comp.CompanyID)
Next comp
End Sub)
|
Implement "Contact" combo box filtering items based on a selected “Company” combo box value.
C# |
SetDataItemsFor((CustomAppointmentEditDialogViewModel m) => m.AppointmentContact, (addItemDelegate) => {
List<CompanyContact> contacts = CompanyContact.GenerateContactDataSource().Where(c => c.CompanyID == AppointmentCompany).ToList();
addItemDelegate("", 0);
foreach(CompanyContact cont in contacts) {
addItemDelegate(cont.ContactName, cont.ContactID);
}
});
|
VB |
SetDataItemsFor(Function(m As CustomAppointmentEditDialogViewModel) m.AppointmentContact, Sub(addItemDelegate)
Dim contacts As List(Of CompanyContact) = CompanyContact.GenerateContactDataSource().Where(Function(c) c.CompanyID = AppointmentCompany).ToList()
addItemDelegate("", 0)
For Each cont As CompanyContact In contacts
addItemDelegate(cont.ContactName, cont.ContactID)
Next cont
End Sub)
|
Then, use the TrackPropertyChangeFor method to regenerate the “Contact” combo box items after changing the “Company” editor's value. This method allows you to track property value changes on the server-side using a corresponding callback request. The form editors are reloaded after executing the callback request.
C# |
TrackPropertyChangeFor((CustomAppointmentEditDialogViewModel m) => m.AppointmentCompany, () => {
AppointmentContact = 0;
});
|
VB |
TrackPropertyChangeFor(Function(m As CustomAppointmentEditDialogViewModel) m.AppointmentCompany, Sub()
AppointmentContact = 0
End Sub)
|
Invoke the TrackPropertyChangeFor method for the “Subject” field with an empty action to reload the dialog content. It allows changing the “Company” and “Contact” combo boxes' visibility depending on the “Subject” editor value.
C# |
TrackPropertyChangeFor(m => m.Subject, () => { });
|
VB |
TrackPropertyChangeFor(Function(m) m.Subject, Sub()
End Sub);
|
The AppointmentEditDialogViewModel object allows changing the dialog editors' visibility and availability based on custom conditions.
Use the SetDialogElementStateConditions overload method to customize the editors' visibility on the form as follows:
-
Hiding the "Location", "All-Day" and "Reminder" editors on the edit form.
-
Showing "Company" and "Contact" editors only when an end-user selects the "phone call" item in the “Subject” editor's dropdown.
-
Showing the "Contact” editor only when an end-user selects an item in the “Company” combo box.
C# |
public override void SetDialogElementStateConditions() {
base.SetDialogElementStateConditions();
SetItemVisibilityCondition("Location", false);
SetItemVisibilityCondition(vm => vm.IsAllDay, false);
SetItemVisibilityCondition(vm => vm.Reminder, false);
SetEditorEnabledCondition((CustomAppointmentEditDialogViewModel vm) => vm.AppointmentContact, AppointmentCompany > 0);
SetItemVisibilityCondition((CustomAppointmentEditDialogViewModel vm) => vm.AppointmentContact, Subject == "phonecall");
SetItemVisibilityCondition((CustomAppointmentEditDialogViewModel vm) => vm.AppointmentCompany, Subject == "phonecall");
}
|
VB |
Public Overrides Sub SetDialogElementStateConditions()
MyBase.SetDialogElementStateConditions()
SetItemVisibilityCondition("Location", False)
SetItemVisibilityCondition(Function(vm) vm.IsAllDay, False)
SetItemVisibilityCondition(Function(vm) vm.Reminder, False)
SetEditorEnabledCondition(Function(vm As CustomAppointmentEditDialogViewModel) vm.AppointmentContact, AppointmentCompany > 0)
SetItemVisibilityCondition(Function(vm As CustomAppointmentEditDialogViewModel) vm.AppointmentContact, Subject = "phonecall")
SetItemVisibilityCondition(Function(vm As CustomAppointmentEditDialogViewModel) vm.AppointmentCompany, Subject = "phonecall")
End Sub
|
The custom AppointmentEditDialogViewModel descendant's complete code for the described scenario is illustrated below:
C# |
public class CustomAppointmentEditDialogViewModel : AppointmentEditDialogViewModel {
[DialogFieldViewSettings(Caption = "Company", EditorType = DialogFieldEditorType.ComboBox)]
public int AppointmentCompany { get; set; }
[DialogFieldViewSettings(Caption = "Contact", EditorType = DialogFieldEditorType.ComboBox)]
public int AppointmentContact { get; set; }
public override void Load(AppointmentFormController appointmentController) {
base.Load(appointmentController);
SetEditorTypeFor(m => m.Subject, DialogFieldEditorType.ComboBox);
SetDataItemsFor(m => m.Subject, (addItemDelegate) => {
addItemDelegate("meeting", "meeting");
addItemDelegate("travel", "travel");
addItemDelegate("phone call", "phonecall");
});
List<Company> companies = Company.GenerateCompanyDataSource();
SetDataItemsFor((CustomAppointmentEditDialogViewModel m) => m.AppointmentCompany, (addItemDelegate) => {
foreach(Company comp in companies) {
addItemDelegate(comp.CompanyName, comp.CompanyID);
}
});
SetDataItemsFor((CustomAppointmentEditDialogViewModel m) => m.AppointmentContact, (addItemDelegate) => {
List<CompanyContact> contacts = CompanyContact.GenerateContactDataSource().Where(c => c.CompanyID == AppointmentCompany).ToList();
addItemDelegate("", 0);
foreach(CompanyContact cont in contacts) {
addItemDelegate(cont.ContactName, cont.ContactID);
}
});
TrackPropertyChangeFor((CustomAppointmentEditDialogViewModel m) => m.AppointmentCompany, () => {
AppointmentContact = 0;
});
TrackPropertyChangeFor(m => m.Subject, () => { });
}
public override void SetDialogElementStateConditions() {
base.SetDialogElementStateConditions();
SetItemVisibilityCondition("Location", false);
SetItemVisibilityCondition(vm => vm.IsAllDay, false);
SetItemVisibilityCondition(vm => vm.Reminder, false);
SetEditorEnabledCondition((CustomAppointmentEditDialogViewModel vm) => vm.AppointmentContact, AppointmentCompany > 0);
SetItemVisibilityCondition((CustomAppointmentEditDialogViewModel vm) => vm.AppointmentContact, Subject == "phonecall");
SetItemVisibilityCondition((CustomAppointmentEditDialogViewModel vm) => vm.AppointmentCompany, Subject == "phonecall");
}
}
|
VB |
Public Class CustomAppointmentEditDialogViewModel
Inherits AppointmentEditDialogViewModel
<DialogFieldViewSettings(Caption := "Company", EditorType := DialogFieldEditorType.ComboBox)> _
Public Property AppointmentCompany() As Integer
<DialogFieldViewSettings(Caption := "Contact", EditorType := DialogFieldEditorType.ComboBox)> _
Public Property AppointmentContact() As Integer
Public Overrides Sub Load(ByVal appointmentController As AppointmentFormController)
MyBase.Load(appointmentController)
SetEditorTypeFor(Function(m) m.Subject, DialogFieldEditorType.ComboBox)
SetDataItemsFor(Function(m) m.Subject, Sub(addItemDelegate)
addItemDelegate("meeting", "meeting")
addItemDelegate("travel", "travel")
addItemDelegate("phone call", "phonecall")
End Sub)
Dim companies As List(Of Company) = Company.GenerateCompanyDataSource()
SetDataItemsFor(Function(m As CustomAppointmentEditDialogViewModel) m.AppointmentCompany, Sub(addItemDelegate)
For Each comp As Company In companies
addItemDelegate(comp.CompanyName, comp.CompanyID)
Next comp
End Sub)
SetDataItemsFor(Function(m As CustomAppointmentEditDialogViewModel) m.AppointmentContact, Sub(addItemDelegate)
Dim contacts As List(Of CompanyContact) = CompanyContact.GenerateContactDataSource().Where(Function(c) c.CompanyID = AppointmentCompany).ToList()
addItemDelegate("", 0)
For Each cont As CompanyContact In contacts
addItemDelegate(cont.ContactName, cont.ContactID)
Next cont
End Sub)
TrackPropertyChangeFor(Function(m As CustomAppointmentEditDialogViewModel) m.AppointmentCompany, Sub()
AppointmentContact = 0
End Sub)
TrackPropertyChangeFor(Function(m) m.Subject, Sub()
End Sub);
End Sub
Public Overrides Sub SetDialogElementStateConditions()
MyBase.SetDialogElementStateConditions()
SetItemVisibilityCondition("Location", False)
SetItemVisibilityCondition(Function(vm) vm.IsAllDay, False)
SetItemVisibilityCondition(Function(vm) vm.Reminder, False)
SetEditorEnabledCondition(Function(vm As CustomAppointmentEditDialogViewModel) vm.AppointmentContact, AppointmentCompany > 0)
SetItemVisibilityCondition(Function(vm As CustomAppointmentEditDialogViewModel) vm.AppointmentContact, Subject = "phonecall")
SetItemVisibilityCondition(Function(vm As CustomAppointmentEditDialogViewModel) vm.AppointmentCompany, Subject = "phonecall")
End Sub
End Class
|

Step 4 - Replace the predefined View Model with a custom one
To replace the predefined View Model with a custom one, use the following code (for example, within the Page.Init event handler):
C# |
var dialog = settings.OptionsForms.DialogLayoutSettings.AppointmentDialog;
dialog.ViewModel = new CustomAppointmentEditDialogViewModel();
|
VB |
Dim dialog = settings.OptionsForms.DialogLayoutSettings.AppointmentDialog
dialog.ViewModel = New CustomAppointmentEditDialogViewModel()
|

Step 5 - Generate a default dialog layout and add custom editors into the dialog
The AppointmentDialog.GenerateDefaultLayoutElements method generates the default dialog layout and can also be used to reorder custom editors on the dialog form.
To locate the editors below the “Description” field on the form, do the following:
C# |
var dialog = settings.OptionsForms.DialogLayoutSettings.AppointmentDialog;
dialog.ViewModel = new CustomAppointmentEditDialogViewModel();
dialog.GenerateDefaultLayoutElements();
var companies = dialog.LayoutElements.CreateField((CustomAppointmentEditDialogViewModel m) => m.AppointmentCompany);
var contacts = dialog.LayoutElements.CreateField((CustomAppointmentEditDialogViewModel m) => m.AppointmentContact);
dialog.InsertBefore(companies, dialog.FindLayoutElement("Description"));
dialog.InsertAfter(contacts, companies);
|
VB |
Dim dialog = settings.OptionsForms.DialogLayoutSettings.AppointmentDialog
dialog.ViewModel = New CustomAppointmentEditDialogViewModel()
dialog.GenerateDefaultLayoutElements()
Dim companies = dialog.LayoutElements.CreateField(Function(m As CustomAppointmentEditDialogViewModel) m.AppointmentCompany)
Dim contacts = dialog.LayoutElements.CreateField(Function(m As CustomAppointmentEditDialogViewModel) m.AppointmentContact)
dialog.InsertBefore(companies, dialog.FindLayoutElement("Description"))
dialog.InsertAfter(contacts, companies)
|
Is this topic helpful?
Additional Feedback
Close
|