# Devexpress Blazor Scheduler

> Build and configure the DevExpress Blazor Scheduler (DxScheduler) — a calendar/appointment scheduling component for Blazor Server, WebAssembly, and Hybrid apps. Use for day/week/work-week/month/timeline views; data binding via DxSchedulerDataStorage and AppointmentMappings; appointment creation, editing, deletion, drag-and-drop and resize; recurring appointments (RecurrenceInfo / recurrence rules…

- **Type:** Skill
- **Install:** `agentstack add skill-devexpress-agent-skills-devexpress-blazor-scheduler`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [DevExpress](https://agentstack.voostack.com/s/devexpress)
- **Installs:** 0
- **Category:** [Productivity](https://agentstack.voostack.com/c/productivity)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [DevExpress](https://github.com/DevExpress)
- **Source:** https://github.com/DevExpress/agent-skills/tree/main/plugins/dx-blazor/skills/devexpress-blazor-scheduler
- **Website:** https://www.devexpress.com

## Install

```sh
agentstack add skill-devexpress-agent-skills-devexpress-blazor-scheduler
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# DevExpress Blazor Scheduler

`DxScheduler` is a calendar/appointment component for Blazor. It visualizes time-based data as appointments across Day, Week, Work Week, Month, and Timeline views. Users can create, edit, drag, resize, and delete appointments through built-in UI.

## When to Use This Skill

- Display appointments or events in calendar views
- Bind to a collection of appointment data objects via `DxSchedulerDataStorage`
- Support recurring appointments (daily, weekly, monthly, yearly)
- Manage multiple resources (rooms, employees, etc.)
- Create, edit, or delete appointments through the built-in edit forms
- Show work-time-only views with `ShowWorkTimeOnly`
- Navigate between dates with the scheduler toolbar

## Prerequisites & Installation

### NuGet Package

| Package | Purpose |
|---|---|
| `DevExpress.Blazor` | Scheduler + all standard Blazor UI components |

```bash
# Install from NuGet.org:
dotnet add package DevExpress.Blazor
```

### Setup

1. Register in `Program.cs`:
   ```csharp
   builder.Services.AddDevExpressBlazor();
   ```
    > **v26.1 note**: `DevExpress.Blazor` no longer includes `options.BootstrapVersion` or `DevExpress.Blazor.BootstrapVersion`. Do not generate either API.
2. Apply a theme and add client scripts in `App.razor` inside ``:
   ```razor
   @using DevExpress.Blazor
   @DxResourceManager.RegisterTheme(Themes.Fluent)
   @DxResourceManager.RegisterScripts()
   ```
3. Add namespace to `_Imports.razor`:
   ```razor
   @using DevExpress.Blazor
   ```

## Before You Start — Ask the Developer

1. **Render mode**: Are you using `InteractiveServer`, `InteractiveWebAssembly`, or `InteractiveAuto`?
2. **Data model**: What is your appointment data class? What are the field names for start, end, subject, type, recurrence, etc.?
3. **Initial view**: Which view should be shown by default? (Day, Week, Work Week, Month, Timeline)
4. **Start date**: What date should the scheduler open on?
5. **Features**: Do you need recurring appointments? Resources? Custom labels/statuses?

## Component Overview

`DxScheduler` includes:

- **Data Storage** (`DxSchedulerDataStorage`): Connects the component to appointment data via `AppointmentsSource` and `AppointmentMappings`
- **Appointment Mappings** (`DxSchedulerAppointmentMappings`): Maps your data model fields to scheduler concepts (Id, Start, End, Subject, Type, RecurrenceInfo, etc.)
- **Views**: `DxSchedulerDayView`, `DxSchedulerWeekView`, `DxSchedulerWorkWeekView`, `DxSchedulerMonthView`, `DxSchedulerTimelineView`
- **Recurrence** (`DxSchedulerRecurrenceInfo`): Built-in recurrence rule support (Daily, Weekly, Monthly, Yearly)
- **Resources**: Bind appointment resources via `DxSchedulerResourceMappings` and `DxSchedulerDataStorage`
- **Labels & Statuses**: Configurable labels and status indicators for appointments
- **Appointment Templates** (`HorizontalAppointmentTemplate`, `VerticalAppointmentTemplate` on each view; `AppointmentTooltipTemplate` on `DxScheduler`): Customize how appointments and hover tooltips render
- **Drag & Resize** (`AllowDragAppointment`, `AllowDragAppointmentBetweenResources`, `AllowResizeAppointment`): Users can drag appointments to reschedule them, drag between resource groups, or resize by dragging appointment borders; all three are enabled by default; set to `false` to restrict a specific operation; `AppointmentStartDragging`, `AppointmentStartResizing`, and `AppointmentDraggingBetweenResources` events allow customizing or canceling these operations
- **Toolbar** (`ToolbarItems`): Add, remove, or replace built-in toolbar items (`DxSchedulerDateNavigatorToolbarItem`, `DxSchedulerTodayToolbarItem`, etc.) and inject custom `DxToolbarItem` commands

### Core Entry Point (Razor)

```razor
@rendermode InteractiveServer


    


@code {
    DxSchedulerDataStorage DataStorage = new DxSchedulerDataStorage {
        AppointmentsSource = new List(),
        AppointmentMappings = new DxSchedulerAppointmentMappings {
            // Required mappings:
            Id = nameof(AppointmentData.Id),
            Type = nameof(AppointmentData.AppointmentType),
            Start = nameof(AppointmentData.StartDate),
            End = nameof(AppointmentData.EndDate),
            Subject = nameof(AppointmentData.Caption),
            // Optional mappings (add as needed):
            // AllDay = nameof(AppointmentData.AllDay),
            // Description = nameof(AppointmentData.Description),
            // Location = nameof(AppointmentData.Location),
            // LabelId = nameof(AppointmentData.Label),
            // StatusId = nameof(AppointmentData.Status),
            // RecurrenceInfo = nameof(AppointmentData.Recurrence)
        }
    };
}
```

## Documentation & Navigation Guide

### Getting Started
📄 [references/getting-started.md](references/getting-started.md)

When you need to:
- Set up the scheduler from scratch
- Configure `DxSchedulerDataStorage` and `AppointmentMappings`
- Display your first calendar view

### Data Binding
📄 [references/data-binding.md](references/data-binding.md)

When you need to:
- Connect your appointment data model to the scheduler
- Load appointments from a service or database
- Understand all `AppointmentMappings` properties

### Appointments
📄 [references/appointments.md](references/appointments.md)

When you need to:
- Handle appointment creation, editing, and deletion events
- Configure recurring appointments
- Customize appointment display with labels and statuses
- Use the compact form settings

### Views
📄 [references/views.md](references/views.md)

When you need to:
- Choose between Day, Week, Work Week, Month, and Timeline views
- Configure `ShowWorkTimeOnly`
- Set visible time range and cell duration

### Examples
💻 [examples/quickstart.razor](examples/quickstart.razor) — Multi-view scheduler with appointment CRUD, labels, and statuses  
💻 [examples/resources.razor](examples/resources.razor) — Multi-resource timeline view with `ResourcesSource`, `ResourceMappings`, and `GroupType.Resource`

## Quick Start Example

```razor
@page "/scheduler-demo"
@rendermode InteractiveServer


    
    
    
    


@code {
    DxSchedulerDataStorage DataStorage;

    protected override void OnInitialized() {
        var appointments = new List {
            new AppointmentData {
                Id = 1, AppointmentType = 0,
                StartDate = DateTime.Today.AddHours(9),
                EndDate = DateTime.Today.AddHours(10),
                Caption = "Team Meeting",
                Description = "Weekly sync",
                Label = 2, Status = 0
            },
            new AppointmentData {
                Id = 2, AppointmentType = 0,
                StartDate = DateTime.Today.AddDays(1).AddHours(14),
                EndDate = DateTime.Today.AddDays(1).AddHours(15),
                Caption = "Code Review",
                Label = 3, Status = 0
            },
        };

        DataStorage = new DxSchedulerDataStorage {
            AppointmentsSource = appointments,
            AppointmentMappings = new DxSchedulerAppointmentMappings {
                Id = nameof(AppointmentData.Id),
                Type = nameof(AppointmentData.AppointmentType),
                Start = nameof(AppointmentData.StartDate),
                End = nameof(AppointmentData.EndDate),
                Subject = nameof(AppointmentData.Caption),
                Description = nameof(AppointmentData.Description),
                AllDay = nameof(AppointmentData.AllDay),
                Location = nameof(AppointmentData.Location),
                LabelId = nameof(AppointmentData.Label),
                StatusId = nameof(AppointmentData.Status),
                RecurrenceInfo = nameof(AppointmentData.Recurrence)
            }
        };
    }

    class AppointmentData {
        public int Id { get; set; }
        public int AppointmentType { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        public string Caption { get; set; }
        public string Description { get; set; }
        public string Location { get; set; }
        public bool AllDay { get; set; }
        public int Label { get; set; }
        public int Status { get; set; }
        public string Recurrence { get; set; }
    }
}
```

## Key Properties

### DxScheduler

| Property | Type | Description |
|---|---|---|
| `StartDate` | `DateTime` | Initial date displayed |
| `DataStorage` | `DxSchedulerDataStorage` | Data source and mapping configuration |
| `ActiveViewType` | `SchedulerViewType` | Currently active view |
| `GroupType` | `SchedulerGroupType` | Group appointments by date or resource |

### DxSchedulerDataStorage

| Property | Type | Description |
|---|---|---|
| `AppointmentsSource` | `IList` | Collection of appointment data objects |
| `AppointmentMappings` | `DxSchedulerAppointmentMappings` | Field mapping configuration |
| `ResourcesSource` | `IList` | Collection of resource objects |
| `ResourceMappings` | `DxSchedulerResourceMappings` | Resource field mappings |

### DxSchedulerAppointmentMappings

| Property | Maps To |
|---|---|
| `Id` | Appointment unique identifier |
| `Type` | Appointment type (`0` = one-time, `1` = pattern, `2` = occurrence, `3` = changed occurrence, `4` = deleted occurrence) |
| `Start` | Start date/time |
| `End` | End date/time |
| `Subject` | Appointment title |
| `AllDay` | All-day flag (bool) |
| `Description` | Appointment notes |
| `Location` | Location string |
| `LabelId` | Label ID (int?) |
| `StatusId` | Status ID (int) |
| `RecurrenceInfo` | Recurrence XML string |

### Programmatic Recurrence Patterns

When a user asks to make an appointment recurring, create a recurring pattern in the data
source. Set `AppointmentType = 1` and assign a recurrence rule string to the mapped
`Recurrence` field. Do not invent helpers like `WeeklyRecurrence(...)` unless the project
already defines them.

```csharp
var start = DateTime.Today.AddDays(1).AddHours(14);
var end = DateTime.Today.AddDays(1).AddHours(15);

var appointment = new AppointmentData {
    Id = 3,
    AppointmentType = 1,
    StartDate = start,
    EndDate = end,
    Caption = "Planning Session",
    Description = "Sprint planning",
    Label = 5,
    Status = 1,
    Recurrence = string.Format(
        System.Globalization.CultureInfo.InvariantCulture,
        "",
        start,
        end,
        1 "
```

Use this exception rule only for changed or deleted occurrences, not for the base recurring
pattern.

### Advanced Recurrence Details

Use these value mappings when a prompt requires exact recurrence control:

| `WeekDays` value | Meaning |
|---|---|
| `1` | Sunday |
| `2` | Monday |
| `4` | Tuesday |
| `8` | Wednesday |
| `16` | Thursday |
| `32` | Friday |
| `64` | Saturday |
| `62` | WorkDays (Monday through Friday) |
| `65` | WeekendDays (Saturday and Sunday) |
| `127` | EveryDay |

`WeekDays` is a flags enum. Combine values with bitwise OR in C# when building recurrence data in
code. In XML, the combined numeric value is stored in the `WeekDays` attribute.

| `WeekOfMonth` value | Meaning |
|---|---|
| `0` | None |
| `1` | First |
| `2` | Second |
| `3` | Third |
| `4` | Fourth |
| `5` | Last |

When `WeekOfMonth = "0"`, the week position does not affect the rule and `WeekDays` is ignored
for monthly and yearly day-number rules. In those cases, use `DayNumber` instead.

| Property | Constraint |
|---|---|
| `DayNumber` | Valid values are `1` through `31`. Lower values are normalized to `1`; higher values are normalized to `31`. |
| `Month` | Valid values are `1` through `12`. Lower values are normalized to `1`; higher values are normalized to `12`. |

If a project works with recurrence objects instead of raw XML strings, use the documented XML
conversion methods on `ISchedulerRecurrenceInfo`:

| Method | Use |
|---|---|
| `FromXml(string)` | Reconstruct recurrence information from an XML rule string |
| `ToXml()` | Convert recurrence information to an XML rule string |
| `Reset(SchedulerRecurrenceType)` | Reset recurrence fields for a specific recurrence type |
| `Assign(...)` | Copy recurrence settings from another recurrence object |

If a prompt mentions time zones for recurring appointments, map the appointment time zone field
with `DxSchedulerAppointmentMappings.TimeZoneId`. Recurrence time zone information is obtained
from the appointment item and is used to calculate recurring series start and end times.

For prompt interpretation, use the following rules:

| Prompt Intent | Recommended Output |
|---|---|
| "every work day" | Weekly rule with `WeekDays="62"` |
| "every day" | Daily rule or `WeekDays="127"` only when the project specifically models recurrence that way |
| "first Monday of each month" | Monthly rule with `Type="2" WeekOfMonth="1" WeekDays="2"` |
| "last Monday of April every year" | Yearly rule with `Type="3" Month="4" WeekOfMonth="5" WeekDays="2"` |
| "skip this occurrence" | Create or preserve a deleted-occurrence exception with an `Id`/`Index` rule |
| "edit only this occurrence" | Create or preserve a changed-occurrence exception with an `Id`/`Index` rule |

Do not generate changed-occurrence or deleted-occurrence records unless the prompt explicitly
targets a single occurrence or the surrounding code already manages recurrence exceptions.

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| No appointments shown | `AppointmentMappings` fields not matching model | Use `nameof()` for all mapping properties |
| Appointments show wrong time | Time zone mismatch | Ensure `StartDate`/`EndDate` are stored in local or UTC consistently |
| Scheduler does not respond to clicks | Static render mode | Add `@rendermode InteractiveServer` to the page |
| Recurring appointments broken | `RecurrenceInfo` mapping missing | Set `RecurrenceInfo = nameof(AppointmentData.Recurrence)` in mappings |
| `MissingMethodException: Constructor on type 'Int32Converter' not found` (WASM) | Blazor linker removes required types during WebAssembly compilation | Set `false` in the project file, or add a `LinkerConfig.xml` to preserve required types |
| `"Unhandled exception on the current circuit"` with no detail | `CircuitOptions.DetailedErrors` not set | Add `builder.Services.Configure(o => o.DetailedErrors = true);` in `Program.cs` (development only) |
| `"Component parameter 'ValueChanged' is used two or more times"` compile error | `@bind-Value` and `ValueChanged` used together | Use `@bind-Value="@val"` for two-way binding, or `Value="@val" ValueChanged="@handler"` — never both simultaneously |
| `dx-blazor.js` not found (404) behind a reverse proxy | Reverse proxy strips the app base path | Add `app.UsePathBase("/subpath")` before `app.MapBlazorHub()`, or set `` in `App.razor` |
| Static assets return 404 (`dx-blazor.css`, `dx-blazor.js`) | `UseStaticWebAssets()` not called | Add `app.UseStaticWebAssets();` in `Program.cs` before `app.UseStaticFiles()` |
| `"Could not find 'X' in 'window.DxBlazor'"` JavaScript error | Stale browser-cached JS from an older DevExpress version | Hard-refresh the browser (Ctrl+Shift+R), clear site data, or verify all DevExpress NuGet packages are the same version |
| `"Cannot pass the parameter 'X' to component 'Y' with rendermode"` | Non-serializable parameter passed across a render mode boundary | Move the component to a child `.razor` file with its own `@rendermode` directive; pass only serializable parameters |

## Constraints & Rules

0. **Never invent API**: If a property, method, event, or feature is not documented in this skill or its references, do **not** assume it exists. W

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [DevExpress](https://github.com/DevExpress)
- **Source:** [DevExpress/agent-skills](https://github.com/DevExpress/agent-skills)
- **License:** MIT
- **Homepage:** https://www.devexpress.com

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-devexpress-agent-skills-devexpress-blazor-scheduler
- Seller: https://agentstack.voostack.com/s/devexpress
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
