Back to Devexpress

SchedulerControl.CustomDrawTimeCell Event

windowsforms-devexpress-dot-xtrascheduler-dot-schedulercontrol-057f5a2e.md

latest24.0 KB
Original Source

SchedulerControl.CustomDrawTimeCell Event

Allows you to manually paint time cells.

Namespace : DevExpress.XtraScheduler

Assembly : DevExpress.XtraScheduler.v25.2.dll

NuGet Package : DevExpress.Win.Scheduler

Declaration

csharp
public event CustomDrawObjectEventHandler CustomDrawTimeCell
vb
Public Event CustomDrawTimeCell As CustomDrawObjectEventHandler

Event Data

The CustomDrawTimeCell event's data class is CustomDrawObjectEventArgs. The following properties provide information specific to this event:

PropertyDescription
BoundsReturns the bounding rectangle of the drawing area.
CacheGets an object which specifies the storage for the pens, fonts and brushes. Use it for custom painting in Scheduler Reports.
GraphicsGets an object used for painting.
HandledGets or sets whether an event was handled. If it was handled, the default actions are not required.
ObjectInfoGets information on the painted element.

The event data class exposes the following methods:

MethodDescription
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.

csharp
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;
    }
}
vb
Private Sub schedulerControl2_CustomDrawTimeCell(ByVal sender As Object, ByVal e As CustomDrawObjectEventArgs)
    Dim cell As SelectableIntervalViewInfo = TryCast(e.ObjectInfo, SelectableIntervalViewInfo)
    Dim scheduler As SchedulerControl = TryCast(sender, SchedulerControl)
    Dim startWorkHours As New TimeSpan(8, 0, 0)
    Dim endWorkHours As New TimeSpan(18, 0, 0)

    If cell.Interval.Start.TimeOfDay >= startWorkHours AndAlso cell.Interval.End.TimeOfDay <= endWorkHours AndAlso cell.Interval.Start.Hour <> 23 Then
        Dim rec As New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height)
        Using hatchBrush = New HatchBrush(HatchStyle.LightDownwardDiagonal, Color.LightYellow, Color.DodgerBlue)
            e.Cache.FillRectangle(hatchBrush, rec)
        End Using
        If cell.Selected Then
            Dim recSelected As New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height - 1)
            e.Cache.FillRectangle(Brushes.MediumVioletRed, rec)
            e.Handled = True
        End If
        e.Handled = True
    End If
End Sub

Example 2

The following sample code handles the SchedulerControl.CustomDrawAppointment event to manually paint appointments. The image below shows the result.

View Example

csharp
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;
    }
}
vb
Imports DevExpress.XtraScheduler
Imports DevExpress.XtraScheduler.Drawing
Imports System.Drawing.Drawing2D
Private Sub schedulerControl1_CustomDrawAppointment(ByVal sender As Object, ByVal e As CustomDrawObjectEventArgs) Handles schedulerControl1.CustomDrawAppointment
    Dim tlvi As TimeLineAppointmentViewInfo = TryCast(e.ObjectInfo, TimeLineAppointmentViewInfo)
    ' This code works only for the Timeline View.
    If tlvi IsNot Nothing Then
        Dim r As Rectangle = e.Bounds
        r.Offset(3, 3)
        Dim s() As String = tlvi.Appointment.Subject.Split(" "c)

        For i As Integer = 0 To s.Length - 1
            Using foreBrush = New SolidBrush(colorArray(i))
                e.Cache.DrawString(s(i), tlvi.Appearance.Font, foreBrush, r, StringFormat.GenericDefault)
            End Using
            Dim shift As SizeF = e.Cache.CalcTextSize(s(i) & " ", tlvi.Appearance.Font)
            r.X += CInt(shift.Width)
        Next i
        e.Handled = True
    End If
End Sub

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.

csharp
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;
}
vb
Public Shared Sub scheduler_CustomDrawTimeCell(ByVal sender As Object, ByVal e As DevExpress.XtraScheduler.CustomDrawObjectEventArgs)
    ' Get the cell to draw.
    Dim cell As SelectableIntervalViewInfo = TryCast(e.ObjectInfo, SelectableIntervalViewInfo)
    If cell IsNot Nothing Then
        ' Draw the cell.
        Dim myBrush As Brush = If(cell.Selected, SystemBrushes.Highlight, SystemBrushes.Window)
        e.Cache.FillRectangle(myBrush, cell.Bounds)
    End If
    e.Handled = True
End Sub

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.

csharp
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);
            }
        }
    }
}
vb
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports DevExpress.XtraScheduler
Imports DevExpress.XtraScheduler.Drawing
Imports System.Drawing.Drawing2D

