Back to Devexpress

Custom Appointment Fields in Blazor Scheduler

blazor-404547-components-scheduler-customization-custom-fields.md

latest11.0 KB
Original Source

Custom Appointment Fields in Blazor Scheduler

  • May 28, 2025
  • 5 minutes to read

YouTube video

The DevExpress Blazor Scheduler works with the DxSchedulerDataStorage object that contains source data for the following objects:

These items contain predefined sets of properties. When you bind a Scheduler to data, you map these properties to data source fields (see the AppointmentMappings, AppointmentLabelMappings, AppointmentStatusMappings, ResourceMappings properties).

You can add custom properties to Scheduler items:

  1. Define custom fields in source objects. These objects must have both getter and setter, and must not implement the readonly modifier.
  2. Add created fields to the CustomFieldMappings collection.

You can use custom properties in appointment templates and custom appointment forms.

Add a Custom Field to an Appointment

The following code snippet implements the following scenario:

razor
<DxScheduler @ref="Scheduler"
             @bind-StartDate="@StartDate" DataStorage="@DataStorage"
             @bind-ActiveViewType="@ActiveViewType"
             AppointmentFormShowing="OnAppointmentFormShowing"
             ValidateEditForm="true" CssClass="demo-sc-size"
             @bind-AppointmentFormMode="@AppointmentFormMode">
    <Views>
        <DxSchedulerWorkWeekView VisibleTime="@(new DxSchedulerTimeSpanRange(TimeSpan.FromHours(8), TimeSpan.FromHours(19)))">
            <HorizontalAppointmentTemplate>
                <div class="demo-sc-apt @(IsAccepted(context.CustomFields) ? "demo-sc-accepted " : "") w-100">
                    <div class="card demo-apt-bg dxbl-purple-color w-100"></div>
                    <div class="card shadow-sm p-1 demo-sc-apt-content text-white w-100">
                        @context.Appointment.Subject
                    </div>
                </div>
            </HorizontalAppointmentTemplate>
            <VerticalAppointmentTemplate>
                <div class="shadow-sm demo-sc-apt @(IsAccepted(context.CustomFields) ? "demo-sc-accepted" : "")">
                    <div class="card demo-apt-bg dxbl-purple-color"></div>
                    <div class="card demo-sc-apt-content text-white">
                        <div class="card demo-sc-status-container">
                            <div class="card demo-apt-status dxbl-purple-color"></div>
                        </div>
                        <div class="demo-apt-subject">
                            @context.Appointment.Subject
                        </div>
                    </div>
                </div>
            </VerticalAppointmentTemplate>
        </DxSchedulerWorkWeekView>
    </Views>
