SchedulerControl.CustomDrawTimeCell Event
Allows you to manually paint time cells.
Namespace: DevExpress.XtraScheduler
Assembly: DevExpress.XtraScheduler.v24.2.dll
Declaration
Event Data
The CustomDrawTimeCell event's data class is CustomDrawObjectEventArgs. The following properties provide information specific to this event:
Property | Description |
---|---|
Bounds | Returns the bounding rectangle of the drawing area. |
Cache | Gets an object which specifies the storage for the pens, fonts and brushes. Use it for custom painting in Scheduler Reports. |
Graphics | Gets an object used for painting. |
Handled | Gets or sets whether an event was handled. If it was handled, the default actions are not required. |
ObjectInfo | Gets information on the painted element. |
The event data class exposes the following methods:
Method | Description |
---|---|
DrawDefault() | Renders the element using the default drawing mechanism. |
DrawHtml(HtmlTemplate, DxHtmlPainterContext, Action<DxHtmlPainterArgs>) | Paints the required HTML template inside an element that raised this event. The context parameter allows you to assign an object that transfers mouse events to template elements. |
DrawHtml(HtmlTemplate, Action<DxHtmlPainterArgs>) | Paints the required HTML template inside an element that raised this event. |
GetDisplayValue(String) | |
GetValue(String) |
Remarks
Handle the CustomDrawTimeCell
event to paint time cells manually. Use the e.Bounds event parameter to get the cell’s bounding rectangle.
Set the e.Handled parameter to true to handle the event and ignore default painting. You can also call the e.DrawDefault()
method to force default cell painting.
Note
It is recommended that you first draw the background of the cell, and then draw its contents.
Use the e.ObjectInfo parameter to get information on the cell currently being painted. To get the cell-specific characteristics, such as the time interval or whether the cell is selected, typecast the ObjectInfo object to the DevExpress.XtraScheduler.Drawing.SelectableIntervalViewInfo
class, which is the base class for time cells of all scheduler views.
To access more specific cell information, you may need to cast ObjectInfo to a corresponding SelectableIntervalViewInfo descendant (TimeCell, SchedulerViewCellBase, SelectionBarCell, etc.). Choose the target type depending on which Scheduler View is currently applied and what information you need to retrieve. To determine that, use Visual Studio debugging methods to check the type of an object returned by the ObjectInfo field.
Example 1
The code below paints Scheduler cells that belong to the “8 a.m. to 6 p.m.” interval with a custom hatch-styled brush. A regular solid brush applies the MediumVioletRed background color to selected cells that belong to the same interval.
private void schedulerControl2_CustomDrawTimeCell(object sender, CustomDrawObjectEventArgs e) {
SelectableIntervalViewInfo cell = e.ObjectInfo as SelectableIntervalViewInfo;
SchedulerControl scheduler = sender as SchedulerControl;
TimeSpan startWorkHours = new TimeSpan(8, 0, 0);
TimeSpan endWorkHours = new TimeSpan(18, 0, 0);
if(cell.Interval.Start.TimeOfDay >= startWorkHours && cell.Interval.End.TimeOfDay <= endWorkHours && cell.Interval.Start.Hour != 23) {
Rectangle rec = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);
using(var hatchBrush = new HatchBrush(HatchStyle.LightDownwardDiagonal, Color.LightYellow, Color.DodgerBlue))
e.Cache.FillRectangle(hatchBrush, rec);
if(cell.Selected) {
Rectangle recSelected = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height - 1);
e.Cache.FillRectangle(Brushes.MediumVioletRed, rec);
e.Handled = true;
}
e.Handled = true;
}
}
Example 2
The following sample code handles the SchedulerControl.CustomDrawAppointment event to manually paint appointments. The image below shows the result.
using DevExpress.XtraScheduler;
using DevExpress.XtraScheduler.Drawing;
using System.Drawing.Drawing2D;
private void schedulerControl1_CustomDrawAppointment(object sender, CustomDrawObjectEventArgs e) {
TimeLineAppointmentViewInfo tlvi = e.ObjectInfo as TimeLineAppointmentViewInfo;
// This code works only for the Timeline View.
if(tlvi != null) {
Rectangle r = e.Bounds;
r.Offset(3, 3);
string[] s = tlvi.Appointment.Subject.Split(' ');
for(int i = 0; i < s.Length; i++) {
using(var foreBrush = new SolidBrush(colorArray[i]))
e.Cache.DrawString(s[i], tlvi.Appearance.Font, foreBrush,
r, StringFormat.GenericDefault);
SizeF shift = e.Cache.CalcTextSize(s[i] + " ", tlvi.Appearance.Font);
r.X += (int)shift.Width;
}
e.Handled = true;
}
}
Example 3
The following example demonstrates how to hide grid lines in the Scheduler view. It handles the SchedulerControl.CustomDrawTimeCell
event. Cell rectangles are painted with the specified brushes, the borders are not painted.
public static void scheduler_CustomDrawTimeCell(object sender, DevExpress.XtraScheduler.CustomDrawObjectEventArgs e)
{
// Get the cell to draw.
SelectableIntervalViewInfo cell =
e.ObjectInfo as SelectableIntervalViewInfo;
if (cell != null) {
// Draw the cell.
Brush myBrush = (cell.Selected) ? SystemBrushes.Highlight : SystemBrushes.Window;
e.Cache.FillRectangle(myBrush, cell.Bounds);
}
e.Handled = true;
}
Example 4
In the sample below, three employees have different shift patterns:
- Employee 1: 4 on 4 off
- Employee 2: 5 on 2 off, Mondays and Tuesdays are days off
- Employee 3: 5 on 2 off, Fridays and Sundays are days off
Custom “ProcessResourceX” methods utilize the RecurrenceInfo objects to define shift patterns and determine whether the current cell belongs to a work day or a weekend.
The SchedulerControl.CustomDrawTimeCell
event is handled to apply a custom drawing to days off. Additionally, the SchedulerControl.AllowAppointmentCreate event prevents users from adding new appointments that belong to these crossed-off days.
using System;
using System.Drawing;
using System.Windows.Forms;
using DevExpress.XtraScheduler;
using DevExpress.XtraScheduler.Drawing;
using System.Drawing.Drawing2D;
namespace XtraSchedulerListDataBinding
{
public partial class Form1 : Form
{
private SchedulerDataStorage storage = new SchedulerDataStorage();
public Form1()
{
InitializeComponent();
schedulerControl1.Start = DateTime.Today;
schedulerControl1.TimelineView.GroupType = SchedulerGroupType.Resource;
schedulerControl1.ActiveViewType = SchedulerViewType.Timeline;
schedulerControl1.OptionsBehavior.SelectOnRightClick = true;
PopulateStorage();
schedulerControl1.CustomDrawTimeCell += SchedulerControl1_CustomDrawTimeCell;
schedulerControl1.OptionsCustomization.AllowAppointmentCreate = UsedAppointmentType.Custom;
schedulerControl1.AllowAppointmentCreate += SchedulerControl1_AllowAppointmentCreate;
schedulerControl1.DataStorage.AppointmentInserting += Storage_AppointmentInserting;
schedulerControl1.DataStorage.AppointmentChanging += Storage_AppointmentChanging;
}
private void Storage_AppointmentChanging(object sender, PersistentObjectCancelEventArgs e)
{
Appointment apt = (Appointment)e.Object;
e.Cancel = !IsAllowed((int)apt.ResourceId, new TimeInterval(apt.Start, apt.End));
}
private void Storage_AppointmentInserting(object sender, PersistentObjectCancelEventArgs e)
{
Appointment apt = (Appointment)e.Object;
e.Cancel = !IsAllowed((int)apt.ResourceId, new TimeInterval(apt.Start, apt.End));
}
private void SchedulerControl1_AllowAppointmentCreate(object sender, AppointmentOperationEventArgs e)
{
SchedulerControl scheduler = (SchedulerControl)sender;
e.Allow = IsAllowed((int)scheduler.TimelineView.SelectedResource.Id, scheduler.TimelineView.SelectedInterval);
}
private void SchedulerControl1_CustomDrawTimeCell(object sender, CustomDrawObjectEventArgs e)
{
SchedulerControl scheduler = (SchedulerControl)sender;
if(scheduler.ActiveViewType == SchedulerViewType.Timeline) {
SchedulerViewCellBase cell = (SchedulerViewCellBase)e.ObjectInfo;
if(cell.Resource.Id != EmptyResourceId.Id) {
e.Handled = true;
if(!IsAllowed((int)cell.Resource.Id, cell.Interval)) {
Rectangle rec = new Rectangle(cell.Bounds.X, cell.Bounds.Y, cell.Bounds.Width, cell.Bounds.Height);
using(var hatchBrush = new HatchBrush(HatchStyle.DiagonalCross, Color.DimGray, Color.Azure))
e.Cache.FillRectangle(hatchBrush, rec);
}
else e.DrawDefault();
}
}
}
private bool IsAllowed(int resourceId, TimeInterval interval)
{
switch (resourceId)
{
case 0:
return ProcessResource0(interval);
case 1:
return ProcessResource1(interval);
case 2:
return ProcessResource2(interval);
default:
return true;
}
}
private bool ProcessResource0(TimeInterval interval)
{
var recInfo = new RecurrenceInfo()
{
AllDay = true,
Start = DateTime.Today,
Duration = TimeSpan.FromDays(4),
Type = RecurrenceType.Daily,
Periodicity = TimeSpan.FromDays(4).Days * 2
};
return IsContained(interval, recInfo);
}
private bool ProcessResource1(TimeInterval interval)
{
var recInfo = new RecurrenceInfo()
{
AllDay = true,
Start = DateTime.Today,
Duration = TimeSpan.FromDays(1),
Type = RecurrenceType.Weekly,
WeekDays = WeekDays.Monday | WeekDays.Tuesday
};
return IsContained(interval, recInfo);
}
private bool ProcessResource2(TimeInterval interval)
{
var recInfo = new RecurrenceInfo()
{
AllDay = true,
Start = DateTime.Today,
Duration = TimeSpan.FromDays(1),
Type = RecurrenceType.Weekly,
WeekDays = WeekDays.Friday | WeekDays.Sunday
};
return IsContained(interval, recInfo);
}
private bool IsContained(TimeInterval interval, RecurrenceInfo recInfo)
{
AppointmentBaseCollection occs = CalcOccs(interval, recInfo);
foreach (var occ in occs)
{
if (!(interval.End <= occ.Start || occ.End <= interval.Start)) {
return false;
}
}
return true;
}
private AppointmentBaseCollection CalcOccs(TimeInterval interval, RecurrenceInfo recInfo)
{
var patt = storage.CreateAppointment(AppointmentType.Pattern);
patt.Start = recInfo.Start;
patt.Duration = recInfo.Duration;
patt.RecurrenceInfo.Assign(recInfo);
var calc = OccurrenceCalculator.CreateInstance(recInfo);
var occs = calc.CalcOccurrences(interval, patt);
return occs;
}
private void PopulateStorage()
{
for (int i = 0; i < 3; i++)
{
var res = schedulerStorage1.CreateResource(i);
res.Caption = String.Format("Employee {0}", i+1);
schedulerStorage1.Resources.Add(res);
}
}
}
}