Add the ability to display the text in appointments vertically.
Description: Using the AppointmentFormatting event, setting the AppointmentElement's TextOrientation property to Vertical should paint the content text in the corresponding orientation.
To reproduce: public Form1() { InitializeComponent(); this.radScheduler1.ActiveViewType = Telerik.WinControls.UI.SchedulerViewType.Timeline; this.radScheduler1.EnableGesture(Telerik.WinControls.GestureType.Pan); this.radScheduler1.DisableGesture(Telerik.WinControls.GestureType.Zoom); this.radScheduler1.ZoomGesture+=radScheduler1_ZoomGesture; this.radScheduler1.PanGesture+=radScheduler1_PanGesture; } private void radScheduler1_PanGesture(object sender, Telerik.WinControls.PanGestureEventArgs e) { Console.WriteLine("Pan should fire"); } private void radScheduler1_ZoomGesture(object sender, Telerik.WinControls.ZoomGestureEventArgs e) { Console.WriteLine("Zoom should NOT fire"); } Workaround: public class CustomScheduler : RadScheduler { public override string ThemeClassName { get { return typeof(RadScheduler).FullName; } } protected override void OnZoomGesture(Telerik.WinControls.ZoomGestureEventArgs args) { //stop the basic logic //base.OnZoomGesture(args); } }
Workaround: public class MyTimelineGroupingByResourcesElement : TimelineGroupingByResourcesElement { public MyTimelineGroupingByResourcesElement(RadScheduler scheduler, SchedulerView view) : base(scheduler, view) { } public override void NavigateForward() { TimeSpan ts = (this.View as SchedulerTimelineView).RangeEndDate - this.View.StartDate; int differenceInDays = ts.Days; int displayedCells = (this.View as SchedulerTimelineView).GetScaling().DisplayedCellsCount; if (differenceInDays >= displayedCells) { base.NavigateForward(); } } } public class MyElementProvider : SchedulerElementProvider { public MyElementProvider(RadScheduler scheduler) : base(scheduler) { } protected override T CreateElement<T>(SchedulerView view, object context) { if (typeof(T) == typeof(TimelineGroupingByResourcesElement)) { return new MyTimelineGroupingByResourcesElement(this.Scheduler, view) as T; } return base.CreateElement<T>(view, context); } } public RadForm2() { InitializeComponent(); this.radScheduler1.ElementProvider = new MyElementProvider(this.radScheduler2); }
To reproduce: 1. Add a RadDock with one DocumentWindow. 2. Place a RadSchedulerNavigator in the DocumentWindow. 3. Add a RadButton and use the following code snippet: private void radButton1_Click(object sender, EventArgs e) { this.radSchedulerNavigator1.SchedulerNavigatorElement.TimeZonesDropDown.SelectedIndexChanging += TimeZonesDropDown_SelectedIndexChanging; string path = @"..\..\layout.xml"; this.radDock1.SaveToXml(path); this.radDock1.LoadFromXml(path); RadScheduler sched = new RadScheduler(); this.documentWindow1.Controls.Add(sched); sched.Dock = DockStyle.Left; this.radSchedulerNavigator1.AssociatedScheduler = this.documentWindow1.Controls[1] as RadScheduler; } After running the application and clicking the button, you will notice that RadScheduler has time zone "Casablanca" but the RadSchedulerNavigator has a different time zone. Workaround: associate the RadSchedulerNavigator before loading the layout.
To reproduce: public Form1() { InitializeComponent(); this.radScheduler1.Appointments.Add(new Appointment(DateTime.Today.AddHours(1),TimeSpan.FromHours(3),"Meeting")); this.radScheduler1.ActiveViewType = SchedulerViewType.Week; this.radScheduler1.GetWeekView().RangeFactor = ScaleRange.HalfHour; this.radScheduler1.SchedulerElement.DragDropBehavior.AutoScrollDayViewOnDrag = true; this.Size = new Size(800, 350); } It's necessary to stretch down the application so that a few hours are shown (let's say 4 hours) and the appointment is a bit less, for example 3 hours. If you look at the gif, I am scrolling down around 14, then I'm stopping a bit, while always keeping the mouse button pressed, and then I start scrolling up: at that time the scroll results in going down until 19, instead of going up. Workaround: this.radScheduler1.SchedulerElement.DragDropBehavior = new CustomAppointmentDraggingBehavior(this.radScheduler1.SchedulerElement); public class CustomAppointmentDraggingBehavior : AppointmentDraggingBehavior { public CustomAppointmentDraggingBehavior(SchedulerVisualElement activeOwner) : base(activeOwner) { } protected override void HandleMouseMove(Point mousePos) { base.HandleMouseMove(mousePos); DayViewAppointmentsTable table = this.ActiveOwner.Scheduler.DragDropBehavior.ActiveOwner as DayViewAppointmentsTable; if (table != null && this.ActiveOwner.Scheduler.DragDropBehavior.AutoScrollDayViewOnDrag) { Point pt = table.PointFromScreen(Control.MousePosition); FieldInfo fi = typeof(DayViewAppointmentsTable).GetField("lastMovingPoint", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); fi.SetValue(table, pt); } } }
Workaround: subscribe to the PanGesture event and set the StartDate property of the current view to the desired new date.
To reproduce: - Bind the scheduler to the default SchedulerData.mdb - Add an appointment like this: this.radScheduler1.Appointments.BeginUpdate(); Appointment appointment = CreateAppointment(); this.radScheduler1.Appointments.Add(appointment); this.radScheduler1.Appointments.EndUpdate(); - Save the database
RadScheduler/RadSchedulerNavigator crashes upon BindingContext change during being/end initialize
Please refer to the attached screenshots. A sample project is attached. There is a known issue in the .NET Framework considering the "fa-IR" culture. Please refer to the following MSDN resource for a solution which is included in the sample project: https://code.msdn.microsoft.com/Fixing-Persian-Locale-for-6e66e044#content Workaround: private void radScheduler1_CellFormatting(object sender, SchedulerCellEventArgs e) { MonthCellElement monthCellElement = e.CellElement as MonthCellElement; if (monthCellElement != null) { monthCellElement.Header.Text = monthCellElement.Date.ToString("dd", this.radScheduler1.Culture); } }
To reproduce: please refer to the attached gif file Dim a1 As New Appointment(DateTime.Today.AddDays(-1), TimeSpan.FromDays(3), "Termin1") a1.AllDay = True Dim a2 As New Appointment(DateTime.Today.AddDays(-1), TimeSpan.FromDays(1), "Termin2") a2.AllDay = True Me.RadScheduler1.Appointments.Add(a1) Me.RadScheduler1.Appointments.Add(a2) Workaround: specify precisely the end date including the time part as well Dim a1 As New Appointment(DateTime.Today.AddDays(-1), TimeSpan.FromDays(3).Add(TimeSpan.FromMinutes(1)), "Termin1") a1.AllDay = False Dim a2 As New Appointment(DateTime.Today.AddDays(-1), TimeSpan.FromDays(2).Add(TimeSpan.FromMinutes(1)), "Termin2") a2.AllDay = False Me.RadScheduler1.Appointments.Add(a1) Me.RadScheduler1.Appointments.Add(a2)
To reproduce: use the following code snippet: private BindingList<MyEvent> eventsSource = new BindingList<MyEvent>(); private AppointmentMappingInfo appointmentMappingInfo_g = new AppointmentMappingInfo(); public RadForm2() { InitializeComponent(); } private void RadForm2_Load(object sender, EventArgs e) { radScheduler1.ActiveViewType = radScheduler2.ActiveViewType = SchedulerViewType.Timeline; radScheduler1.GetTimelineView().ShowTimescale(Timescales.Days); radScheduler2.GetTimelineView().ShowTimescale(Timescales.Days); radScheduler1.GetTimelineView().RangeStartDate = radScheduler2.GetTimelineView().RangeStartDate = new DateTime(2015, 9, 1); radScheduler1.GetTimelineView().RangeEndDate = radScheduler2.GetTimelineView().RangeEndDate = new DateTime(2015, 9, 30); radScheduler1.GetTimelineView().StartDate = radScheduler2.GetTimelineView().StartDate = new DateTime(2015, 9, 1); radScheduler1.GetTimelineView().GetScaling().DisplayedCellsCount = radScheduler2.GetTimelineView().GetScaling().DisplayedCellsCount = 7; appointmentMappingInfo_g.Start = "Start"; appointmentMappingInfo_g.End = "End"; appointmentMappingInfo_g.Summary = "Subject"; appointmentMappingInfo_g.Description = "Description"; appointmentMappingInfo_g.Location = "Location"; appointmentMappingInfo_g.UniqueId = "Id"; SchedulerBindingDataSource dataSource_l = new SchedulerBindingDataSource(); dataSource_l.EventProvider.Mapping = appointmentMappingInfo_g; dataSource_l.EventProvider.DataSource = eventsSource; radScheduler2.DataSource = dataSource_l; FillAppointments(); } private void FillAppointments() { Appointment appointment = new Appointment(new DateTime(2015, 9, 2), new DateTime(2015, 9, 6), "DU 2 AU 6"); appointment.AllDay = true; radScheduler1.Appointments.BeginUpdate(); radScheduler1.Appointments.Add(appointment); radScheduler1.Appointments.EndUpdate(); MyEvent appointment2 = new MyEvent(new DateTime(2015, 9, 2), new DateTime(2015, 9, 6), "DU 2 AU 6","","",""); radScheduler2.Appointments.BeginUpdate(); eventsSource.Add(appointment2); radScheduler2.Appointments.EndUpdate(); } public class MyEvent { public DateTime Start { get; set; } public DateTime End { get; set; } public string Subject { get; set; } public string Description { get; set; } public string Location { get; set; } public string UniqueId { get; set; } public MyEvent(DateTime start, DateTime end, string subject, string description, string location, string uniqueId) { this.Start = start; this.End = end; this.Subject = subject; this.Description = description; this.Location = location; this.UniqueId = uniqueId; } } Workaround: specify the end day with 1 second more: MyEvent appointment2 = new MyEvent(new DateTime(2015, 9, 2), new DateTime(2015, 9, 6, 0, 0, 1), "DU 2 AU 6", "", "", "");
Please refer to the attached file. Workaround: clear remind objects when the appointment is changed: private void radScheduler1_AppointmentChanged(object sender, AppointmentChangedEventArgs e) { schedulerReminder.ClearRemindObjects(); foreach (Appointment a in this.radScheduler1.Appointments) { schedulerReminder.AddRemindObject(a); } }
To reproduce: Add a RadScheduler to a form and try the following method : private void Scroll() { SchedulerDayView dayView = radScheduler1.GetDayView(); SchedulerWeekView weekView = radScheduler1.GetWeekView(); dayView.RulerStartScale = 7; dayView.RulerEndScale = 22; if (radScheduler1.ActiveViewType == SchedulerViewType.Day) { if (dayView != null) { dayView.RangeFactor = ScaleRange.QuarterHour; } } else if (radScheduler1.ActiveViewType == SchedulerViewType.Week) { if (weekView != null) { weekView.RangeFactor = ScaleRange.QuarterHour; } } dayView.RulerTimeFormat = RulerTimeFormat.hours24; SchedulerDayViewElement dayViewElement = this.radScheduler1.SchedulerElement.ViewElement as SchedulerDayViewElement; if (dayViewElement != null) { dayViewElement.DataAreaElement.Table.ScrollToTime(new TimeSpan(DateTime.Now.Hour, 0, 0)); } } As you can see the scroll is not correct.
To reproduce: use a German TimeZone 1. Create a recurring appointment with a yearly recurrence rule on the last Sunday of October. 2. Export to iCal. As a result, the TimeZone information is not correct. The exported RRULE BYSETPOS=5 defines the 5th Sunday. This is wrong. There may be a year with 5 Sundays in March/October but that is not true for every year. The correct encoding for ics files is BYSETPOS=-1. This indicates the last Sunday of a month. The other error is the DTSTART:16010101T030000 and DTSTART:00010101T020000. The German daylight rule is valid since 1996, not since 1601 or year 1. Note: German timezone defines the switch to daylight saving time as - start on last Sunday in March at 03:00 - end on last Sunday in October at 02:00 This rule is valid since 1996. Alert: Events created in RadScheduler for the last Sunday of a month are correct! The rule here is exported as expected and contains BYSETPOS=-1:
To reproduce: public Form1() { InitializeComponent(); Appointment a1 = new Appointment(new DateTime(2015, 03, 04, 10, 30, 0), TimeSpan.FromMinutes(30), "A1"); Appointment a2 = new Appointment(new DateTime(2015, 03, 04, 11, 00, 0), TimeSpan.FromMinutes(30), "A2"); Appointment a3 = new Appointment(new DateTime(2015, 03, 04, 11, 30, 0), TimeSpan.FromMinutes(30), "A3"); this.radScheduler1.Appointments.Add(a1); this.radScheduler1.Appointments.Add(a2); this.radScheduler1.Appointments.Add(a3); DateTime currentDate = new DateTime(2015, 03, 03, 09, 00, 10); this.radScheduler1.FocusedDate = currentDate; SchedulerTimelineView timelineView = radScheduler1.GetTimelineView(); timelineView.ShowTimescale(Timescales.Minutes); timelineView.RangeStartDate = currentDate.AddMonths(-3); timelineView.RangeEndDate = currentDate.AddMonths(3); timelineView.GetScaling().DisplayedCellsCount = 10; } Workaround: Use the date part only: DateTime currentDate = new DateTime(2015, 03, 03, 09, 00, 10); currentDate = currentDate.Date;
To reproduce: 1. Follow the steps for creating custom Appointment as it is demonstrated here: http://www.telerik.com/help/winforms/scheduler-appointments-and-dialogs-adding-a-custom-field-to-the-editappointment-dialog.html 2. Create a new Appointment and press Ctrl+C to copy the selected custom appointment. 3. Press Ctrl+V to paste. You will notice that the pasted appointment is from the default type, not the custom one. Workaround: this.radScheduler1.AppointmentsCopying += radScheduler1_AppointmentsCopying; this.radScheduler1.AppointmentsPasting += radScheduler1_AppointmentsPasting; private void radScheduler1_AppointmentsCopying(object sender, SchedulerClipboardEventArgs e) { email = ((AppointmentWithEmail)this.radScheduler1.SelectionBehavior.SelectedAppointments.First()).Email; } private void radScheduler1_AppointmentsPasting(object sender, SchedulerClipboardEventArgs e) { e.Cancel = true; if (e.Format == "ICal") { DataObject clipboardObject = Clipboard.GetDataObject() as DataObject; if (clipboardObject == null) { return; } string ical = Convert.ToString(clipboardObject.GetData(RadScheduler.ICalendarDataFormat)); bool pasteResult = PasteFromICal(ical); } } private bool PasteFromICal(string ical) { SchedulerICalendarImporter importer = new SchedulerICalendarImporter( this.radScheduler1.AppointmentFactory); SnapshotAppointmentsSchedulerData data = new SnapshotAppointmentsSchedulerData(this.radScheduler1, null); importer.Import(data, ical); ISchedulerStorage<IEvent> storage = data.GetEventStorage(); if (storage == null || storage.Count == 0) { return false; } IEnumerator<IEvent> enumerator = storage.GetEnumerator(); enumerator.MoveNext(); TimeSpan pasteOffset = this.radScheduler1.SelectionBehavior.SelectionStartDate - enumerator.Current.Start; enumerator.Dispose(); foreach (IEvent appointment in storage) { TimeSpan oldDuration = appointment.Duration; appointment.Start = appointment.Start.Add(pasteOffset); appointment.Duration = oldDuration; appointment.UniqueId = new EventId(Guid.NewGuid()); ((AppointmentWithEmail)appointment).Email = email; if (appointment.RecurrenceRule != null && appointment.Exceptions != null) { foreach (IEvent exception in appointment.Exceptions) { oldDuration = exception.Duration; exception.Start = exception.Start.Add(pasteOffset); exception.Duration = oldDuration; exception.UniqueId = new EventId(Guid.NewGuid()); } } if (this.radScheduler1.GroupType == GroupType.Resource) { appointment.ResourceId = this.radScheduler1.SelectionBehavior.SelectedResourceId; } } foreach (IEvent appointment in storage) { this.radScheduler1.Appointments.Add(appointment); } return true; }
Workaround: SchedulerBindingDataSource schedulerBindingSource = new SchedulerBindingDataSource(); schedulerBindingSource.EventProvider.ResourceMapperFactory = new MyResourceMapperFactory(schedulerBindingSource); class MyResourceMapperFactory : Telerik.WinControls.UI.Scheduler.ResourceMapperFactory { public MyResourceMapperFactory(SchedulerBindingDataSource owner) : base(owner) { } public override Telerik.WinControls.UI.Scheduler.ResourceIdMapper GetResourceMapper(object dataSourceItem, PropertyDescriptor resourceIdDescriptor) { if (resourceIdDescriptor == null) { resourceIdDescriptor = GetResourceIdDescriptor(dataSourceItem); } return base.GetResourceMapper(dataSourceItem, resourceIdDescriptor); } private PropertyDescriptor GetResourceIdDescriptor(object resourceIdList) { string resourceIdPropertyName = ((AppointmentMappingInfo)this.OwnerDataSource.EventProvider.Mapping).ResourceId; if (string.IsNullOrEmpty(resourceIdPropertyName)) return null; System.Collections.IList list = resourceIdList as System.Collections.IList; Type listType = resourceIdList.GetType(); if (list == null && listType.IsGenericType && listType.GetGenericArguments().Length == 1) { Type[] genericArguments = listType.GetGenericArguments(); PropertyDescriptorCollection resourceProperties = TypeDescriptor.GetProperties(genericArguments[0]); return resourceProperties.Find(resourceIdPropertyName, true); } else { PropertyDescriptorCollection resourceProperties = ListBindingHelper.GetListItemProperties(resourceIdList); return resourceProperties.Find(resourceIdPropertyName, true); } } }