Skip to main content

LgWorkScheduler

LgWorkScheduler<TItem> displays tasks and milestones on a horizontal timeline. It groups items by row, offers multiple timeline granularities, an agenda mode, drag-and-drop, resizing, linked milestones, and custom rendering areas.

<LgWorkScheduler TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
RowField="@(item => item.RowId)" />
  • Namespace: Lagoon.UI.Components
  • Inherits from: LgComponentBase
  • Interfaces: IFormTrackerComponent, IAsyncDisposable
  • NuGet package: Lagoon.UI
Mobile usage

This component is designed for a wide workspace and is not suitable for mobile screens.

Usage​

Demonstration​

Try this component in the Lagoon showcase. A variant oriented toward metric scale is available in the SchedulerVMeters showcase.

Data source​

TItem must implement IWorkSchedulerData. From sets the start, To sets the end, and IsVisible allows excluding an item from rendering. If To is null, the item is rendered as a milestone; otherwise it is rendered as a task.

WorkItem.cs
public class WorkItem : IWorkSchedulerData
{
// Identifies the visual row used by RowField.
public int RowId { get; set; }

// Task or milestone start date.
public DateTime? From { get; set; }

// End date; null transforms the item into a milestone.
public DateTime? To { get; set; }

// Allows filtering without removing the item from the collection.
public bool IsVisible { get; set; } = true;

// Business label displayed in custom fragments.
public string LabelKey { get; set; }

// First optional grouping level.
public string GroupKey { get; set; }

// Second optional grouping level.
public string SubGroupKey { get; set; }
}

Simple schedule​

Define Items, From, To, and RowField. Without custom fragments, tasks use ToString() and milestones use DefaultJalonCssClass.

WorkSchedulerPage.razor
<LgWorkScheduler TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
Timeline="TimelineMode.MonthDay"
RowField="@(item => item.RowId)" />
WorkSchedulerPage.razor.cs
public partial class WorkSchedulerPage : LgPage
{
// Start bound displayed by the schedule.
private DateTime _from = new(2025, 1, 1);

// End bound displayed by the schedule.
private DateTime _to = new(2025, 1, 31);

// Data displayed: one task and one milestone on two rows.
private List<WorkItem> _items = new()
{
new() { RowId = 1, From = new DateTime(2025, 1, 3), To = new DateTime(2025, 1, 8), LabelKey = "#WksTaskA" },
new() { RowId = 2, From = new DateTime(2025, 1, 10), To = null, LabelKey = "#WksMilestone" }
};
}

Customize rows and tasks​

ProjectItems customizes the left-side list. SchedulerItems customizes the bars and milestones in the schedule area.

WorkSchedulerCustomPage.razor
<LgWorkScheduler TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
RowField="@(item => item.RowId)">
<ProjectItems Context="item">
<LgLabel Text="@item.LabelKey" />
</ProjectItems>
<SchedulerItems Context="item">
<div class="w-100 h-100 text-center custom-work-item">
@item.LabelKey.Translate()
</div>
</SchedulerItems>
</LgWorkScheduler>

Milestones​

An item with To set to null is a milestone. By default, DefaultJalonCssClass is wk-milestone-square. The component also provides wk-milestone-arrow-up. You can define a custom class and use it in SchedulerItems.

WorkSchedulerMilestonePage.razor
<LgWorkScheduler TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
DefaultJalonCssClass="custom-milestone-circle"
RowField="@(item => item.RowId)" />
WorkSchedulerMilestonePage.scss
.custom-milestone-circle {
width: 20px;
height: 20px;
border-radius: 50%;
background: yellow;
border: 1px solid black;
}

Group rows​

GroupBy adds one or more grouping levels. ProjectItemsGroup and SchedulerItemsGroup customize the rendering of groups.

WorkSchedulerGroupPage.razor
<LgWorkScheduler TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
RowField="@(item => item.RowId)"
GroupBy="_groupBy"
DefaultGroupsState="GroupState.Open">
<ProjectItemsGroup Context="group">
<LgLabel Text="@group.Key?.ToString()" />
</ProjectItemsGroup>
</LgWorkScheduler>
WorkSchedulerGroupPage.razor.cs
public partial class WorkSchedulerGroupPage : LgPage
{
// Groups rows by business family, then by subfamily.
private List<Func<WorkItem, object>> _groupBy = new()
{
item => item.GroupKey,
item => item.SubGroupKey
};
}

Filter items​

The component does not provide a built-in filter like LgGridView. Filter your data by updating IsVisible.

