Add the possibility to have multiple time intervals on the DayView's display range.
Filtering should not show the appointments which have their resources not visible.
Please refer to the attached sample project and screenshot. Note that if RadScheduler is not grouped by resources, the scrollbar works as expected.
Please refer to the attached sample project. When you toggle the button the Visible property for the first resource is inverted. However, it doesn't take effect in RadScheduler and the resource is always visible. Workaround: Currently, if you want to hide some of the resources, you should remove them from the Resources collection of RadScheduler. When you want to use them again, you should just add them to the same collection.
To reproduce: Use the following code snippet: DateTime dt = DateTime.Now; this.radScheduler1.Appointments.Add(new Appointment(dt, TimeSpan.FromHours(4),"A1")); this.radScheduler1.Appointments.Add(new Appointment(dt, TimeSpan.FromHours(4),"A2")); By default, when two appointments start at the same time, on the left side it is displayed the shorter appointment. Hence, if you start resizing an appointment it may jump to another location leaving the mouse in a wrong and inconsistent position. The attached gif illustartes the behavior. Workaround: public RadForm1() { InitializeComponent(); this.radScheduler1.ElementProvider = new MyElementProvider(this.radScheduler1); DateTime dt = DateTime.Now; this.radScheduler1.Appointments.Add(new Appointment(dt, TimeSpan.FromHours(4),"A1")); this.radScheduler1.Appointments.Add(new Appointment(dt, TimeSpan.FromHours(4),"A2")); } private class AppointmentDateInfo : IComparable { public AppointmentElement appointment; public DateTime date; public bool isEnd; private DateTimeComparer comparer; public AppointmentDateInfo(AppointmentElement appointment, DateTime date, bool isEnd) { this.comparer = new DateTimeComparer(appointment.Scheduler); this.appointment = appointment; this.date = date; this.isEnd = isEnd; } public int CompareTo(object obj) { AppointmentDateInfo other = obj as AppointmentDateInfo; if (other == null) { return 1; } int res = date.CompareTo(other.date); if (res == 0) { if (other.appointment != this.appointment) { res = other.isEnd.CompareTo(isEnd); } else { res = this.isEnd.CompareTo(other.isEnd); } } if (appointment.Start.Equals(other.appointment.Start)) { return res != 0 ? res : appointment.AppointmentSubject.CompareTo(other.appointment.AppointmentSubject); } return res != 0 ? res : comparer.Compare(appointment, other.appointment); } } public class MyElementProvider : SchedulerElementProvider { public MyElementProvider(RadScheduler scheduler) : base(scheduler) { } protected override T CreateElement<T>(SchedulerView view, object context) { if (typeof(T) == typeof(DayViewAppointmentsTable)) { return new CustomDayViewAppointmentsTable(this.Scheduler, view, (DayViewAppointmentsArea)context)as T; } return base.CreateElement<T>(view, context); } } public class CustomDayViewAppointmentsTable : DayViewAppointmentsTable { public CustomDayViewAppointmentsTable(RadScheduler scheduler, SchedulerView view, DayViewAppointmentsArea area) : base(scheduler, view, area) { } private int FindLaneSpan(AppointmentElement appointment, Dictionary<AppointmentElement, int> appointmentLanes, int maxLanes) { int lane = appointmentLanes[appointment]; int span = maxLanes - lane; int cellsPerHour = this.GetDayViewBase().GetNumberOfCellsPerHour(); int minutesPerSlot = 60 / cellsPerHour; DateTime roundedAppStart = this.GetRulerRoundedDateTime(appointment.Start, false); DateTime roundedAppEnd = this.GetRulerRoundedDateTime(appointment.End, true); if (appointment.Start == appointment.End) { roundedAppEnd = roundedAppEnd.AddMinutes(minutesPerSlot); } foreach (KeyValuePair<AppointmentElement, int> item in appointmentLanes) { if (appointment == item.Key) { continue; } DateTime roundedItemStart = this.GetRulerRoundedDateTime(item.Key.Start, false); DateTime roundedItemEnd = this.GetRulerRoundedDateTime(item.Key.End, true); if (item.Key.Start == item.Key.End) { roundedItemEnd = roundedItemEnd.AddMinutes(minutesPerSlot); } if (roundedItemStart < roundedAppEnd && roundedItemEnd > roundedAppStart && item.Value > lane) { span = Math.Min(span, item.Value - lane); } } return span; } private int FindFreeLane(List<AppointmentElement> overlappingAppointments, Dictionary<AppointmentElement, int> appointmentLanes) { List<int> indexes = new List<int>(); for (int i = 0; i < overlappingAppointments.Count; i++) { indexes.Add(appointmentLanes[overlappingAppointments[i]]); } indexes.Sort(); for (int i = 0; i < indexes.Count; i++) { if (i < indexes[i]) { return i; } } return overlappingAppointments.Count; } protected override void ArrangeAppointments(SizeF finalSize) { RectangleF containerRect = new RectangleF(PointF.Empty, finalSize); List<AppointmentElement> appointmentsInLayout = new List<AppointmentElement>(); foreach (AppointmentElement element in this.AppointmentElements) { if (element.Visibility != ElementVisibility.Collapsed) { appointmentsInLayout.Add(element); } } appointmentsInLayout.Sort(new DateTimeComparer(this.Scheduler)); Dictionary<AppointmentElement, object> arrangedAppointments = new Dictionary<AppointmentElement, object>(); foreach (AppointmentElement appointmentElement in appointmentsInLayout) { if (arrangedAppointments.ContainsKey(appointmentElement)) { continue; } appointmentElement.RelatedAppointments.Sort(new DateTimeComparer(this.Scheduler)); List<AppointmentDateInfo> appointmentDates = new List<AppointmentDateInfo>(); List<AppointmentElement> overlappingAppointments = new List<AppointmentElement>(); Dictionary<AppointmentElement, int> appointmentLanes = new Dictionary<AppointmentElement, int>(); foreach (AppointmentElement relatedAppointment in appointmentElement.RelatedAppointments) { if (relatedAppointment.Visibility == ElementVisibility.Collapsed) { continue; } DateTime appStart = relatedAppointment.Start <= relatedAppointment.End ? relatedAppointment.Start : relatedAppointment.End; DateTime appEnd = relatedAppointment.Start <= relatedAppointment.End ? relatedAppointment.End : relatedAppointment.Start; if (!this.Scheduler.EnableExactTimeRendering) { if (appStart != appEnd) { appointmentDates.Add(new AppointmentDateInfo(relatedAppointment, this.GetRulerRoundedDateTime(appStart, false), false)); appointmentDates.Add(new AppointmentDateInfo(relatedAppointment, this.GetRulerRoundedDateTime(appEnd, true), true)); } else { int cellsPerHour = this.GetDayViewBase().GetNumberOfCellsPerHour(); int minutesPerSlot = 60 / cellsPerHour; appointmentDates.Add(new AppointmentDateInfo(relatedAppointment, this.GetRulerRoundedDateTime(appStart, false), false)); appointmentDates.Add(new AppointmentDateInfo(relatedAppointment, this.GetRulerRoundedDateTime(appEnd, true).AddMinutes(minutesPerSlot), true)); } } else { appointmentDates.Add(new AppointmentDateInfo(relatedAppointment, appStart, false)); appointmentDates.Add(new AppointmentDateInfo(relatedAppointment, appEnd, true)); } } appointmentDates.Sort(); int maxLanesCount = 0; for (int i = 0; i < appointmentDates.Count; i++) { if (!appointmentDates[i].isEnd) { int freeLane = FindFreeLane(overlappingAppointments, appointmentLanes); appointmentLanes.Add(appointmentDates[i].appointment, freeLane); overlappingAppointments.Add(appointmentDates[i].appointment); maxLanesCount = Math.Max(maxLanesCount, freeLane + 1); } else { overlappingAppointments.Remove(appointmentDates[i].appointment); } if (overlappingAppointments.Count == 0) { foreach (KeyValuePair<AppointmentElement, int> item in appointmentLanes) { AppointmentElement appointment = item.Key; int lane = item.Value; DateTime rulerRoundStart = this.GetRulerRoundedDateTime(appointment.Start, false); DateTime rulerRoundEnd = this.GetRulerRoundedDateTime(appointment.End, true); if (appointment.Start == appointment.End) { int cellsPerHour = this.GetDayViewBase().GetNumberOfCellsPerHour(); int minutesPerSlot = 60 / cellsPerHour; rulerRoundEnd = rulerRoundEnd.AddMinutes(minutesPerSlot); } PointF location = GetItemLocationInTable(appointment.Start, finalSize); float dayWidth = this.Area.DayViewElement.GetColumnWidth(this.Area.DayViewElement.GetColumnForDate(rulerRoundStart), finalSize.Width); int laneSpan = FindLaneSpan(appointment, appointmentLanes, maxLanesCount); SizeF size = new SizeF(dayWidth / maxLanesCount * laneSpan, this.GetItemHeight(appointment.Start, appointment.End)); location.X += dayWidth / maxLanesCount * lane + this.Area.DayViewElement.AppointmentMargin.Left; location.Y += this.Area.DayViewElement.AppointmentMargin.Top; size.Width -= this.Area.DayViewElement.AppointmentMargin.Horizontal; appointment.DesiredBounds = this.OnAppointmentLayout(appointment, new RectangleF(location, size), finalSize); if (!arrangedAppointments.ContainsKey(appointment)) { arrangedAppointments.Add(appointment, null); } } appointmentLanes.Clear(); maxLanesCount = 0; } } for (int i = 0; i < appointmentsInLayout.Count; i++) { AppointmentElement appointment = appointmentsInLayout[i]; if (appointment.Visibility != ElementVisibility.Visible) continue; RectangleF rectangle = appointment.DesiredBounds; if (this.RightToLeft) { rectangle = LayoutUtils.RTLTranslateNonRelative(rectangle, containerRect); } appointment.Arrange(rectangle); } } } }
To reproduce: please refer to the attached sample project and run it. Try to edit the existing appointment by using the inline editor. As a result, the AppointmentAdded event will be fired. You will notice that the Appointments collection contains more appointments than the existing ones. Note that if you use the edit dialog, this event is not fired and the behavior is as expected. Workaround: RadScheduler1.SchedulerElement.EditorManager.EditorViewMode = SchedulerEditorViewMode.EditorDialog
Currently the range starts from the start date of the first appointment an ends with the end date of the last appointment within the range. One should be able to show that there are no appointments within the specified range (start from the DateStartRange).
To reproduce: - Bind the scheduler using SchedulerBindingDataSource and group by resources. - At runtime change the data source of the SchedulerBindingDataSource. - A System.ArgumentException is thrown.
To reproduce: please refer to the attached sample project. Edit some appointment by changing its name or time slot. In the AppointmentChanged event the changes are stored to database. However, if you restart the application you will notice that the changes are not saved at all. Workaround: call the IEditableObject.EndEdit method for the affected record before saving the changes to the database. private void RadScheduler1_AppointmentChanged(object sender, AppointmentChangedEventArgs e) { IEditableObject editableObject = e.Appointment.DataItem as IEditableObject; if (editableObject!=null) { editableObject.EndEdit(); } SaveChanges(); }
How to reproduce: public partial class Form1 : Form { public Form1() { InitializeComponent(); this.radScheduler1.AppointmentAdded += radScheduler1_AppointmentAdded; Appointment appointment = new Appointment(DateTime.Now, TimeSpan.FromMinutes(60), "Summary", "Description"); appointment.StatusId = 2; appointment.BackgroundId = 6; this.radScheduler1.Appointments.Add(appointment); } private void radScheduler1_AppointmentAdded(object sender, AppointmentAddedEventArgs e) { Console.WriteLine("AppointmentAdded"); } } Workaround: public Form1() { InitializeComponent(); this.radScheduler1.Appointments.CollectionChanged += Appointments_CollectionChanged; Appointment appointment = new Appointment(DateTime.Now, TimeSpan.FromMinutes(60), "Summary", "Description"); appointment.StatusId = 2; appointment.BackgroundId = 6; this.radScheduler1.Appointments.Add(appointment); } private void Appointments_CollectionChanged(object sender, Telerik.WinControls.Data.NotifyCollectionChangedEventArgs e) { if (e.Action == Telerik.WinControls.Data.NotifyCollectionChangedAction.Add) { Console.WriteLine("AppointmentAdded"); } }
To reproduce: Image img1; Image img2; public RadForm1() { InitializeComponent(); new Telerik.WinControls.RadControlSpy.RadControlSpyForm().Show(); img1 = Image.FromFile(@"..\..\delete.png"); img2 = Image.FromFile(@"..\..\111.png"); Color[] colors = new Color[]{Color.LightBlue, Color.LightGreen, Color.LightYellow, .Red, Color.Orange, Color.Pink, Color.Purple, Color.Peru, Color.PowderBlue}; string[] names = new string[]{"Alan Smith", "Anne Dodsworth", n Mastoni", "Richard Duncan", "Maria Shnaider"}; for (int i = 0; i < names.Length; i++) { Resource resource = new Resource(); resource.Id = new EventId(i); resource.Name = names[i]; resource.Color = colors[i]; resource.Image = img2; this.radScheduler1.Resources.Add(resource); } this.radScheduler1.ActiveView.ResourcesPerView = 2; this.radScheduler1.GroupType = GroupType.Resource; SchedulerDayViewGroupedByResourceElement dayView = this.radScheduler1.SchedulerElement.ViewElement as SchedulerDayViewGroupedByResourceElement; dayView.ResourceHeaderHeight = 120; radScheduler1.AppointmentFormatting += RadScheduler1_AppointmentFormatting; radScheduler1.Appointments.Add(new Appointment(DateTime.Now.AddHours(-7), DateTime.Now.AddHours(-5), "Summary", "Description") { ResourceId = radScheduler1.Resources[0].Id }); } private void RadScheduler1_AppointmentFormatting(object sender, SchedulerAppointmentEventArgs e) { e.AppointmentElement.Image = img1 } - Drag the appointment to the top if needed. - Scroll down. Workaround: private void RadScheduler1_AppointmentFormatting(object sender, SchedulerAppointmentEventArgs e) { if (e.AppointmentElement.Children.Count ==0) { LightVisualElement el = new LightVisualElement(); el.DrawImage = true; el.Image = img1; e.AppointmentElement.Children.Add(el); } }
Please refer to the attached sample project and gif file. Workaround: this.radScheduler1.ElementProvider = new CustomSchedulerElementProvider(this.radScheduler1); public class CustomSchedulerElementProvider : SchedulerElementProvider { public CustomSchedulerElementProvider(RadScheduler scheduler) : base(scheduler) { } protected override T CreateElement<T>(SchedulerView view, object context) { if (typeof(T) == typeof(TimelineGroupingByResourcesElement)) { return new CustomTimelineGroupingByResourcesElement(this.Scheduler,view)as T; } return base.CreateElement<T>(view, context); } } public class CustomTimelineGroupingByResourcesElement : TimelineGroupingByResourcesElement { public CustomTimelineGroupingByResourcesElement(RadScheduler scheduler, SchedulerView view) : base(scheduler, view) { } protected override SizeF ArrangeOverride(SizeF finalSize) { RectangleF contentRect = new RectangleF(PointF.Empty, finalSize); int vScrollOffset = this.View.AllowResourcesScrolling ? this.ResourceScrollBarThickness : 0; if (this.VScrollBar != null && this.VScrollBar.Maximum < this.VScrollBar.LargeChange) { vScrollOffset = 0; } IList<SchedulerTimelineViewElement> timelineElements = this.GetChildViewElements(); IList<LightVisualElement> viewSeparators = this.GetViewSeparators(); List<RectangleF> resourcesBounds = new List<RectangleF>(); List<RectangleF> separatorsBounds = new List<RectangleF>(); int scrollBarOffset = 0; if (timelineElements.Count > 0) { if (timelineElements[timelineElements.Count - 1].NavigationElement.Visibility == ElementVisibility.Visible) { scrollBarOffset = 17; } } int headerHeight = 0; if (timelineElements.Count > 0 && timelineElements[0].Header.Visibility != ElementVisibility.Collapsed) { headerHeight = timelineElements[0].ViewHeaderHeight + timelineElements[0].ColumnHeaderHeight; } FieldInfo fi = typeof(TimelineGroupingByResourcesElement).GetField("leftCell", BindingFlags.Instance | BindingFlags.NonPublic); SchedulerCellElement leftCell = fi.GetValue(this) as SchedulerCellElement; FieldInfo fi2 = typeof(TimelineGroupingByResourcesElement).GetField("bottomCell", BindingFlags.Instance | BindingFlags.NonPublic); SchedulerCellElement bottomCell = fi2.GetValue(this) as SchedulerCellElement; if (leftCell != null) { RectangleF arrangeRectangle = new RectangleF(0, 0, ResourceHeaderWidth, headerHeight); if (this.RightToLeft) { arrangeRectangle = LayoutUtils.RTLTranslateNonRelative(arrangeRectangle, contentRect); } leftCell.Arrange(arrangeRectangle); } if (bottomCell != null) { RectangleF arrangeRectangle = new RectangleF(0, finalSize.Height - scrollBarOffset, ResourceHeaderWidth, scrollBarOffset); if (this.RightToLeft) { arrangeRectangle = LayoutUtils.RTLTranslateNonRelative(arrangeRectangle, contentRect); } bottomCell.Arrange(arrangeRectangle); } float separatorsWidth = this.View.GroupSeparatorWidth * (this.View.ResourcesPerView - 1); float resourcesHeight = finalSize.Height - separatorsWidth - headerHeight ; float y = 0; for (int i = 0; i < timelineElements.Count; i++) { SchedulerTimelineViewElement timelineElement = timelineElements[i]; LightVisualElement separator = i < viewSeparators.Count ? viewSeparators[i] : null; if (timelineElement != null) { float calculatedHeight = this.GetResourceSize(i, resourcesHeight); RectangleF arrangeRect = new RectangleF(this.ResourceHeaderWidth, y, finalSize.Width - this.ResourceHeaderWidth - vScrollOffset, calculatedHeight); if (i == 0) { arrangeRect.Height += headerHeight; } else if (i == timelineElements.Count - 1) { arrangeRect.Height = finalSize.Height - arrangeRect.Top - 1; } if (this.RightToLeft) { arrangeRect = LayoutUtils.RTLTranslateNonRelative(arrangeRect, contentRect); } timelineElement.Arrange(arrangeRect); y += arrangeRect.Height; if (i == 0) { arrangeRect.Height -= headerHeight; } else { arrangeRect.Y -= headerHeight; } resourcesBounds.Add(arrangeRect); } if (separator != null) { float calculatedHeight = this.View.GroupSeparatorWidth; RectangleF arrangeRect = new RectangleF(this.ResourceHeaderWidth, y, finalSize.Width - this.ResourceHeaderWidth - vScrollOffset, calculatedHeight); if (this.RightToLeft) { arrangeRect = LayoutUtils.RTLTranslateNonRelative(arrangeRect, contentRect); } separator.Arrange(arrangeRect); arrangeRect.Y -= headerHeight; separatorsBounds.Add(arrangeRect); y += calculatedHeight; } } if (this.ResourcesHeader != null) { RectangleF arrangeRectangle = new RectangleF(0, headerHeight, this.ResourceHeaderWidth, finalSize.Height - scrollBarOffset - headerHeight); if (this.RightToLeft) { arrangeRectangle = LayoutUtils.RTLTranslateNonRelative(arrangeRectangle, contentRect); } this.ResourcesHeader.SetResourcesLayoutInfo(resourcesBounds, separatorsBounds); this.ResourcesHeader.Arrange(arrangeRectangle); } if (this.View.AllowResourcesScrolling) { RectangleF scrollbarRect = new RectangleF(finalSize.Width - vScrollOffset, 0, vScrollOffset, finalSize.Height - scrollBarOffset); if (this.RightToLeft) { scrollbarRect = LayoutUtils.RTLTranslateNonRelative(scrollbarRect, contentRect); } this.VScrollBar.Arrange(scrollbarRect); } else { this.VScrollBar.Arrange(RectangleF.Empty); } return finalSize; } }
To reproduce: Appointment a1 = new Appointment(DateTime.Today.AddHours(10).AddMinutes(30), TimeSpan.FromMinutes(30), "A1"); Appointment a2 = new Appointment(DateTime.Today.AddHours(11) , TimeSpan.FromMinutes(30), "A2"); Appointment a3 = new Appointment(DateTime.Today.AddHours(11).AddMinutes(30), TimeSpan.FromMinutes(30), "A3"); this.radScheduler1.Appointments.Add(a1); this.radScheduler1.Appointments.Add(a2); this.radScheduler1.Appointments.Add(a3); this.radScheduler1.ActiveViewType = SchedulerViewType.Timeline; SchedulerTimelineView timelineView = radScheduler1.GetTimelineView(); timelineView.ShowTimescale(Timescales.Minutes); timelineView.GetScaling().DisplayedCellsCount = 10; Please refer to the attached sample project which incorrect behavior when scrolling is illustrated in the attached gif file. Workaround: instead of specifying 30 minutes duration of an appointment, use 29 minutes and 59 seconds.
Workaround: create a derivative of the EditAppointmentDialog. Open the designer and adjust the form's height and button's position. Then replace the default dialog with the custom one: public RadForm1() { InitializeComponent(); this.radScheduler1.AppointmentEditDialogShowing += radScheduler1_AppointmentEditDialogShowing; } CustomEditAppointmentDialog dialog; private void radScheduler1_AppointmentEditDialogShowing(object sender, Telerik.WinControls.UI.AppointmentEditDialogShowingEventArgs e) { if (dialog==null) { dialog = new CustomEditAppointmentDialog(); } e.AppointmentEditDialog = dialog; }
To reproduce: Sub New() InitializeComponent() Dim colors() As Color = {Color.LightBlue, Color.LightGreen, Color.LightYellow, Color.Red, _ Color.Orange, Color.Pink, Color.Purple, Color.Peru, Color.PowderBlue} Dim names() As String = {"Alan Smith", "Anne Dodsworth", "Boyan Mastoni", "Richard Duncan", "Maria Shnaider"} For i As Integer = 0 To names.Length - 1 Dim resource As New Telerik.WinControls.UI.Resource() resource.Id = New EventId(i) resource.Name = names(i) resource.Color = colors(i) Me.RadScheduler1.Resources.Add(resource) Next i Me.RadScheduler1.GroupType = GroupType.Resource Me.RadScheduler1.ActiveView.ResourcesPerView = Me.RadScheduler1.Resources.Count Me.RadScheduler1.ActiveViewType = SchedulerViewType.Timeline Dim rand As New Random For index = 1 To 20 Dim a As New Appointment(DateTime.Now.AddDays(index), TimeSpan.FromHours(2), "A" & index) a.ResourceId = Me.RadScheduler1.Resources(rand.Next(0, Me.RadScheduler1.Resources.Count)).Id Me.RadScheduler1.Appointments.Add(a) Next Dim timelineView As SchedulerTimelineView = Me.RadScheduler1.GetTimelineView() Dim oneMinute As New OneMinuteTimescale() timelineView.SchedulerTimescales.Add(oneMinute) oneMinute.Visible = True End Sub Public Class OneMinuteTimescale Inherits MinutesTimescale Public Overrides ReadOnly Property Name As String Get Return "OneMinuteTimescale" End Get End Property Public Overrides ReadOnly Property ScalingFactor() As Integer Get Return 1 End Get End Property End Class Workaround: decrease the range: timelineView.RangeStartDate = DateTime.Today timelineView.RangeEndDate = timelineView.RangeStartDate.AddDays(1)
How to reproduce: Public Class Form1 Sub New() InitializeComponent() End Sub Protected Overrides Sub OnLoad(e As EventArgs) MyBase.OnLoad(e) Me.SetUpScheduler() For i As Integer = 0 To 0 Dim app As New Appointment(DateTime.Now.AddHours(1), TimeSpan.FromMinutes(60), "Summary" & i, "Description1") app.ResourceId = Me.RadScheduler1.Resources(i).Id Me.RadScheduler1.Appointments.Add(app) Dim app2 As New Appointment(DateTime.Now.AddHours(3), TimeSpan.FromMinutes(60), "Summary" & i, "Description2") app2.BackgroundId = 2 app2.ResourceId = Me.RadScheduler1.Resources(i).Id Me.RadScheduler1.Appointments.Add(app2) Dim recurringAppointment As New Appointment(DateTime.Now, TimeSpan.FromMinutes(60), "Recurring" & i, "Recurring Appointment") recurringAppointment.BackgroundId = 4 recurringAppointment.ResourceId = Me.RadScheduler1.Resources(i).Id recurringAppointment.RecurrenceRule = New DailyRecurrenceRule(DateTime.Now, 1, 10) Me.RadScheduler1.Appointments.Add(recurringAppointment) Next 'AddHandler Me.RadScheduler1.CellPrintElementFormatting, AddressOf RadScheduler1_CellPrintElementFormatting End Sub Private Sub SetUpScheduler() Dim colors As Color() = New Color() {Color.LightBlue, Color.LightGreen, Color.LightYellow, Color.Red, Color.Orange, Color.Pink, _ Color.Purple, Color.Peru, Color.PowderBlue} 'Dim names As String() = New String() {"Alan Smith", "Anne Dodsworth", "Boyan Mastoni", "Richard Duncan", "Maria Schneider"} Dim names As String() = New String() {"Rick Astley"} For i As Integer = 0 To names.Length - 1 Dim resource As New Resource() resource.Id = New EventId(i) resource.Name = names(i) resource.Color = colors(i) Me.RadScheduler1.Resources.Add(resource) Next Me.RadScheduler1.ActiveView.ResourcesPerView = 1 Me.RadScheduler1.GroupType = GroupType.Resource Me.RadSchedulerNavigator1.SchedulerNavigatorElement.TimeZonesElementLayout.Visibility = ElementVisibility.Collapsed Me.RadSchedulerNavigator1.ShowWeekendCheckBox.Visibility = ElementVisibility.Collapsed Me.RadSchedulerNavigator1.SchedulerNavigatorElement.MonthViewButton.Visibility = ElementVisibility.Collapsed Me.RadSchedulerNavigator1.SchedulerNavigatorElement.TimelineViewButtonVisible = False End Sub Private Sub RadButton1_Click(sender As Object, e As EventArgs) Handles RadButton1.Click Me.PrintScheduler(Me.RadScheduler1) End Sub Private Sub PrintScheduler(radScheduler As RadScheduler) Dim doc As RadPrintDocument = New RadPrintDocument doc.AssociatedObject = radScheduler Dim schedulerPrintStyle As Telerik.WinControls.UI.SchedulerPrintStyle = Nothing Select Case Me.RadScheduler1.ActiveViewType Case SchedulerViewType.Day schedulerPrintStyle = New SchedulerDailyPrintStyle() 'schedulerPrintStyle = New CustomRadSchedulerDailyPrintStyle() Case SchedulerViewType.Week, SchedulerViewType.WorkWeek schedulerPrintStyle = New SchedulerWeeklyCalendarPrintStyle() 'schedulerPrintStyle = New CustomSchedulerWeeklyCalendarPrintStyle() End Select schedulerPrintStyle.DateStartRange = radScheduler.ActiveView.StartDate schedulerPrintStyle.DateEndRange = radScheduler.ActiveView.EndDate schedulerPrintStyle.TimeStartRange = TimeSpan.FromMinutes(5) schedulerPrintStyle.TimeEndRange = TimeSpan.FromHours(23).Add(TimeSpan.FromMinutes(59)) schedulerPrintStyle.AppointmentFont = New Font("Consolas", 8.5) schedulerPrintStyle.GroupType = SchedulerPrintGroupType.Resource AddHandler schedulerPrintStyle.CellElementFormatting, AddressOf radSchedWork_PrintSchedulerCellElementFormatting radScheduler.PrintStyle = schedulerPrintStyle radScheduler.PrintPreview() End Sub Private Sub radSchedWork_PrintSchedulerCellElementFormatting(sender As Object, e As PrintSchedulerCellEventArgs) e.CellElement.BackColor = Color.White e.CellElement.DrawFill = False Dim cell As SchedulerPrintCellElement = TryCast(e.CellElement, SchedulerPrintCellElement) If cell IsNot Nothing Then Dim msg As String = "PrintSchedulerCellElementFormatting for Date {0}" Debug.Print(String.Format(msg, e.CellElement.Date)) 'If cell.DateFormat = "hh:mm" Then ' cell.DateFormat = "hh:mm tt" 'ElseIf cell.DateFormat = "dd MMM" Then ' cell.DateFormat = "dd ddd" 'Else e.CellElement.DrawFill = True If e.CellElement.[Date].Hour Mod 2 = 0 Then If e.CellElement.[Date].Day Mod 2 = 0 Then e.CellElement.BackColor = Color.LightSalmon Else e.CellElement.BackColor = Color.LightBlue End If Else e.CellElement.BackColor = Color.LightGreen End If 'End If End If End Sub Private Sub RadScheduler1_CellFormatting(sender As Object, e As SchedulerCellEventArgs) Handles RadScheduler1.CellFormatting 'reset all properties for cells that may be changed here e.CellElement.BackColor = Color.White e.CellElement.DrawFill = False If e.CellElement.[Date].Hour Mod 2 = 0 Then e.CellElement.DrawFill = True If e.CellElement.[Date].Day Mod 2 = 0 Then e.CellElement.BackColor = Color.LightSalmon Else e.CellElement.BackColor = Color.LightBlue End If Else e.CellElement.BackColor = Color.LightGreen End If End Sub End Class Workaround: Private Sub PrintScheduler(radScheduler As RadScheduler) Dim doc As RadPrintDocument = New RadPrintDocument doc.AssociatedObject = radScheduler Dim schedulerPrintStyle As Telerik.WinControls.UI.SchedulerPrintStyle = Nothing Select Case Me.RadScheduler1.ActiveViewType Case SchedulerViewType.Day 'schedulerPrintStyle = New SchedulerDailyPrintStyle() schedulerPrintStyle = New CustomRadSchedulerDailyPrintStyle() Case SchedulerViewType.Week, SchedulerViewType.WorkWeek 'schedulerPrintStyle = New SchedulerWeeklyCalendarPrintStyle() schedulerPrintStyle = New CustomSchedulerWeeklyCalendarPrintStyle() End Select schedulerPrintStyle.DateStartRange = radScheduler.ActiveView.StartDate schedulerPrintStyle.DateEndRange = radScheduler.ActiveView.EndDate schedulerPrintStyle.TimeStartRange = TimeSpan.FromMinutes(5) schedulerPrintStyle.TimeEndRange = TimeSpan.FromHours(23).Add(TimeSpan.FromMinutes(59)) schedulerPrintStyle.AppointmentFont = New Font("Consolas", 8.5) schedulerPrintStyle.GroupType = SchedulerPrintGroupType.Resource AddHandler schedulerPrintStyle.CellElementFormatting, AddressOf radSchedWork_PrintSchedulerCellElementFormatting radScheduler.PrintStyle = schedulerPrintStyle radScheduler.PrintPreview() End Sub Public Class CustomRadSchedulerDailyPrintStyle Inherits SchedulerDailyPrintStyle Private currentPage As Integer Public Overrides Sub DrawPage(graphics As Graphics, drawingArea As Rectangle, pageNumber As Integer) Me.currentPage = pageNumber MyBase.DrawPage(graphics, drawingArea, pageNumber) End Sub Protected Overrides Sub DrawCells(appArea As Rectangle, graphics As Graphics) Dim currentDate = Me.GetPageDate(Me.currentPage) Dim rowCount As Single = Math.Max(1, CInt(Math.Ceiling((TimeEndRange - TimeSpan.FromHours(TimeStartRange.Hours)).TotalHours))) Dim rowHeight As Single = CSng(appArea.Height) / rowCount For row As Integer = 0 To rowCount - 1 Dim headerCellRect As New RectangleF(appArea.X, appArea.Y + row * rowHeight, Me.HoursColumnWidth, rowHeight) Dim element As New SchedulerPrintCellElement() element.DrawBorder = True element.Font = Me.DateHeadingFont element.[Date] = currentDate.AddHours(CInt(TimeStartRange.Add(TimeSpan.FromHours(row)).TotalHours)) element.DateFormat = "hh:mm" element.TextAlignment = ContentAlignment.TopRight Me.DrawCell(element, graphics, headerCellRect) element.DrawText = False Dim numberOfSubRows As Integer = 1 If Me.Scheduler.ActiveViewType = SchedulerViewType.Day OrElse Me.Scheduler.ActiveViewType = SchedulerViewType.MultiDay OrElse Me.Scheduler.ActiveViewType = SchedulerViewType.Week OrElse Me.Scheduler.ActiveViewType = SchedulerViewType.WorkWeek Then numberOfSubRows = 60 / CInt(DirectCast(Me.Scheduler.ActiveView, SchedulerDayViewBase).RangeFactor) End If For i As Integer = 0 To numberOfSubRows - 1 Dim rect As New RectangleF(appArea.X + HoursColumnWidth, appArea.Y + row * rowHeight + rowHeight / numberOfSubRows * i, appArea.Width - HoursColumnWidth, rowHeight / numberOfSubRows) If i = numberOfSubRows - 1 Then rect.Height += (appArea.Y + (row + 1) * rowHeight) - (rect.Y + rect.Height) End If Me.DrawCell(element, graphics, rect) Next Next End Sub End Class Public Class CustomSchedulerWeeklyCalendarPrintStyle Inherits SchedulerWeeklyCalendarPrintStyle Protected Overrides Sub DrawCells(appArea As RectangleF, graphics As Graphics, pageNumber As Integer) Dim days As Integer = Me.GetNumberOfDays(pageNumber) Dim currentDate As DateTime = Me.GetPageDate(pageNumber) If Me.TwoPagesPerWeek AndAlso pageNumber Mod 2 = 0 Then 'page numbers are 1-based currentDate = currentDate.AddDays(Me.GetNumberOfDays(pageNumber - 1)) End If Dim rowCount As Single = Math.Max(1, CInt(Math.Ceiling((TimeEndRange - TimeSpan.FromHours(TimeStartRange.Hours)).TotalHours))) Dim rowHeight As Single = CSng(appArea.Height) / rowCount Dim columnWidth As Single = (appArea.Width - Me.HoursColumnWidth) / CSng(days) For row As Integer = 0 To rowCount - 1 Dim headerCellRect As New RectangleF(appArea.X, appArea.Y + row * rowHeight, Me.HoursColumnWidth, rowHeight) Dim element As New SchedulerPrintCellElement() element.DrawBorder = True element.Font = Me.DateHeadingFont element.[Date] = DateTime.Today.AddHours(CInt(TimeStartRange.Add(TimeSpan.FromHours(row)).TotalHours)) element.[Date] = currentDate.AddHours(CInt(TimeStartRange.Add(TimeSpan.FromHours(row)).TotalHours)) element.DateFormat = "hh:mm" element.TextAlignment = ContentAlignment.TopRight Me.DrawCell(element, graphics, headerCellRect) element.DrawText = False Dim numberOfSubRows As Integer = 60 / CInt(DirectCast(Me.Scheduler.ActiveView, SchedulerDayViewBase).RangeFactor) For i As Integer = 0 To numberOfSubRows - 1 Dim rect As New RectangleF(appArea.X + HoursColumnWidth, appArea.Y + row * rowHeight + rowHeight / numberOfSubRows * i, appArea.Width - HoursColumnWidth, rowHeight / numberOfSubRows) If i = numberOfSubRows - 1 Then rect.Height += (appArea.Y + (row + 1) * rowHeight) - (rect.Y + rect.Height) End If Me.DrawCell(element, graphics, rect) Next For j As Integer = 0 To days - 1 element = New SchedulerPrintCellElement() element.DrawBorder = True element.DrawText = False element.[Date] = currentDate.AddDays(j).AddHours(CInt(TimeStartRange.Add(TimeSpan.FromHours(row)).TotalHours)) Dim rect As New RectangleF(appArea.X + HoursColumnWidth + j * columnWidth, appArea.Y + row * rowHeight, columnWidth, rowHeight) Me.DrawCell(element, graphics, rect) Next Next End Sub End Class
To reproduce: public Form1() { InitializeComponent(); this.radScheduler1.ActiveViewType = SchedulerViewType.Day; RulerPrimitive ruler = (this.radScheduler1.SchedulerElement.ViewElement as SchedulerDayViewElement).DataAreaElement.Ruler; ruler.RangeFactor= ScaleRange.TenMinutes; } Workaround: this.radScheduler1.GetDayView().RangeFactor = ScaleRange.TenMinutes;
To reproduce: Private Sub RadForm1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim dayView As SchedulerDayView = Me.RadScheduler1.GetDayView() dayView.RangeFactor = ScaleRange.FiveMinutes Dim ruler As RulerPrimitive = TryCast(Me.RadScheduler1.SchedulerElement.ViewElement, _ SchedulerDayViewElement).DataAreaElement.Ruler ruler.FormatStrings = New RulerFormatStrings("hh", "mm", "hh", "mm") End Sub Add a RadScheduler to a form and use the code snippet above. Run the application and scroll to the current time to see the current time indicator. Leave the form opened so you can see it on the second monitor but focus on another application for 5 minutes. You will notice that the current time indicator won't be redrawn until you focus RadScheduler again, click on the view or perform scrolling. The expected behavior is that RadScheduler will move the current time indicator as time is ticking. Workaround: use a timer to refresh RadScheduler at a certain interval: Dim timer As New Timer timer.Interval = 1000 AddHandler timer.Tick, AddressOf TimerTick timer.Start() Private Sub TimerTick(sender As Object, e As EventArgs) Me.RadScheduler1.SchedulerElement.RefreshViewElement() End Sub
Workaround: private void radScheduler1_CellFormatting(object sender, Telerik.WinControls.UI.SchedulerCellEventArgs e) { if (e.CellElement is SchedulerHeaderCellElement && e.CellElement.Text == "Local") { e.CellElement.TextAlignment = ContentAlignment.BottomLeft; } }
The resulting behavior should be similar to having all day appointments in the control with the view having its ShowAllDayArea property set to false. Currently when printed the all day appointments are drawn in the all day area.