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
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. Double click over the scheduler to open the edit dialog. 2. Click the Recurrence button. 3. Check "all day event" 4. Select Yearly recurrence pattern , every January 1st 5. Confirm the appointment. 6. Navigate to the first occurrence, select it and press Delete key. Confirm the deletion. You will see that the appointment is still visible. However, if you chose the "all day event" from the first edit dialog, everything works as expected.
It would be nice if the RadScheduler allows dragging of multiple selected appointments and change the events' start time in correspondence with the active appointment offset time.
To reproduce: Open Demo application >> Scheduler >> Printing example. Add two appointments one of which is with duration 1 hour, the other one lasts 2 hours. When you click the PrintPreview button, the shorter appointment is missing. Workaround: public Form1() { InitializeComponent(); this.radScheduler1.PrintStyle = new CustomSchedulerDailyPrintStyle(); } public class CustomSchedulerDailyPrintStyle :SchedulerDailyPrintStyle { protected override void DrawAppointments(DateTime currentDate, IResource resource, Rectangle appArea, Graphics graphics) { int rowCount = Math.Max(1, (int)Math.Ceiling((TimeEndRange - TimeSpan.FromHours(TimeStartRange.Hours)).TotalHours)); float rowHeight = (float)appArea.Height / rowCount; List<IEvent> appointments = this.GetAppointments(currentDate, false, resource); appointments.Sort(CompareAppointments); bool setColumn = true; Dictionary<IEvent, int> columns = new Dictionary<IEvent, int>(); Dictionary<IEvent, int> maxColumns = new Dictionary<IEvent, int>(); int currentColumn = 0; while (setColumn) { setColumn = false; DateTime currentTime = DateTime.MinValue; foreach (IEvent app in appointments) { if (!columns.ContainsKey(app) && DateFloor(app.Start) >= currentTime) { setColumn = true; columns.Add(app, currentColumn); currentTime = DateCeiling(app.End); } } currentColumn++; } DateTime maxEndDate = DateTime.MinValue; int lastIndex = 0; int maxColumn = 0; for (int i = 0; i <= appointments.Count; i++) { if (i == appointments.Count || DateFloor(appointments[i].Start) >= maxEndDate) { for (int j = lastIndex; j < i; j++) { maxColumns.Add(appointments[j], maxColumn); } maxColumn = 0; lastIndex = i; } if (i == appointments.Count) { break; } maxColumn = Math.Max(maxColumn, columns[appointments[i]]); if (maxEndDate < DateCeiling(appointments[i].End)) { maxEndDate = DateCeiling(appointments[i].End); } } foreach (IEvent app in appointments) { AppointmentPrintElement printedAppointment = new AppointmentPrintElement(app, this.Scheduler); printedAppointment.ShowHours = false; printedAppointment.DrawBorder = printedAppointment.DrawFill = true; float appY = appArea.Y + Math.Max(0, (float)(((DateFloor(printedAppointment.Start) - currentDate.Add(this.TimeStartRange)).TotalHours) * rowHeight)); float appBottom = appArea.Y + Math.Min(appArea.Height, (float)(((DateCeiling(printedAppointment.End) - currentDate.Add(this.TimeStartRange)).TotalHours) * rowHeight)); float appHeight = appBottom - appY - app.End.Minute; float appWidth = (appArea.Width - HoursColumnWidth) / (maxColumns[app] + 1); float appX = appArea.X + HoursColumnWidth + columns[app] * appWidth; RectangleF appRect = new RectangleF(appX, appY, appWidth, appHeight); appRect.Inflate(-2f, -2f); this.DrawAppointment(printedAppointment, graphics, appRect); } } }
Hi When using group view we need the reminders to be shown for a selected (set programitically) resource. At the moment it shows reminders for all resources that have appointments that need reminding. In our case we have users who have scheduler open in group view showing multiple resources but would only like to be reminded about appointments that are for the user using the system.
This request is to add Working hours range of the view, which will style the cells as working and non working. In addition, add a property ShowWorkingHours while will determine whether non-working hours are visible or not. Or perhaps for the sake of consistency, we can have API as in the day view: dayView.RangeFactor = ScaleRange.QuarterHour dayView.RulerStartScale = 9 dayView.RulerStartScaleMinutes = 30 dayView.RulerEndScale = 14 dayView.RulerEndScaleMinutes = 45
The recurrence rule has a missing letter "Z" at the end of the start/end values.
To reproduce: - Add mapping for the reminder property and try to save it in the database. Workaround: appointmentMappingInfo.Reminder = "Reminder"; appointmentMappingInfo.FindBySchedulerProperty("Reminder").ConvertToScheduler = ConvertReminderToScheduler; appointmentMappingInfo.FindBySchedulerProperty("Reminder").ConvertToDataSource = ConvertReminderToDataSource; private object ConvertReminderToDataSource(object item) private object ConvertReminderToDataSource(object item) { TimeSpan? reminder = item as TimeSpan?; if (reminder != null) { return (int)reminder.Value.TotalMilliseconds; } return 0; } private object ConvertReminderToScheduler(object item) { try { int value = Convert.ToInt32(item); if (value != 0) { return TimeSpan.FromMilliseconds(value); } return null; } catch { return null; } }
ADD. RadScheduler - add the ability to change the culture of the generated print document.
To reproduce: 1. Add several appointments: Random rand = new Random(); for (int i = 0; i < 5; i++) { Appointment app = new Appointment(DateTime.Now.AddHours(i), TimeSpan.FromMinutes(45), "App" + i); app.BackgroundId = this.radScheduler1.Backgrounds[rand.Next(0, radScheduler1.Backgrounds.Count)].Id; this.radScheduler1.Appointments.Add(app); } 2. On RadButton.Click event try to change the PrintStyle and print the scheduler: private void radButton1_Click(object sender, EventArgs e) { SchedulerDetailsPrintStyle detailsStyle = new SchedulerDetailsPrintStyle(); detailsStyle.PageBreakMode = PageBreakMode.Day; this.radScheduler1.PrintStyle = detailsStyle; this.radScheduler1.Print(); }
To reproduce: Add appointments to TimelineView so that they create a vertical scrollbar. Scroll to bottom and click at the last appointment, you will see that the scrollbar will return back to the start and will hide for a moment Workaround: Use the following custom scheduler: public class Myscheduler : RadScheduler { public override string ThemeClassName { get { return typeof(RadScheduler).FullName; } set { base.ThemeClassName = value; } } protected override RadSchedulerElement CreateRadSchedulerElement() { return new MySchedulerElement(this, this.ActiveView); } } class MySchedulerElement : RadSchedulerElement { public MySchedulerElement(RadScheduler scheduler, SchedulerView view) : base(scheduler, view) { } protected override SchedulerViewElement CreateViewElement() { if (this.Scheduler.ActiveViewType == SchedulerViewType.Timeline && this.Scheduler.GroupType == GroupType.None) { return new MyTimelineViewElement(this.Scheduler, this.View); } return base.CreateViewElement(); } } class MyTimelineViewElement : SchedulerTimelineViewElement { public MyTimelineViewElement(RadScheduler scheduler, SchedulerView view) : base(scheduler, view) { } protected override void UpdateVeticalScroll(float presenterHeight, float appointmentsMaxHeight) { base.UpdateVeticalScroll(presenterHeight, appointmentsMaxHeight + this.VScrollBar.Value); } }
Please refer to the attached file.
If your current time is 9:30 AM and you have an appointment in 11:00 AM with reminder 6 hours, the alarm popup should be displayed at 5:00 AM. When you run the application and show the scheduler, the reminder pop up appears immediately. This behavior is expected. However, if you snooze the event with 1 hour, it is expected that the reminder for this appointment will not popup the next hour. However, the RadScheduler makes the following calculation: reminder start time - reminder value + snooze time = 11:00 - 6 + 1 = 6:00. Hence, the reminder popup shows immediately as the current time is 9:30h.
To reproduce: 1. Open Demo application >> Scheduler >> Printing example. 2. Change to Weekly style and return back to Daily style. 3. Modify a random appointment's end time to be half an hour, e.g. 10:30. 4. Change the rule scale to 5 minute and press PrintPreview button. You will notice that the rendered appointment in the PrintPreview dialog fills the entire hour interval, instead of half of it. public Form1() { InitializeComponent(); this.radScheduler1.PrintStyle = new CustomSchedulerDailyPrintStyle(); } public class CustomSchedulerDailyPrintStyle :SchedulerDailyPrintStyle { protected override void DrawAppointments(DateTime currentDate, IResource resource, Rectangle appArea, Graphics graphics) { int rowCount = Math.Max(1, (int)Math.Ceiling((TimeEndRange - TimeSpan.FromHours(TimeStartRange.Hours)).TotalHours)); float rowHeight = (float)appArea.Height / rowCount; List<IEvent> appointments = this.GetAppointments(currentDate, false, resource); appointments.Sort(CompareAppointments); bool setColumn = true; Dictionary<IEvent, int> columns = new Dictionary<IEvent, int>(); Dictionary<IEvent, int> maxColumns = new Dictionary<IEvent, int>(); int currentColumn = 0; while (setColumn) { setColumn = false; DateTime currentTime = DateTime.MinValue; foreach (IEvent app in appointments) { if (!columns.ContainsKey(app) && DateFloor(app.Start) >= currentTime) { setColumn = true; columns.Add(app, currentColumn); currentTime = DateCeiling(app.End); } } currentColumn++; } DateTime maxEndDate = DateTime.MinValue; int lastIndex = 0; int maxColumn = 0; for (int i = 0; i <= appointments.Count; i++) { if (i == appointments.Count || DateFloor(appointments[i].Start) >= maxEndDate) { for (int j = lastIndex; j < i; j++) { maxColumns.Add(appointments[j], maxColumn); } maxColumn = 0; lastIndex = i; } if (i == appointments.Count) { break; } maxColumn = Math.Max(maxColumn, columns[appointments[i]]); if (maxEndDate < DateCeiling(appointments[i].End)) { maxEndDate = DateCeiling(appointments[i].End); } } foreach (IEvent app in appointments) { AppointmentPrintElement printedAppointment = new AppointmentPrintElement(app, this.Scheduler); printedAppointment.ShowHours = false; printedAppointment.DrawBorder = printedAppointment.DrawFill = true; float appY = appArea.Y + Math.Max(0, (float)(((DateFloor(printedAppointment.Start) - currentDate.Add(this.TimeStartRange)).TotalHours) * rowHeight)); float appBottom = appArea.Y + Math.Min(appArea.Height, (float)(((DateCeiling(printedAppointment.End) - currentDate.Add(this.TimeStartRange)).TotalHours) * rowHeight)); float appHeight = appBottom - appY - app.End.Minute; float appWidth = (appArea.Width - HoursColumnWidth) / (maxColumns[app] + 1); float appX = appArea.X + HoursColumnWidth + columns[app] * appWidth; RectangleF appRect = new RectangleF(appX, appY, appWidth, appHeight); appRect.Inflate(-2f, -2f); this.DrawAppointment(printedAppointment, graphics, appRect); } } } private void radButton1_Click(object sender, EventArgs e) { this.radScheduler1.PrintPreview(); }
Add Reminder property to the AppointmentMappingInfo class.