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
Hi,
using a RadScheduler into a desktop application. It seems like, on mouse-down event happening into a cell of the first row, the grid of the scheduler is shifting down of a row, resulting in the mouse handle being on the previous row's cell. No mouse wheel scrolled, no other mouse movement. Just one left-click. The result is that on mouse-up we are in a different cell and our event-handler is getting confused.
Sorry for not having any code snippet, I just attach a video of what's happening. Consider that I have only positioned the mouse on the cell at 8am and left-clicked. Tested also with version 2019.2.508 (even though in our app we are still using 2016.2.608).
Thanks in advance and best regards,
Emanuele Nava
Apogeo srl
Italy
When RadScheduler is grouped by resources, the programmatically added Holidays are not displayed into the view:
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 = 2
Dim holiday As Holiday = New Holiday()
holiday.Date = New DateTime(2023, 3, 8)
holiday.HolidayName = "International Women's Day"
holiday.Location = "Bulgaria"
Dim generateAppointment As Boolean = True
Me.RadScheduler1.Holidays.AddHoliday(holiday, generateAppointment)
End Sub
How it looks with resources:
How it looks without resources:
This width is 6px by default and it doesn't offer convenient API for customizing it:
If I set '2 Settimane' (2 Weeks in English) and re-open the appointment it show '2 ore' (2 hours in English) or
If i set '4 giorni' (4 days in English) and re-open the appointment it show '4 ore' (4 hours in English)
The code snippet reproduces the issue:
Public Class RadForm1
Sub New()
RadSchedulerLocalizationProvider.CurrentProvider = New ItalianSchedulerLocalizationProvider()
InitializeComponent()
End Sub
Private Sub RadForm1_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
'
End Sub
End Class
Public Class ItalianSchedulerLocalizationProvider
Inherits RadSchedulerLocalizationProvider
Public Overrides Function GetLocalizedString(id As String) As String
Select Case id
Case RadSchedulerStringId.NextAppointment
Return "Prossimi Appuntamenti"
Case RadSchedulerStringId.PreviousAppointment
Return "Appuntamenti Precedenti"
Case RadSchedulerStringId.AppointmentDialogTitle
Return "Modifica Appuntamento"
Case RadSchedulerStringId.AppointmentDialogSubject
Return "Oggetto:"
Case RadSchedulerStringId.AppointmentDialogLocation
Return "Posizione:"
Case RadSchedulerStringId.AppointmentDialogBackground
Return "Sfondo:"
Case RadSchedulerStringId.AppointmentDialogDescription
Return "Descrizione:"
Case RadSchedulerStringId.AppointmentDialogStartTime
Return "Ora di inizio:"
Case RadSchedulerStringId.AppointmentDialogEndTime
Return "Ora di fine:"
Case RadSchedulerStringId.AppointmentDialogAllDay
Return "Tutto il giorno"
Case RadSchedulerStringId.AppointmentDialogResource
Return "Risorsa:"
Case RadSchedulerStringId.AppointmentDialogStatus
Return "Mostra come:"
Case RadSchedulerStringId.AppointmentDialogOK
Return "OK"
Case RadSchedulerStringId.AppointmentDialogCancel
Return "Annulla"
Case RadSchedulerStringId.AppointmentDialogDelete
Return "Elimina"
Case RadSchedulerStringId.AppointmentDialogRecurrence
Return "Ricorrenza"
Case RadSchedulerStringId.OpenRecurringDialogTitle
Return "Apri elemento ricorrente"
Case RadSchedulerStringId.DeleteRecurrenceDialogOK
Return "OK"
Case RadSchedulerStringId.OpenRecurringDialogOK
Return "OK"
Case RadSchedulerStringId.DeleteRecurrenceDialogCancel
Return "Annulla"
Case RadSchedulerStringId.OpenRecurringDialogCancel
Return "Annulla"
Case RadSchedulerStringId.OpenRecurringDialogLabel
Return """{0}"" è un appuntamento" & vbLf & "ricorrente. Vuoi aprire" & vbLf & "la sola occorenza o la serie?"
Case RadSchedulerStringId.OpenRecurringDialogRadioOccurrence
Return "Apri questa occorrenza."
Case RadSchedulerStringId.OpenRecurringDialogRadioSeries
Return "Apri la serie."
Case RadSchedulerStringId.DeleteRecurrenceDialogTitle
Return "Conferma cancellazione"
Case RadSchedulerStringId.DeleteRecurrenceDialogRadioOccurrence
Return "Elimina questa occorrenza."
Case RadSchedulerStringId.DeleteRecurrenceDialogRadioSeries
Return "Elimina la serie."
Case RadSchedulerStringId.DeleteRecurrenceDialogLabel
Return "Vuoi eliminare tutte le occorrenze dell'appuntamento ricorrente ""{0}"", o sola questa?"
Case RadSchedulerStringId.RecurrenceDragDropCreateExceptionDialogText
Return "Hai modificato la data di una singola occorrenza di un appuntamento ricorrente. Per modificare tutte le date, aprire la serie." & vbLf & "Vuoi cambiare solo questa?"
Case RadSchedulerStringId.RecurrenceDragDropValidationSameDateText
Return "Due occorrenze della stessa serie non possono verificarsi nello stesso giorno."
Case RadSchedulerStringId.RecurrenceDragDropValidationSkipOccurrenceText
Return "Non è possibile riprogrammare un'occorrenza di un appuntamento ricorrente se viene saltata un'occorrenza successiva dello stesso appuntamento."
Case RadSchedulerStringId.RecurrenceDialogMessageBoxText
Return "La data di inizio deve essere precedente alla data di fine."
Case RadSchedulerStringId.RecurrenceDialogMessageBoxWrongRecurrenceRuleText
Return "Il modello di ricorrenza non è valido."
Case RadSchedulerStringId.RecurrenceDialogMessageBoxTitle
Return "Errore di validazione"
Case RadSchedulerStringId.RecurrenceDialogTitle
Return "Modifica ricorrenza"
Case RadSchedulerStringId.RecurrenceDialogAppointmentTimeGroup
Return "Orario dell'appuntamento"
Case RadSchedulerStringId.RecurrenceDialogDuration
Return "Durata:"
Case RadSchedulerStringId.RecurrenceDialogAppointmentEnd
Return "Fine:"
Case RadSchedulerStringId.RecurrenceDialogAppointmentStart
Return "Inizio:"
Case RadSchedulerStringId.RecurrenceDialogRecurrenceGroup
Return "Modello di ricorrenza"
Case RadSchedulerStringId.RecurrenceDialogRangeGroup
Return "Intervallo di ricorrenza"
Case RadSchedulerStringId.RecurrenceDialogOccurrences
Return "occorrenze"
Case RadSchedulerStringId.RecurrenceDialogRecurrenceStart
Return "Inizio:"
Case RadSchedulerStringId.RecurrenceDialogYearly
Return "Annuale"
Case RadSchedulerStringId.RecurrenceDialogHourly
Return "Ora"
Case RadSchedulerStringId.RecurrenceDialogMonthly
Return "Mese"
Case RadSchedulerStringId.RecurrenceDialogWeekly
Return "Settimana"
Case RadSchedulerStringId.RecurrenceDialogDaily
Return "Giorno"
Case RadSchedulerStringId.RecurrenceDialogEndBy
Return "Fine entro:"
Case RadSchedulerStringId.RecurrenceDialogEndAfter
Return "Fine dopo:"
Case RadSchedulerStringId.RecurrenceDialogNoEndDate
Return "Nessuna data di fine"
Case RadSchedulerStringId.RecurrenceDialogAllDay
Return "Evento tutto il giorno"
Case RadSchedulerStringId.RecurrenceDialogDurationDropDown1Day
Return "1 giorno"
Case RadSchedulerStringId.RecurrenceDialogDurationDropDown2Days
Return "2 giorni"
Case RadSchedulerStringId.RecurrenceDialogDurationDropDown3Days
Return "3 giorni"
Case RadSchedulerStringId.RecurrenceDialogDurationDropDown4Days
Return "4 giorni"
Case RadSchedulerStringId.RecurrenceDialogDurationDropDown1Week
Return "1 settimana"
Case RadSchedulerStringId.RecurrenceDialogDurationDropDown2Weeks
Return "2 settimane"
Case RadSchedulerStringId.RecurrenceDialogOK
Return "OK"
Case RadSchedulerStringId.RecurrenceDialogCancel
Return "Annulla"
Case RadSchedulerStringId.RecurrenceDialogRemoveRecurrence
Return "Elimina Ricorrenza"
Case RadSchedulerStringId.HourlyRecurrenceEvery
Return "Ogni"
Case RadSchedulerStringId.HourlyRecurrenceHours
Return "Ora(e)"
Case RadSchedulerStringId.DailyRecurrenceEveryDay
Return "Ogni"
Case RadSchedulerStringId.DailyRecurrenceEveryWeekday
Return "Ogni giorno della settimana"
Case RadSchedulerStringId.DailyRecurrenceDays
Return "giorno(i)"
Case RadSchedulerStringId.WeeklyRecurrenceRecurEvery
Return "Ricorre ogni"
Case RadSchedulerStringId.WeeklyRecurrenceWeeksOn
Return "settimana(e) dopo:"
Case RadSchedulerStringId.WeeklyRecurrenceSunday
Return "Domenica"
Case RadSchedulerStringId.WeeklyRecurrenceMonday
Return "Lunedì"
Case RadSchedulerStringId.WeeklyRecurrenceTuesday
Return "Martedì"
Case RadSchedulerStringId.WeeklyRecurrenceWednesday
Return "Mercoledì"
Case RadSchedulerStringId.WeeklyRecurrenceThursday
Return "Giovedì"
Case RadSchedulerStringId.WeeklyRecurrenceFriday
Return "Venerdì"
Case RadSchedulerStringId.WeeklyRecurrenceSaturday
Return "Sabato"
Case RadSchedulerStringId.WeeklyRecurrenceDay
Return "Giorno"
Case RadSchedulerStringId.WeeklyRecurrenceWeekday
Return "Giorno lavorativo"
Case RadSchedulerStringId.WeeklyRecurrenceWeekendDay
Return "Giorno del fine settimana"
Case RadSchedulerStringId.MonthlyRecurrenceDay
Return "Giorno"
Case RadSchedulerStringId.MonthlyRecurrenceWeek
Return "Il"
Case RadSchedulerStringId.MonthlyRecurrenceDayOfMonth
Return "di ogni"
Case RadSchedulerStringId.MonthlyRecurrenceMonths
Return "mese(i)"
Case RadSchedulerStringId.MonthlyRecurrenceWeekOfMonth
Return "di ogni"
Case RadSchedulerStringId.MonthlyRecurrenceFirst
Return "Primo"
Case RadSchedulerStringId.MonthlyRecurrenceSecond
Return "Secondo"
Case RadSchedulerStringId.MonthlyRecurrenceThird
Return "Terzo"
Case RadSchedulerStringId.MonthlyRecurrenceFourth
Return "Quarto"
Case RadSchedulerStringId.MonthlyRecurrenceLast
Return "Ultimo"
Case RadSchedulerStringId.YearlyRecurrenceDayOfMonth
Return "Ogni"
Case RadSchedulerStringId.YearlyRecurrenceWeekOfMonth
Return "Il"
Case RadSchedulerStringId.YearlyRecurrenceOfMonth
Return "di"
Case RadSchedulerStringId.YearlyRecurrenceJanuary
Return "Gennaio"
Case RadSchedulerStringId.YearlyRecurrenceFebruary
Return "Febbraio"
Case RadSchedulerStringId.YearlyRecurrenceMarch
Return "Marzo"
Case RadSchedulerStringId.YearlyRecurrenceApril
Return "Aprile"
Case RadSchedulerStringId.YearlyRecurrenceMay
Return "Maggio"
Case RadSchedulerStringId.YearlyRecurrenceJune
Return "Giugno"
Case RadSchedulerStringId.YearlyRecurrenceJuly
Return "Luglio"
Case RadSchedulerStringId.YearlyRecurrenceAugust
Return "Agosto"
Case RadSchedulerStringId.YearlyRecurrenceSeptember
Return "Settembre"
Case RadSchedulerStringId.YearlyRecurrenceOctober
Return "Ottobre"
Case RadSchedulerStringId.YearlyRecurrenceNovember
Return "Novembre"
Case RadSchedulerStringId.YearlyRecurrenceDecember
Return "Dicembre"
Case RadSchedulerStringId.BackgroundNone
Return "Nessuna"
Case RadSchedulerStringId.BackgroundImportant
Return "Importante"
Case RadSchedulerStringId.BackgroundBusiness
Return "Business"
Case RadSchedulerStringId.BackgroundPersonal
Return "Personale"
Case RadSchedulerStringId.BackgroundVacation
Return "Vacanza"
Case RadSchedulerStringId.BackgroundMustAttend
Return "Deve Frequentare"
Case RadSchedulerStringId.BackgroundTravelRequired
Return "Viaggio Richiesto"
Case RadSchedulerStringId.BackgroundNeedsPreparation
Return "Necessita di preparazione"
Case RadSchedulerStringId.BackgroundBirthday
Return "Compleanno"
Case RadSchedulerStringId.BackgroundAnniversary
Return "Anniversario"
Case RadSchedulerStringId.BackgroundPhoneCall
Return "Chiamata Tel."
Case RadSchedulerStringId.StatusBusy
Return "Occupato"
Case RadSchedulerStringId.StatusFree
Return "Libero"
Case RadSchedulerStringId.StatusTentative
Return "Tentative"
Case RadSchedulerStringId.StatusUnavailable
Return "Non Disponibile"
Case RadSchedulerStringId.ReminderNone
Return "Nessuno"
Case RadSchedulerStringId.ReminderOneMinute
Return "1 minuto"
Case RadSchedulerStringId.ReminderMinutes
Return " minuti"
Case RadSchedulerStringId.ReminderOneSecond
Return "1 secondo"
Case RadSchedulerStringId.ReminderSeconds
Return " secondi"
Case RadSchedulerStringId.ReminderDays
Return " giorni"
Case RadSchedulerStringId.ReminderWeeks
Return " settimane"
Case RadSchedulerStringId.ReminderHours
Return " ore"
Case RadSchedulerStringId.ReminderZeroMinutes
Return "0 minuti"
Case RadSchedulerStringId.ReminderFiveMinutes
Return "5 minuti"
Case RadSchedulerStringId.ReminderTenMinutes
Return "10 minuti"
Case RadSchedulerStringId.ReminderFifteenMinutes
Return "15 minuti"
Case RadSchedulerStringId.ReminderThirtyMinutes
Return "30 minuti"
Case RadSchedulerStringId.ReminderOneHour
Return "1 ora"
Case RadSchedulerStringId.ReminderTwoHours
Return "2 ore"
Case RadSchedulerStringId.ReminderThreeHours
Return "3 ore"
Case RadSchedulerStringId.ReminderFourHours
Return "4 ore"
Case RadSchedulerStringId.ReminderFiveHours
Return "5 ore"
Case RadSchedulerStringId.ReminderSixHours
Return "6 ore"
Case RadSchedulerStringId.ReminderSevenHours
Return "7 ore"
Case RadSchedulerStringId.ReminderEightHours
Return "8 ore"
Case RadSchedulerStringId.ReminderNineHours
Return "9 ore"
Case RadSchedulerStringId.ReminderTenHours
Return "10 ore"
Case RadSchedulerStringId.ReminderElevenHours
Return "11 ore"
Case RadSchedulerStringId.ReminderTwelveHours
Return "12 ore"
Case RadSchedulerStringId.ReminderEighteenHours
Return "18 ore"
Case RadSchedulerStringId.ReminderOneDay
Return "1 giorno"
Case RadSchedulerStringId.ReminderTwoDays
Return "2 giorni"
Case RadSchedulerStringId.ReminderThreeDays
Return "3 giorni"
Case RadSchedulerStringId.ReminderFourDays
Return "4 giorni"
Case RadSchedulerStringId.ReminderOneWeek
Return "1 settimana"
Case RadSchedulerStringId.ReminderTwoWeeks
Return "2 settimane"
Case RadSchedulerStringId.Reminder
Return "Promemoria"
Case RadSchedulerStringId.ContextMenuNewAppointment
Return "Nuovo Appuntamento"
Case RadSchedulerStringId.ContextMenuEditAppointment
Return "Modifica Appuntamento"
Case RadSchedulerStringId.ContextMenuNewRecurringAppointment
Return "Nuovo appuntamento ricorrente"
Case RadSchedulerStringId.ContextMenu60Minutes
Return "60 Minuti"
Case RadSchedulerStringId.ContextMenu30Minutes
Return "30 Minuti"
Case RadSchedulerStringId.ContextMenu15Minutes
Return "15 Minuti"
Case RadSchedulerStringId.ContextMenu10Minutes
Return "10 Minuti"
Case RadSchedulerStringId.ContextMenu6Minutes
Return "6 Minuti"
Case RadSchedulerStringId.ContextMenu5Minutes
Return "5 Minuti"
Case RadSchedulerStringId.ContextMenuNavigateToNextView
Return "Vista Successiva"
Case RadSchedulerStringId.ContextMenuNavigateToPreviousView
Return "Vista Precedente"
Case RadSchedulerStringId.ContextMenuTimescales
Return "Scale temporali"
Case RadSchedulerStringId.ContextMenuTimescalesYear
Return "Anno"
Case RadSchedulerStringId.ContextMenuTimescalesMonth
Return "Mese"
Case RadSchedulerStringId.ContextMenuTimescalesWeek
Return "Settimana"
Case RadSchedulerStringId.ContextMenuTimescalesDay
Return "Giorno"
Case RadSchedulerStringId.ContextMenuTimescalesHour
Return "Ora"
Case RadSchedulerStringId.ContextMenuTimescalesHalfHour
Return "30 minuti"
Case RadSchedulerStringId.ContextMenuTimescalesFifteenMinutes
Return "15 minuti"
Case RadSchedulerStringId.ErrorProviderWrongAppointmentDates
Return "L'ora di fine dell'appuntamento è inferiore o uguale all'ora di inizio!"
Case RadSchedulerStringId.ErrorProviderWrongExceptionDuration
Return "L'intervallo di ricorrenza deve essere maggiore o uguale alla durata dell'appuntamento!"
Case RadSchedulerStringId.ErrorProviderExceptionSameDate
Return "Due occorrenze della stessa serie non possono verificarsi nello stesso giorno."
Case RadSchedulerStringId.ErrorProviderExceptionSkipOverDate
Return "L'eccezione di ricorrenza non può ignorare un'occorrenza successiva dello stesso appuntamento."
Case RadSchedulerStringId.TimeZoneLocal
Return "Locale"
Case RadSchedulerStringId.CategoryNone
Return "Personale"
Case RadSchedulerStringId.CategoryBlue
Return "Riunione"
Case RadSchedulerStringId.CategoryGray
Return "Contabilita"
Case RadSchedulerStringId.CategoryGreen
Return "SiCoGe Impegno"
Case RadSchedulerStringId.CategoryLavender
Return "SiCoGe OP"
Case RadSchedulerStringId.CategoryOlive
Return "SiCoGe OA"
Case RadSchedulerStringId.CategoryOrange
Return "SiCoGe Var. Competenza"
Case RadSchedulerStringId.CategoryOrange
Return "SiCoGe Var. Cassa"
Case Else
Debug.Print(id)
Return "*UNKNOWN"
End Select
End Function
1. In Day View, add an appointment for Thursday Jan 30 3. Click the Print Preview button 4. Click on the Print Settings dialog 5. Now change the Print style to Weekly. Note that the DateRange now changes to Jan 27 - Feb 2. 6. Now change the Print style to Monthly. Note that the DateRange now changes to Jan 26 - Feb 2, whereas it should be Jan 26 to Feb 2, since the default week count is 4
The request is covered here - http://feedback.telerik.com/Project/154/Feedback/Details/107090-fix-radscheduler-monthly-print-style-does-not-take-into-consideration-the-week Resolution: In Q2 2014 we introduced new feature: WeeklyCalendarPrintStyle. More information you can find in our help: http://www.telerik.com/help/winforms/scheduler-print-support-schedulerprintstyle.html, section WeeklyCalendarStyle
In some cases when the BindingContext changed (re-bind, re-parent) the control thown the Null Reference Exception
To work around the issue, you can set scheduler's GroupType to None, set the ResourcesPerView property, set the GroupType to Resource: radScheduler1.GroupType = GroupType.None; this.radScheduler1.ActiveView.ResourcesPerView =resourcesPerView radScheduler1.GroupType = GroupType.Resource;
An AppointmentChanged event should be added to RadScheduler that can be handled in VB.NET by the 'Handles' approach. Resolution: The AppointmentChanged event is added which is the Appointments.CollectionChanged event with ItemChanged action.
Let's say that we have the common scenario of loading appointments and resources in RadScheduler. For this purpose we have three tables - Appointments, Resources and AppointmensResources. Normally, (ADO.NET) we have three TableAdapters that fill our tables with data. However, currently we should order them like this: Resources, AppointmentsResources and Appointments. Otherwise, RadScheduler will not be able to load the resources for the existing appointments. CLOSED: The AppointmentsResources table is not assigned anywhere to the scheduler so there is nothing it can notify when filled. However the table is needed in order to resolve the relations between appointments and resources. Therefore, it should be filled before the Appointments table or you can rebind the scheduler by using its DataBind method after you have filled all the tables.
AppointmentFormatting event is not fired when RadScheduler is in TimelineView.
Wrong layout behavior when you create neighborhood appointments.
Wrong layout behavior when the datasource is changed
Add functionality for localization of the error provider in EditAppointmentDialog
Add StatusId property to AppointmentElement class for formatting purposes.
Steps to reproduce: 1. Add a scheduler to a form. 2. Add some data and group it by resource. 3. Add a button and on click call the NavigateToNextResource method: this.radSchedulerDemo.SchedulerElement.NavigateToNextResource(); You will see that nothing happens. WORKAROUND: RadScrollBarElement scrollBarElement = this.radScheduler1.SchedulerElement.ViewElement.Children[3] as RadScrollBarElement; this.radScheduler1.SchedulerElement.NavigateToLastResource(); int numberOfBackSteps = scrollBarElement.Maximum - scrollBarElement.Value - (this.radSchedulerDemo.SchedulerElement.View.ResourcesPerView - 1); for (int i = 0; i <= numberOfBackSteps; i++) { this.radScheduler1.SchedulerElement.NavigateToPreviousResource(); }
Steps to reproduce. 1. Add a RadScheduler to a form, add some appointments. 2. Add grouping with at least two groups. 3. Drag an appointment from the second group (top to bottom) and drop it above the scheduler. The drag hint should be for invalid operation (striked red circle) You will see that the appointment will disappear from the scheduler. WORKAROUND AddHandler Me.RadScheduler1.DragDropBehavior.Stopped, AddressOf DragDropBehavior_Stopped Private Sub DragDropBehavior_Stopped(sender As Object, e As EventArgs) Dim element As TimelineGroupingByResourcesElement = Me.RadScheduler1.SchedulerElement.Children(0) For Each timelineViewElement In element.Children If timelineViewElement.GetType() = GetType(SchedulerTimelineViewElement) Then For Each applicationElement As RadElement In CType(timelineViewElement, SchedulerTimelineViewElement).Presenter.Children If applicationElement.GetType() = GetType(AppointmentElement) Then applicationElement.Visibility = ElementVisibility.Visible End If Next End If Next End Sub