@* ... *@
</DxScheduler>
@* ... *@
@code {
    DxScheduler Scheduler { get; set; }
    SchedulerAppointmentFormMode AppointmentFormMode { get; set; } = SchedulerAppointmentFormMode.Both;
    List<SchedulerAppointmentFormMode> EditModes = Enum.GetValues(typeof(SchedulerAppointmentFormMode))
        .OfType<SchedulerAppointmentFormMode>()
        .ToList();

    DateTime StartDate { get; set; } = DateTime.Today;
    SchedulerViewType ActiveViewType { get; set; } = SchedulerViewType.WorkWeek;

    public class CustomAppointmentFormInfo : SchedulerAppointmentFormInfo {
        public CustomAppointmentFormInfo(DxSchedulerAppointmentItem AppointmentItem, DxSchedulerDataStorage DataStorage, DxScheduler scheduler) : base(AppointmentItem, DataStorage, scheduler) { }

        [Required]
        public override string Subject {
            get { return base.Subject; }
            set { base.Subject = value; }
        }

        public bool IsAccepted {
            get { return IsAccepted(CustomFields); }
            set { CustomFields["IsAccepted"] = value; }
        }
    }

    void OnAppointmentFormShowing(SchedulerAppointmentFormEventArgs args) {
        args.FormInfo = new CustomAppointmentFormInfo(args.Appointment, DataStorage, Scheduler);
    }

    static bool IsAccepted(DxExpandoDictionaryObject customFields) => true == (bool?)customFields["IsAccepted"];

    DxSchedulerDataStorage DataStorage = new DxSchedulerDataStorage() {
        AppointmentsSource = AppointmentCollection.GetAppointments(),
        AppointmentMappings = new DxSchedulerAppointmentMappings() {
            Type = "AppointmentType",
            Start = "StartDate",
            End = "EndDate",
            Subject = "Caption",
            AllDay = "AllDay",
            Location = "Location",
            Description = "Description",
            CustomFieldMappings = new List<DxSchedulerCustomFieldMapping> {
                new DxSchedulerCustomFieldMapping { Name = "IsAccepted", Mapping = "Accepted" }
            }
        }
    };
}
csharp
public static partial class Appointment {
    public class Appointment {
        public Appointment() { }
        public int AppointmentType { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        //...
        // Custom field
        public bool Accepted { get; set; }
    }
}
csharp
public static partial class AppointmentCollection {
    public static List<Appointment> GetAppointments() {
        DateTime date = DateTimeUtils.CreateWeekStart();
        var dataSource = new List<Appointment>() {
                new Appointment {
                    Caption = "Install New Router in Dev Room",
                    StartDate = date + (new TimeSpan(0, 10, 0, 0)),
                    EndDate = date + (new TimeSpan(0, 12, 30, 0)),
                    Label = 6,
                    Status = 4
                },
                new Appointment {
                    Caption = "Upgrade Personal Computers",
                    StartDate = date + (new TimeSpan(0, 13, 0, 0)),
                    EndDate = date + (new TimeSpan(0, 15, 30, 0)),
                    Label = 1,
                    Status = 4
                },
                new Appointment {
                    Caption = "Website Redesign Plan",
                    StartDate = date + (new TimeSpan(1, 9, 30, 0)),
                    EndDate = date + (new TimeSpan(1, 12, 0, 0)),
                    Label = 1,
                    Status = 1,
                    Accepted = true
                },
                new Appointment {
                    Caption = "New Brochures",
                    StartDate = date + (new TimeSpan(1, 13, 30, 0)),
                    EndDate = date + (new TimeSpan(1, 15, 15, 0)),
                    Label = 8,
                    Status = 2,
                    Accepted = true
                },
                // ...
            };
        return dataSource;
    }
    public static class DateTimeUtils {
        public static DateTime GetWeekStart(DateTime date) {
            return date.DayOfWeek == DayOfWeek.Sunday ? ValidWeekStart(date.Date) : ValidWeekStart(date.Date - CreateWeekOffset(date, DayOfWeek.Sunday));
        }
        public static DateTime GetBeginOfMonth(DateTime date) {
            return new DateTime(date.Year, date.Month, 1);
        }
        static DateTime ValidWeekStart(DateTime date) {
            TimeSpan weekSpan = new TimeSpan(7, 0, 0, 0);
            DateTime baseDate = date.Date;
            if(DateTime.MaxValue - date < weekSpan)
                return baseDate - weekSpan;
            return baseDate;
        }
        static TimeSpan CreateWeekOffset(DateTime date, DayOfWeek firstDayOfWeek) {
            int offset = (date.DayOfWeek + 7 - firstDayOfWeek) % 7;
            TimeSpan result = TimeSpan.FromDays(offset);
            if(date.Ticks < result.Ticks)
                result = TimeSpan.FromDays(offset - 7);
            return result;
        }
    }
}

Run Demo: Scheduler - Custom Fields and Appointment Form

YouTube video

Add a Custom Field to a Label

The following code snippet adds a custom field to LabelObject and maps this field to the appointment label’s custom property:

csharp
@code {
    public class LabelObject {
        public int Id { get; set; }
        public string LabelName { get; set; }
        public System.Drawing.Color LabelColor { get; set; }
        public string MyCustomField { get; set; } // a custom field
    }

    DxSchedulerDataStorage DataStorage = new DxSchedulerDataStorage() {
        AppointmentLabelsSource = new List<LabelObject>() {
            new LabelObject() { 
                Id = 1, 
                LabelName = "Label One", 
                LabelColor = System.Drawing.Color.Aqua, 
                MyCustomField = "custom text for Label One" 
            },
            new LabelObject() { 
                Id = 2, 
                LabelName = "Label Two", 
                LabelColor = System.Drawing.Color.Beige, 
                MyCustomField = "custom text for Label Two"
            },
        },
        AppointmentLabelMappings = new DxSchedulerAppointmentLabelMappings() {
            Id = "Id",
            Caption = "LabelName",
            Color = "LabelColor",
            // Map the source object's custom field to the label's custom property
            CustomFieldMappings = new List<DxSchedulerCustomFieldMapping> {
                new DxSchedulerCustomFieldMapping { Name = "MyCustomProperty", Mapping = "MyCustomField" }
            }
        }
    };
}

Refer to AppointmentLabelMappings for additional information.