Namespace XtraSchedulerListDataBinding
    Partial Public Class Form1
        Inherits Form

        Private storage As New SchedulerDataStorage()
        Public Sub New()
            InitializeComponent()
            schedulerControl1.Start = Date.Today
            schedulerControl1.TimelineView.GroupType = SchedulerGroupType.Resource
            schedulerControl1.ActiveViewType = SchedulerViewType.Timeline
            schedulerControl1.OptionsBehavior.SelectOnRightClick = True

            PopulateStorage()

            AddHandler schedulerControl1.CustomDrawTimeCell, AddressOf SchedulerControl1_CustomDrawTimeCell
            schedulerControl1.OptionsCustomization.AllowAppointmentCreate = UsedAppointmentType.Custom
            AddHandler schedulerControl1.AllowAppointmentCreate, AddressOf SchedulerControl1_AllowAppointmentCreate
            AddHandler schedulerControl1.DataStorage.AppointmentInserting, AddressOf Storage_AppointmentInserting
            AddHandler schedulerControl1.DataStorage.AppointmentChanging, AddressOf Storage_AppointmentChanging
        End Sub

        Private Sub Storage_AppointmentChanging(ByVal sender As Object, ByVal e As PersistentObjectCancelEventArgs)
            Dim apt As Appointment = CType(e.Object, Appointment)
            e.Cancel = Not IsAllowed(CInt(Math.Truncate(apt.ResourceId)), New TimeInterval(apt.Start, apt.End))
        End Sub

        Private Sub Storage_AppointmentInserting(ByVal sender As Object, ByVal e As PersistentObjectCancelEventArgs)
            Dim apt As Appointment = CType(e.Object, Appointment)
            e.Cancel = Not IsAllowed(CInt(Math.Truncate(apt.ResourceId)), New TimeInterval(apt.Start, apt.End))
        End Sub

        Private Sub SchedulerControl1_AllowAppointmentCreate(ByVal sender As Object, ByVal e As AppointmentOperationEventArgs)
            Dim scheduler As SchedulerControl = DirectCast(sender, SchedulerControl)
            e.Allow = IsAllowed(CInt(Math.Truncate(scheduler.TimelineView.SelectedResource.Id)), scheduler.TimelineView.SelectedInterval)
        End Sub

        Private Sub SchedulerControl1_CustomDrawTimeCell(ByVal sender As Object, ByVal e As CustomDrawObjectEventArgs)
            Dim scheduler As SchedulerControl = CType(sender, SchedulerControl)
            If scheduler.ActiveViewType = SchedulerViewType.Timeline Then
                Dim cell As SchedulerViewCellBase = CType(e.ObjectInfo, SchedulerViewCellBase)
                If cell.Resource.Id <> EmptyResourceId.Id Then
                    e.Handled = True
                    If Not IsAllowed(CInt(Math.Truncate(cell.Resource.Id)), cell.Interval) Then
                        Dim rec As New Rectangle(cell.Bounds.X, cell.Bounds.Y, cell.Bounds.Width, cell.Bounds.Height)
                        Using hatchBrush = New HatchBrush(HatchStyle.DiagonalCross, Color.DimGray, Color.Azure)
                            e.Cache.FillRectangle(hatchBrush, rec)
                        End Using
                    Else
                        e.DrawDefault()
                    End If
                End If
            End If
        End Sub

        Private Function IsAllowed(ByVal resourceId As Integer, ByVal interval As TimeInterval) As Boolean
            Select Case resourceId
                Case 0
                    Return ProcessResource0(interval)
                Case 1
                    Return ProcessResource1(interval)
                Case 2
                    Return ProcessResource2(interval)
                Case Else
                    Return True
            End Select
        End Function

        Private Function ProcessResource0(ByVal interval As TimeInterval) As Boolean
            Dim recInfo = New RecurrenceInfo() With {.AllDay = True, .Start = Date.Today, .Duration = TimeSpan.FromDays(4), .Type = RecurrenceType.Daily, .Periodicity = TimeSpan.FromDays(4).Days * 2}

            Return IsContained(interval, recInfo)
        End Function

        Private Function ProcessResource1(ByVal interval As TimeInterval) As Boolean
            Dim recInfo = New RecurrenceInfo() With {.AllDay = True, .Start = Date.Today, .Duration = TimeSpan.FromDays(1), .Type = RecurrenceType.Weekly, .WeekDays = WeekDays.Monday Or WeekDays.Tuesday}

            Return IsContained(interval, recInfo)
        End Function

        Private Function ProcessResource2(ByVal interval As TimeInterval) As Boolean
            Dim recInfo = New RecurrenceInfo() With {.AllDay = True, .Start = Date.Today, .Duration = TimeSpan.FromDays(1), .Type = RecurrenceType.Weekly, .WeekDays = WeekDays.Friday Or WeekDays.Sunday}

            Return IsContained(interval, recInfo)
        End Function

        Private Function IsContained(ByVal interval As TimeInterval, ByVal recInfo As RecurrenceInfo) As Boolean
            Dim occs As AppointmentBaseCollection = CalcOccs(interval, recInfo)
            For Each occ In occs
                If Not(interval.End <= occ.Start OrElse occ.End <= interval.Start) Then
                    Return False
                End If
            Next occ

            Return True
        End Function

        Private Function CalcOccs(ByVal interval As TimeInterval, ByVal recInfo As RecurrenceInfo) As AppointmentBaseCollection
            Dim patt = storage.CreateAppointment(AppointmentType.Pattern)
            patt.Start = recInfo.Start
            patt.Duration = recInfo.Duration
            patt.RecurrenceInfo.Assign(recInfo)
            Dim calc = OccurrenceCalculator.CreateInstance(recInfo)
            Dim occs = calc.CalcOccurrences(interval, patt)
            Return occs
        End Function

        Private Sub PopulateStorage()
            For i As Integer = 0 To 2
                Dim res = schedulerStorage1.CreateResource(i)
                res.Caption = String.Format("Employee {0}", i+1)
                schedulerStorage1.Resources.Add(res)
            Next i
        End Sub
    End Class
End Namespace

See Also

Time Cells

SchedulerControl Class

SchedulerControl Members

DevExpress.XtraScheduler Namespace