WorkSchedulerFilterPage.razor
<LgTextBox @bind-Value="_filterText" Label="#WksFilter" OnChange="FilterItemsAsync" />

<LgWorkScheduler TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
RowField="@(item => item.RowId)" />
WorkSchedulerFilterPage.razor.cs
public partial class WorkSchedulerFilterPage : LgPage
{
// Text entered by the user to filter displayed rows.
private string _filterText;

// Applies the filter while keeping objects in the data source.
private Task FilterItemsAsync(ChangeEventArgs args)
{
string filter = args.Value?.ToString() ?? string.Empty;
foreach (WorkItem item in _items)
{
item.IsVisible = string.IsNullOrWhiteSpace(filter) || item.LabelKey.Contains(filter, StringComparison.OrdinalIgnoreCase);
}
return Task.CompletedTask;
}
}

Drag-and-drop and resizing​

Implement IWorkSchedulerDraggableData to enable horizontal movement, vertical movement, and per-item resizing. OnDragCompleted and OnResizeCompleted allow canceling the operation with Cancel.

DraggableWorkItem.cs
public class DraggableWorkItem : WorkItem, IWorkSchedulerDraggableData
{
// Allows movement within the current row.
public bool AllowHorizontalMove { get; set; }

// Allows movement to another row.
public bool AllowVerticalMove { get; set; }

// Allows task resizing.
public bool AllowResize { get; set; }
}

Implement IWorkSchedulerLinkableData to draw links between tasks. TaskId identifies the task and Next contains the identifiers of subsequent tasks.

LinkedWorkItem.cs
public class LinkedWorkItem : DraggableWorkItem, IWorkSchedulerLinkableData
{
// Unique identifier used by the link area.
public string TaskId { get; set; }

// Identifiers of tasks linked to this task.
public List<string> Next { get; set; } = new();
}

Agenda mode​

DisplayMode="DisplayMode.Agenda" replaces project rows with a vertical hourly grid. Configure AgendaRowStep, AgendaHoursFrom, AgendaHoursTo, and the highlight bounds.

WorkSchedulerAgendaPage.razor
<LgWorkScheduler TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
DisplayMode="DisplayMode.Agenda"
AgendaRowStep="30"
AgendaHoursFrom="TimeSpan.FromHours(8)"
AgendaHoursTo="TimeSpan.FromHours(18)"
RowField="@(item => item.RowId)" />

Control by reference​

Add a reference to control scrolling or convert positions, dates, and durations.

WorkSchedulerActionsPage.razor
<LgButton Text="#WksToday" OnClick="ScrollTodayAsync" />

<LgWorkScheduler @ref="_workScheduler"
TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
RowField="@(item => item.RowId)" />
WorkSchedulerActionsPage.razor.cs
public partial class WorkSchedulerActionsPage : LgPage
{
// Reference used to call the component's public methods.
private LgWorkScheduler<WorkItem> _workScheduler;

// Centers the schedule on today's date.
private Task ScrollTodayAsync()
{
return _workScheduler.ScrollToTodayAsync();
}
}

Useful public methods: ScrollToAsync(double), ScrollToAsync(DateTime), ScrollToTodayAsync(), ScrollToEnd(), ScrollToStart(), GetTaskPosition(TItem), GetDatePosition(DateTime), GetTaskWidth(TItem), GetDurationWidth(DateTime, DateTime), GetDurationWidth(double), GetDateFromLeftPosition(double), GetRowPosition(), ExportAsync(...).

Child component LgWorkSchedulerDraggableItem​

LgWorkSchedulerDraggableItem<TItem> declares an external item that the user can drop into an LgWorkScheduler<TItem>. WorkScheduler and Duration are required; Id is returned in OnDragCompletedEventArgs<TItem>.DroppedItemId.

WorkSchedulerExternalDragPage.razor
<LgWorkScheduler @ref="_workScheduler"
TItem="WorkItem"
Items="_items"
From="_from"
To="_to"
RowField="@(item => item.RowId)"
OnDragCompleted="DropExternalItemAsync" />

@if (_workScheduler is not null)
{
<LgWorkSchedulerDraggableItem TItem="WorkItem"
WorkScheduler="_workScheduler"
Id="external-task-1"
Duration="TimeSpan.FromDays(2)"
Text="@("#WksExternalTask".Translate())"
CssClass="external-task" />
}
WorkSchedulerExternalDragPage.razor.cs
public partial class WorkSchedulerExternalDragPage : LgPage
{
// Adds a new task when an external item is dropped in the schedule.
private Task DropExternalItemAsync(OnDragCompletedEventArgs<WorkItem> args)
{
if (args.IsNew)
{
_items.Add(new WorkItem { RowId = Convert.ToInt32(args.RowId), From = args.NewStart, To = args.NewEnd, LabelKey = "#WksExternalTask" });
}
return Task.CompletedTask;
}
}

