Currently,
I’m using the Radscheduler MultiDayView to create a “two week” view in which
the end user has the possibility to choose if he wants to see weekend days or
not.
When this
view is used in combination with appointments spanning multiple days and the display
of the weekend days, every thing works fine (with_weekend.png). The appointment
starts at 06/21/19 05:00 and ends 06/24/19 21:05.
However, if
weekend days are not shown in this view (without_weekend.png), part of the same
appointment is shown on 06/25/19 and the end time on 06/24/19 is also incorrect.
How can I solve this? It is not an option to show it as an “All day appointment” since the customer wants to know the exact start and end time.
To reproduce: Me.RadScheduler1.ActiveViewType = Telerik.WinControls.UI.SchedulerViewType.Timeline Dim timelineView As SchedulerTimelineView = Me.RadScheduler1.GetTimelineView() Dim currentScaling As SchedulerTimescale = timelineView.GetScaling() currentScaling.DisplayedCellsCount = 100 Try to scroll horizontally. Then, change the currentScaling.DisplayedCellsCount property to 50 and try to scroll again. You will notice a considerable difference. Workaround: reduce the number of the displayed visual cell elements by the DisplayedCellsCount.
Hello,
We have developed an ASP.NET application and a WinForms application that both uses Telerik RadScheduler. The applications share the same data.
We have set EnableExactTimeRendering = true to prevent appointments to falsely be displayed as collisions.
Our problem is that appointments with short durations (0-4 minutes) are totally invisible in the WinForms Scheduler. In the ASP.NET scheduler all appointments are visible. An appointment with no duration (0 minutes) is shown as 30min appointment in ASP.NET while 1-minute appointments are shown as a thin line which is ok as we use tooltips for all appointments.
How can we make all appointments visible in WinForms and still use EnableExactTimeRendering? Of course, the rendering will not be exact for small durations but that is better than not showing the appointments at all. We would like to set a minimum size for appointments.
Best regards,
Daniel Gidlöf
To reproduce: 1.Change the first day of week to Monday: SchedulerMonthView view = new SchedulerMonthView(); CultureInfo ci = new CultureInfo("en-US"); ci.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Monday; view.CurrentCulture = ci; this.radScheduler1.ActiveView = view; 2. Create an appointment with a recurrence rule illustrated in the attached screenshot. Imagine that today is Wednesday and the recurrence rule starts on Monday from the same week. As a result, you will notice that the WeeklyRecurrenceRule.FirstDayOfWeek is not set and the appointment occurs on the wrong Sundays. Refer to the attached screenshot. Workaround: private void radScheduler1_AppointmentAdded(object sender, AppointmentAddedEventArgs e) { if (e.Appointment.RecurrenceRule != null) { WeeklyRecurrenceRule r = e.Appointment.RecurrenceRule as WeeklyRecurrenceRule; r.FirstDayOfWeek = DayOfWeek.Monday; } }
How to reproduce: check the attached (video radscheduler-selection-incorrect.gif) public RadForm1() { InitializeComponent(); Appointment appointment = new Appointment(DateTime.Today.AddHours(13), TimeSpan.FromHours(1), "Test Appointment"); this.radScheduler1.Appointments.Add(appointment); for (int i = 0; i < 25; i++) { appointment = new Appointment(DateTime.Today.AddHours(24), TimeSpan.FromHours(1), "AllDay: " + i); appointment.AllDay = true; this.radScheduler1.Appointments.Add(appointment); } this.radScheduler1.AllowAppointmentsMultiSelect = true; } Workaround: create a custom input behavior this.radScheduler1.SchedulerInputBehavior = new CustomSchedulerInputBehavior(this.radScheduler1); public class CustomSchedulerInputBehavior : SchedulerInputBehavior { public CustomSchedulerInputBehavior(RadScheduler scheduler) : base(scheduler) { } public override bool HandleMouseWheel(MouseEventArgs args) { if (!this.Scheduler.AllowMouseWheelSupport) return false; bool scrolled = false; if (this.Scheduler.SelectionBehavior.IsAllDayAreaSelection || this.IsLastSelectedAppointmentAllDay(this.Scheduler.SelectionBehavior.SelectedAppointments)) { if (this.Scheduler.GroupType == GroupType.Resource) { SchedulerDayViewGroupedByResourceElement grouped = this.Scheduler.ViewElement as SchedulerDayViewGroupedByResourceElement; IList<SchedulerDayViewElement> childViews = grouped != null ? grouped.GetChildViewElements() : null; if (childViews != null && childViews.Count > 0) { RadScrollBarElement scroll = childViews[childViews.Count - 1].AllDayHeaderElement.ScrollBar; if (scroll.Visibility != ElementVisibility.Collapsed) { int newValue = scroll.Value - childViews[childViews.Count - 1].AllDayHeaderElement.HeaderHeight * Math.Sign(args.Delta); newValue = Math.Max(Math.Min(newValue, scroll.Maximum - scroll.LargeChange + 1), scroll.Minimum); scroll.Value = newValue; scrolled = true; } } } else { SchedulerDayViewElement dayView = this.Scheduler.ViewElement as SchedulerDayViewElement; RadScrollBarElement scroll = dayView != null ? dayView.AllDayHeaderElement.ScrollBar : null; if (scroll != null && scroll.Visibility != ElementVisibility.Collapsed) { int newValue = scroll.Value - dayView.AllDayHeaderElement.HeaderHeight * Math.Sign(args.Delta); newValue = Math.Max(Math.Min(newValue, scroll.Maximum - scroll.LargeChange + 1), scroll.Minimum); scroll.Value = newValue; scrolled = true; } } } if (scrolled) { return false; } if (args.Delta > 0) { this.Scheduler.ViewElement.Scroll(true); } else { this.Scheduler.ViewElement.Scroll(false); } return false; } private bool IsLastSelectedAppointmentAllDay(ReadOnlyCollection<IEvent> selectedAppointments) { if (selectedAppointments.Count > 0) { return selectedAppointments[selectedAppointments.Count - 1].AllDay; } return false; } }
Workaround: create a custom Appointment and override the PaintRecurrenceIcon method Public Class MyAppointmentElement Inherits AppointmentElement Public Sub New(scheduler As RadScheduler, view As SchedulerView, appointment As IEvent) MyBase.New(scheduler, view, appointment) End Sub Public Overrides Sub PaintRecurrenceIcon(graphics As IGraphics) If Not Me.Recurring Then Return End If Dim icon As Image = DirectCast(GetType(AppointmentElement).GetMethod("GetRecurrenceIcon", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(Me, Nothing), Image) If icon Is Nothing Then Return End If SyncLock icon Dim clientRect As RectangleF = Me.GetClientRectangle(Me.Bounds.Size) Dim x As Integer = CInt(clientRect.X) + CInt(clientRect.Width) - icon.Width If Me.RightToLeft Then x = CInt(clientRect.X) End If Dim imageRect As Rectangle = New Rectangle(x, CInt(clientRect.Y) + CInt(clientRect.Height) - icon.Height, icon.Width, icon.Height) graphics.DrawImage(imageRect, icon, ContentAlignment.TopLeft, True) End SyncLock End Sub End Class Public Class MyElementProvider Inherits SchedulerElementProvider Public Sub New(scheduler As RadScheduler) MyBase.New(scheduler) End Sub Protected Overrides Function CreateElement(Of T As SchedulerVisualElement)(view As SchedulerView, context As Object) As T If GetType(T) = GetType(AppointmentElement) Then Return TryCast(New MyAppointmentElement(Me.Scheduler, view, DirectCast(context, IEvent)), T) End If Return MyBase.CreateElement(Of T)(view, context) End Function End Class
If you set the ResourcesPerView property first to a value greater than the available resources in RadScheduler and then add even more resources, incorrect layout is displayed. Please refer to the attached gif file. However, note that if you first add the resources and then manipulate the ResourcesPerView property, everything is OK. Workaround: set the ResourcesPerView property considering the available resources in RadScheduler Private Sub RadSpinEditor2_ValueChanged(sender As Object, e As EventArgs) Handles RadSpinEditor2.ValueChanged Me.RadScheduler1.Resources.Clear() For i As Integer = 1 To Me.RadSpinEditor2.Value Dim resource As New Telerik.WinControls.UI.Resource() resource.Id = New EventId(i) resource.Name = "Resource" & i resource.Visible = True resource.Color = Color.LightBlue Me.RadScheduler1.Resources.Add(resource) Next i Me.RadScheduler1.GroupType = GroupType.Resource Me.RadScheduler1.ActiveView.ResourcesPerView = Math.Min(Me.RadScheduler1.Resources.Count, Me.RadSpinEditor1.Value) End Sub
To reproduce: this.radScheduler1.ActiveViewType = Telerik.WinControls.UI.SchedulerViewType.Month; SchedulerMonthView monthView = this.radScheduler1.GetMonthView(); DateTime start= new DateTime(2018, 8, 1); DateTime end= new DateTime(2018,8,31); monthView.ShowFullMonth = true; monthView.StartDate=start; monthView.RangeStartDate = start; monthView.RangeEndDate = end; You will notice that you can navigate outside the specified range. Workaround: manipulate the start date of the view: this.radScheduler1.ActiveView.PropertyChanged += ActiveView_PropertyChanged; DateTime start = new DateTime(2018, 8, 1); DateTime end = new DateTime(2018,8,31); private void ActiveView_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "StartDate" && (this.radScheduler1.ActiveView.StartDate < start || start.AddDays(30) < this.radScheduler1.ActiveView.StartDate) || e.PropertyName == "WeekCount" && this.radScheduler1.ActiveView.EndDate > end) { this.radScheduler1.ActiveView.StartDate = start; } }
Use attached to reproduce. Workaround: protected override void OnShown(EventArgs e) { base.OnShown(e); radScheduler1.SchedulerElement.ViewElement.UpdateCells(); }
How to rerproduce: this.radScheduler1.AccessibleInterval.Start = new DateTime(2018, 7, 18, 00, 00, 00).AddMonths(-2); this.radScheduler1.AccessibleInterval.End = new DateTime(2018, 7, 18, 00, 00, 00).AddMonths(2); this.radScheduler1.ActiveViewType = Telerik.WinControls.UI.SchedulerViewType.Month; Workaround: public class CustomRadScheduler : RadScheduler { private FieldInfo schedulerFi; private FieldInfo activeViewsFi; private MethodInfo onPropertyChangedMi; private MethodInfo setActiveViewMi; protected override void CreateChildItems(RadElement parent) { base.CreateChildItems(parent); this.activeViewsFi = typeof(RadScheduler).GetField("activeViews", BindingFlags.Instance | BindingFlags.NonPublic); this.schedulerFi = typeof(SchedulerView).GetField("scheduler", BindingFlags.Instance | BindingFlags.NonPublic); this.onPropertyChangedMi = typeof(SchedulerView).GetMethod("OnPropertyChanged", BindingFlags.Instance | BindingFlags.NonPublic); this.setActiveViewMi = typeof(RadScheduler).GetMethod("SetActiveView", BindingFlags.Instance | BindingFlags.NonPublic); } public override string ThemeClassName { get { return typeof(RadScheduler).FullName; } } /// <summary> /// Gets or sets the type of the active view. /// </summary> /// <value>The type of the active view.</value> [DefaultValue(SchedulerViewType.Day)] [NotifyParentProperty(true)] public override SchedulerViewType ActiveViewType { get { return base.ActiveViewType; } set { if (this.ActiveViewType != value && value == SchedulerViewType.Month) { SchedulerView newView; Dictionary<SchedulerViewType, SchedulerView> activeViews = this.activeViewsFi.GetValue(this) as Dictionary<SchedulerViewType, SchedulerView>; if (activeViews.ContainsKey(value)) { newView = activeViews[value]; } else { SchedulerView view = new CustomSchedulerMonthView(); this.schedulerFi.SetValue(view, this); this.onPropertyChangedMi.Invoke(view, new object[] { new string[] { "Scheduler" } }); newView = view; } if (this.ActiveView != newView && newView != null) { this.setActiveViewMi.Invoke(this, new object[] { newView, true }); } } else { base.ActiveViewType = value; } } } } public class CustomSchedulerMonthView : SchedulerMonthView { public override SchedulerView OffsetView(int offset) { if (this.ShowFullMonth) { DateTime dtStart = DateHelper.GetStartOfMonth(this.StartDate); if (this.StartDate.Day > 1) { dtStart = dtStart.AddMonths(1); } dtStart = dtStart.AddMonths(offset); return this.CreateViewWithStartDate(dtStart); } else { DateTime startDate = this.StartDate.Add(new TimeSpan(offset * this.OffsetTimeSpan.Ticks)); DateTimeInterval interval = new DateTimeInterval(startDate, this.GetEndDate(startDate)); if (this.Scheduler.AccessibleInterval.Contains(interval)) { return this.CreateViewWithStartDate(startDate); } if (true) { } return this.CreateViewWithStartDate(startDate); } } protected override SchedulerView CreateViewWithStartDate(DateTime startDate) { SchedulerMonthView monthView = new SchedulerMonthView(); this.CopyPropertiesToView(monthView); DateTimeInterval interval = new DateTimeInterval(startDate, this.GetEndDate(startDate)); if (interval.End > this.Scheduler.AccessibleInterval.End) { startDate = startDate.Add(new TimeSpan(-1 * this.OffsetTimeSpan.Ticks)); } if (interval.Start < this.Scheduler.AccessibleInterval.Start) { startDate = startDate.Add(new TimeSpan(1 * this.OffsetTimeSpan.Ticks)); } monthView.StartDate = startDate; if (this.ShowFullMonth) { monthView.WeekCount = DateHelper.GetMonthDisplayWeeks(startDate, this.CurrentCulture.DateTimeFormat); } return monthView; } }
How to reproduce: public partial class RadForm1 : Telerik.WinControls.UI.RadForm { public RadForm1() { InitializeComponent(); this.radScheduler1.MouseMove += RadScheduler1_MouseMove; this.radScheduler1.GroupType = GroupType.Resource; Appointment appointment = new Appointment(DateTime.Today.AddHours(13), TimeSpan.FromHours(1), "Test Appointment"); this.radScheduler1.Appointments.Add(appointment); } private void RadScheduler1_MouseMove(object sender, MouseEventArgs e) { Point pt = this.radScheduler1.PointToClient(Cursor.Position); SchedulerCellElement cell = this.radScheduler1.SchedulerElement.ElementTree.GetElementAtPoint(pt) as SchedulerCellElement; if (cell != null) { if (cell.Date != null) { Console.WriteLine(cell.Date.ToShortTimeString()); } } } private void button1_Click(object sender, EventArgs e) { switch (this.radScheduler1.ActiveViewType) { // showing the Day View case SchedulerViewType.Day: var theDayView = this.radScheduler1.GetDayView(); if (theDayView != null) { RulerPrimitive ruler = (this.radScheduler1.SchedulerElement.ViewElement as SchedulerDayViewElement).DataAreaElement.Ruler; ruler.RangeFactor = ScaleRange.QuarterHour; ruler.StartScale = 8; ruler.EndScale = 18; } break; } } } Workaround: instead of accessing directly the ruler, apply the scaling on the view element private void button2_Click(object sender, EventArgs e) { switch (this.radScheduler1.ActiveViewType) { // showing the Day View case SchedulerViewType.Day: var theDayView = this.radScheduler1.GetDayView(); if (theDayView != null) { theDayView.RangeFactor = ScaleRange.QuarterHour; theDayView.RulerStartScale = 8; theDayView.RulerEndScale = 18; } break; } }
To reproduce: public Form1() { InitializeComponent(); for (int i = 0; i < 7; i++) { this.radScheduler1.Appointments.Add(new Appointment(DateTime.Now.AddHours(i),TimeSpan.FromHours(3),"App" + i)); } this.radScheduler1.AutoSizeAppointments = true; this.radScheduler1.ActiveViewType = SchedulerViewType.Month; SchedulerMonthView monthView = this.radScheduler1.GetMonthView(); monthView.EnableAppointmentsScrolling = true; } Workaround: set the AutoSizeAppointments property to false.
How to reproduce: public partial class RadForm1 : Telerik.WinControls.UI.RadForm { public RadForm1() { InitializeComponent(); Resource resource1 = new Resource(); resource1.Id = new EventId(1); resource1.Name = "Resource 1"; resource1.Color = Color.Blue; Resource resource2 = new Resource(); resource2.Id = new EventId(2); resource2.Name = "Resource 2"; resource2.Color = Color.Green; Resource resource3 = new Resource(); resource3.Id = new EventId(3); resource3.Name = "Resource 3"; resource3.Color = Color.Red; this.radScheduler1.Resources.Add(resource1); this.radScheduler1.Resources.Add(resource2); this.radScheduler1.Resources.Add(resource3); } private void RadForm1_Load(object sender, EventArgs e) { this.radScheduler1.GroupType = GroupType.Resource; ((SchedulerViewGroupedByResourceElementBase)this.radScheduler1.ViewElement).ResourceStartIndex = 2; } private void radButton1_Click(object sender, EventArgs e) { this.radScheduler1.Resources.RemoveAt(0); } } Workaround: public partial class RadForm1 : Telerik.WinControls.UI.RadForm { public RadForm1() { InitializeComponent(); Resource resource1 = new Resource(); resource1.Id = new EventId(1); resource1.Name = "Resource 1"; resource1.Color = Color.Blue; Resource resource2 = new Resource(); resource2.Id = new EventId(2); resource2.Name = "Resource 2"; resource2.Color = Color.Green; Resource resource3 = new Resource(); resource3.Id = new EventId(3); resource3.Name = "Resource 3"; resource3.Color = Color.Red; this.radScheduler1.Resources.Add(resource1); this.radScheduler1.Resources.Add(resource2); this.radScheduler1.Resources.Add(resource3); } private void RadForm1_Load(object sender, EventArgs e) { this.radScheduler1.GroupType = GroupType.Resource; ((SchedulerViewGroupedByResourceElementBase)this.radScheduler1.ViewElement).ResourceStartIndex = 2; } private void radButton1_Click(object sender, EventArgs e) { this.radScheduler1.GroupType = GroupType.None; this.radScheduler1.Resources.RemoveAt(0); this.radScheduler1.GroupType = GroupType.Resource; } }
Please refer to the attached gif file and sample project. Workaround: remove the database restrictions and validate the data in the edit dialog before submitting the new appointment data.
To reproduce: this.radScheduler1.RightToLeft = System.Windows.Forms.RightToLeft.Yes; this.radScheduler1.Appointments.Add(new Appointment(DateTime.Now, TimeSpan.FromHours(2), "آقای حقیقت")); Please refer to the attached screenshot. Workaround: private void radScheduler1_AppointmentFormatting(object sender, SchedulerAppointmentEventArgs e) { e.AppointmentElement.UseHtml = false; }
To reproduce: RadScheduler radScheduler1 = new RadScheduler(); public Form1() { InitializeComponent(); radScheduler1.Top += 100; radScheduler1.Parent = this; this.radSchedulerNavigator1.AssociatedScheduler = radScheduler1; this.radScheduler1.ActiveViewType = SchedulerViewType.Timeline; Color[] colors = new Color[]{Color.LightBlue, Color.LightGreen, Color.LightYellow, Color.Red, Color.Orange, Color.Pink, Color.Purple, Color.Peru, Color.PowderBlue}; string[] names = new string[]{"Alan Smith", "Anne Dodsworth", "Boyan 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]; this.radScheduler1.Resources.Add(resource); } this.radScheduler1.GroupType = GroupType.Resource; this.radScheduler1.ActiveView.ResourcesPerView = 2; } private void radButton1_Click(object sender, EventArgs e) { SchedulerWeeklyCalendarPrintStyle weeklyCalendarStyle = new SchedulerWeeklyCalendarPrintStyle(); weeklyCalendarStyle.AppointmentFont = new System.Drawing.Font("Segoe UI", 12, FontStyle.Regular); weeklyCalendarStyle.HeadingAreaHeight = 120; weeklyCalendarStyle.HoursColumnWidth = 30; this.radScheduler1.PrintStyle = weeklyCalendarStyle; this.radScheduler1.PrintPreview(); } Workaround: Change the view before printing.
To reproduce: - Use the search in the scheduler navigator. - Sort the grid by start/end date. - The values are sorted as strings. Workraround: - Use custom sorting.