Properties of LgWorkSchedulerDraggableItem​

NameTypeDefaultDeclared inDescription
IdstringnullLgWorkSchedulerDraggableItem<TItem>Identifier returned on drop in DroppedItemId.
DurationTimeSpan?nullLgWorkSchedulerDraggableItem<TItem>Duration of the external item; required.
TextstringnullLgWorkSchedulerDraggableItem<TItem>Text displayed in the droppable item.
CssClassstringnullLgWorkSchedulerDraggableItem<TItem>CSS class added to the external item.
WorkSchedulerLgWorkScheduler<TItem>nullLgWorkSchedulerDraggableItem<TItem>Instance of the target schedule; required.

Properties​

NameTypeDefaultDeclared inDescription
OnSortFunc<IEnumerable<TItem>, IEnumerable<TItem>>nullLgWorkScheduler<TItem>Sorts the source before rendering.
TimelineTimelineModeYearMonthLgWorkScheduler<TItem>Defines the horizontal granularity.
DisplayModeDisplayModeTimelineLgWorkScheduler<TItem>Defines the main rendering.
TimelineDisplayModeTimelineDisplayModeTwoRowsLgWorkScheduler<TItem>Defines the number of timeline rows.
GroupDisplayModeGroupDisplayModeRowLgWorkScheduler<TItem>Defines the rendering of groups.
FocusTodayOnLoadboolfalseLgWorkScheduler<TItem>Automatically centers the schedule on today when loaded.
AgendaRowStepint30LgWorkScheduler<TItem>Vertical step, in minutes, of agenda mode.
AgendaHoursFromTimeSpan00:00:00LgWorkScheduler<TItem>Start hour displayed in agenda mode.
AgendaHoursToTimeSpan00:00:00LgWorkScheduler<TItem>End hour displayed in agenda mode.
AgendaHoursFromHighlightTimeSpan00:00:00LgWorkScheduler<TItem>Start of the hour range highlighted in agenda mode.
AgendaHoursToHighlightTimeSpan00:00:00LgWorkScheduler<TItem>End of the hour range highlighted in agenda mode.
AllowCollapseGroupbooltrueLgWorkScheduler<TItem>Allows collapsing and expanding groups.
StateIdstringnullLgWorkScheduler<TItem>Unique identifier used notably to restore scroll position.
RestoreScrollPositionboolfalseLgWorkScheduler<TItem>Restores scroll position after a full reload if StateId is set.
TimelineHeightint50LgWorkScheduler<TItem>Timeline height in pixels.
ShowWeekendbooltrueLgWorkScheduler<TItem>Shows weekends in the timeline.
FromDateTime?nullLgWorkScheduler<TItem>Start bound displayed; if absent, it is deduced from the data.
ToDateTime?nullLgWorkScheduler<TItem>End bound displayed; if absent, it is deduced from the data.
ZoomLeveldouble4LgWorkScheduler<TItem>Number of pixels representing one hour.
ProjectListWidthint200LgWorkScheduler<TItem>Width of the project list in pixels.
RowHeightint50LgWorkScheduler<TItem>Height of a row in pixels.
PaddingRowint7LgWorkScheduler<TItem>Internal spacing of a row in pixels.
ItemsICollection<TItem>nullLgWorkScheduler<TItem>Data to display.
OnCustomDateIndicatorFunc<DateTime, string>nullLgWorkScheduler<TItem>Formats the date displayed during movement or resizing.
DragStepTypeDragStepTypeFreeLgWorkScheduler<TItem>Defines the movement constraint.
DragStepSizeTimeSpan?nullLgWorkScheduler<TItem>Custom step used if DragStepType is Manual.
ShowMouseIndicatorbooltrueLgWorkScheduler<TItem>Shows the mouse position indicator.
ShowDragIndicatorboolfalseLgWorkScheduler<TItem>Shows the indicator during movement or resizing.
VirtualScrollingboolfalseLgWorkScheduler<TItem>Enables virtual scrolling for large volumes.
ShowProjectResizingbooltrueLgWorkScheduler<TItem>Allows project list resizing.
RowFieldFunc<TItem, object>nullLgWorkScheduler<TItem>Selects the row grouping key.
GroupByIEnumerable<Func<TItem, object>>nullLgWorkScheduler<TItem>Defines grouping levels.
OrderByIEnumerable<Func<TItem, object>>nullLgWorkScheduler<TItem>Defines row sort properties.
GroupMarginint30LgWorkScheduler<TItem>Group indentation in pixels.
DefaultGroupsStateGroupStateCloseLgWorkScheduler<TItem>Initial state of groups.
DefaultJalonCssClassstring"wk-milestone-square"LgWorkScheduler<TItem>Default CSS class for milestones.
JoinMilestoneboolfalseLgWorkScheduler<TItem>Links milestones together on the same row.
HourStepint3LgWorkScheduler<TItem>Hour step of TimelineMode.DayHour.
DatesCustomHighlightDictionary<DateTime, string>nullLgWorkScheduler<TItem>Dates highlighted with a CSS class per date.
ProjectHeaderRenderFragmentnullLgWorkScheduler<TItem>Content of the project list header.
ProjectItemsRenderFragment<TItem>nullLgWorkScheduler<TItem>Rendering of a row in the project list.
ProjectItemsGroupRenderFragment<GroupItem<TItem>>nullLgWorkScheduler<TItem>Rendering of a group in the project list.
SchedulerItemsRenderFragment<TItem>nullLgWorkScheduler<TItem>Rendering of a task or milestone in the schedule area.
SchedulerItemsGroupRenderFragment<GroupItem<TItem>>nullLgWorkScheduler<TItem>Rendering of a group in the schedule area.
AgendaHoursRenderRenderFragment<TimeSpan>nullLgWorkScheduler<TItem>Rendering of an hour mark in agenda mode.
TimelineFirstLevelRenderFragment<DateTime>nullLgWorkScheduler<TItem>Rendering of the first timeline level.
TimelineSecondLevelRenderFragment<DateTime>nullLgWorkScheduler<TItem>Rendering of the second timeline level.
ChildContentRenderFragmentnullLgWorkScheduler<TItem>Child content; used only to declare named fragments.
IgnoreFormTrackingboolfalseIFormTrackerComponentExcludes the component from change tracking by an LgFormTracker.

Events​

NameTypeDescription
OnItemClickEventCallback<TItem>Triggered on a click on a task or milestone.
OnEmptyClickEventCallback<OnEmptyClickEventArgs>Triggered on a click in an empty area; exposes RowId and Date.
OnDragCompletedEventCallback<OnDragCompletedEventArgs<TItem>>Triggered at the end of a movement; exposes the item, target row, dates, and Cancel.
OnResizeCompletedEventCallback<OnResizeCompletedEventArgs<TItem>>Triggered at the end of a resize; exposes the new dates and Cancel.

Associated enumerations​

TimelineMode​

ValueDefaultDescription
YearMonthYesYear at first level, month at second.
MonthDayNoMonth at first level, days at second.
DayAmPmNoDay at first level, half-day at second.
DayHourNoDays at first level, hours at second.
MonthWeekNoMonth at first level, week numbers at second.
MonthWeekDayNoMonth, weeks, then days on three levels.
WeekDayNoWeek numbers at first level, days at second.

DisplayMode​

ValueDefaultDescription
TimelineYesDisplays bars and milestones with the project list.
AgendaNoDisplays an agenda grid with vertical hour axis.

TimelineDisplayMode​

ValueDefaultDescription
OneRowNoDisplays the timeline on one row.
TwoRowsYesDisplays the timeline on two rows.
ThreeRowsNoDisplays the timeline on three rows.

GroupDisplayMode​

ValueDefaultDescription
RowYesDisplays groups as rows.
ColumnNoDisplays groups as columns.

GroupState​

ValueDefaultDescription
OpenNoGroup open.
CloseYesGroup closed.

DragStepType​

ValueDefaultDescription
FreeYesNo step imposed during movement.
HourNoMovement constrained to the hour.
DayNoMovement constrained to the day.
ManualNoMovement constrained by DragStepSize.

Accessibility​

  • Provide explicit labels in ProjectItems and SchedulerItems, as custom rendering replaces the default content.
  • Actions in fragments must use Lagoon components (LgButton, LgIcon with appropriate role) and translated text.
  • Do not hide weekends if tasks can start or end on these days: this creates ambiguous temporal reading.
  • ShowMouseIndicator is a visual aid; do not use it as the only business indication.
  • LgWorkSchedulerDraggableItem<TItem>: external item droppable into a schedule.
  • LgFormTracker: tracks changes when IgnoreFormTracking is false.