About

I'm Mike Pope. I live in the Seattle area. I've been a technical writer and editor for over 35 years. I'm interested in software, language, music, movies, books, motorcycles, travel, and ... well, lots of stuff.

Read more ...

Blog Search


(Supports AND)

Feed

Subscribe to the RSS feed for this blog.

See this post for info on full versus truncated feeds.

Quote

A new week always seems such a hopeful thing before reality sets in.

Mike Gunderloy



Navigation





<April 2025>
SMTWTFS
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

Categories

  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  
  RSS  

Contact Me

Email me

Blog Statistics

Dates
First entry - 6/27/2003
Most recent entry - 4/22/2025

Totals
Posts - 2658
Comments - 2678
Hits - 2,738,610

Averages
Entries/day - 0.33
Comments/entry - 1.01
Hits/day - 344

Updated every 30 minutes. Last: 1:36 PM Pacific


  02:06 AM

One of the major purposes for using the Calendar control is to have a handy way to be able to select a date. Navigate to a month, click a date, and you've got a guaranteed well-formed date to work with, which you can get this way:
Dim aDate As DateTime = Calendar1.SelectedDate
The Calendar control also supports a multi-select feature that is, IMO, of limited use. If you set the control's SelectionMode property to CalendarSelectionMode.DayWeek, the calendar displays a selection glyph next to each week that allows you to select that week. Similarly, setting SelectionMode to CalendarSelectionMode.DayWeekMonth displays a month-selection glyph that allows you to select that entire month. I can't say I've ever used either of these, although the week-selection mode would probably be useful for those situations where people want to highlight an entire week, as sometimes happens. In those cases, you can get the selection(s) from the Calendar.SelectedDates collection.


Selection Behavior

When you use the Calendar UI to select a date -- whether a day, week, or month -- the Calendar control selects that unit and almost needless to say, unselects any other selected date(s). This can be the source of some frustration, as I'll explain in a moment.

Selecting a date also raises the Calendar control's SelectionChanged event. If you're simply using the Calendar as a date picker, you don't need to handle the event; you can just get the selected date at any time during page processing from the SelectedDate property, as shown earlier. But you do need to handle the event if you want to do something with the selected date, such as display it, to use a lame example:
Sub Calendar1_SelectionChanged(sender As Object, e As EventArgs)
Label1.Text = Calendar1.SelectedDate.ToString()
End Sub
Fortunately, there are more interesting uses for this event.


Selecting Dates Programmatically

The saving grace for the Calendar control's selection model is that you can set selected dates programmatically. The calendar UI doesn't allow you to set multiple dates except for an entire week or month, but you can select any dates by manipulating the SelectedDates collection yourself. Here's a simple example that shows how to select multiple non-contiguous dates:
Calendar1.SelectedDates.Add( New DateTime(2004, 4, 2) )
Calendar1.SelectedDates.Add( New DateTime(2004, 4, 12) )
Calendar1.SelectedDates.Add( New DateTime(2004, 4, 15) )
Where things get a little tricky is when you want to mix the UI -- selecting dates by clicking on them -- with programmatically setting dates.


Selecting Multiple Dates in the UI

Setting selected dates programmatically is well and good, but sometimes you want to allow people to click two dates in the Calendar control and select them both. Imagine a start date and end date for a trip planner, for example. Remember that each time you click a single day, you throw away any previous selection, the source of that frustration I mentioned earlier.

One solution is to grab each date as it's selected and persist it somewhere. When the user clicks another date, you grab that date and add it to your date cache.

Here's an example. When someone clicks a date, it raises the SelectionChanged event. In the event, I call a method that adds the selected date to the SelectedDates collection and adds it to an ArrayList that's shoved into viewstate. (I used ArrayList because it serializes into viewstate nicely.) Each time you click another date, the code reconstructs the ArrayList from viewstate, adds each stored date into the SelectedDates collection, and then adds the newest date as well. End result, each click selects another date.
Sub Calendar1_SelectionChanged(sender As Object, e As EventArgs)
AddToDates( Calendar1.SelectedDate )
End Sub


Sub AddToDates( newDate As DateTime)
Dim dt As DateTime
Dim dtArrayList As ArrayList
If Not Viewstate("selectedDates") Is Nothing Then
dtArrayList = CType(Viewstate("selectedDates"), ArrayList)
Dim i As Integer
For i = 0 to dtArrayList.Count - 1
dt = CType( dtArrayList(i), DateTime)
Calendar1.SelectedDates.Add( dt )
Next
Else
dtArrayList = New ArrayList()
End If


' Display in Calendar
Calendar1.SelectedDates.Add(newDate)
' Add new date to arraylist ...
dtArrayList.Add(newDate)
' ... and persist updated arraylist to viewstate
Viewstate("selectedDates") = dtArrayList
End Sub
Here's a different take on the same strategy. This one allows you both to select and unselect by clicking:
Protected datesArray As ArrayList
Sub Page_Load()
If ViewState("selectedDates") Is Nothing Then
datesArray = new ArrayList()
Else
datesArray = CType( Viewstate("selectedDates"), ArrayList )
End If
End Sub


Sub Calendar1_SelectionChanged(sender As Object, e As EventArgs)
' Is the date already selected? If so, unselect it
Dim index As Integer = -1
index = datesArray.indexOf( Calendar1.SelectedDate )
If index >= 0 Then
datesArray.RemoveAt( index )
Else
datesArray.Add( Calendar1.SelectedDate )
End if
Viewstate("selectedDates") = datesArray
DisplaySelectedDates()
End Sub


Sub DisplaySelectedDates()
Calendar1.SelectedDates.Clear
Dim i As Integer
For i = 0 to datesArray.Count - 1
Calendar1.SelectedDates.Add( datesArray(i) )
Next
End Sub

Selecting a Date Range

You can use a multi-select technique like those above to create a date range. An easier way (for the user) is to allow the user to click one date as the start date and another as the end date. The following is one way to do that. The first click stores the selected date as a start date. The second click stores the end date and selects the range between them. The start date and end date are stored in viewstate. The third click (i.e., if there's already a start date and end date in viewstate) starts over with a new start date. (Note that this code does not check that the end date is after the start date.)
Sub Calendar1_SelectionChanged(sender As Object, e As EventArgs)
If ViewState("startDate") Is Nothing Then
ViewState("startDate") = Calendar1.SelectedDate
Else
If ViewState("endDate") Is Nothing Then
' This must be the end date
Viewstate("endDate") = Calendar1.SelectedDate
Dim startDate As DateTime
startDate = CType(ViewState("startDate"), DateTime)
Filldates(startDate, Calendar1.SelectedDate)
Else
' Since there's already a start date and end date,
' another click resets the start date
ViewState("startDate") = Calendar1.SelectedDate
ViewState("endDate") = Nothing
End if
End If
End Sub


Sub FillDates(sdate, edate)
While sdate <= edate
Calendar1.SelectedDates.Add(sdate)
sdate = sdate.AddDays(1)
End While
End Sub

Reselecting the Current Date
A, um, interesting feature of the Calendar control is that if you click the currently selected date, the SelectionChanged event isn't raised again. Presumably it's because the date hasn't changed. Whatever. Sometimes it's still handy to get that event, even if the date is already selected. There are a number of ways to do this.

1) Set EnableViewState to false for the Calendar. Presto! It won't remember a thing and you can click all you want.
2) In the SelectionChanged event, clear the SelectedDates collection (Calendar1.SelectedDates.Clear()).

The distinct disadvantage of these two methods is that, well, the selected date isn't saved. If you want to read the selected date programmatically, there's nothing there to read. That isn't necessarily a showstopper -- in the SelectionChanged handler you could save off the selected date (perhaps into a control) and then get it from there. But for sure there is a problem with visually indicating the selected date in the calendar. Method 1 displays the selected date while you're clicking in the calendar, but not if you cause a postback some other way. Method 2 doesn't display any selected date at all, since there isn't one.

I've played around with various ways to get around these problems. The following is something I came up with that allows you to click the same date repeatedly and it mocks what the date would look like if selected. To solve the problem of having no selected date to read, I created a page property that stores the most recently clicked date. You can't get the selected date out of the calendar directly -- once again, there is no actual selected date -- but you can get it from the page property. Not the best solution, but workable.
Protected Property SavedDate() As DateTime
Get
If ViewState("savedDate") Is Nothing Then
Return Nothing
Else
Return CType(ViewState("savedDate"), DateTime)
End If
End Get


Set (ByVal Value As DateTime)
ViewState("savedDate") = Value
End Set
End Property


Sub Calendar1_SelectionChanged(sender As Object, e As EventArgs)
Me.SavedDate = Calendar1.SelectedDate
Calendar1.SelectedDates.Clear()
Calendar1.SelectedDates.Add(Calendar1.SelectedDate)
End Sub


Sub Calendar1_DayRender(sender As Object, e As DayRenderEventArgs)
If e.Day.Date = Me.SavedDate Then
e.Cell.ForeColor = Calendar1.SelectedDayStyle.ForeColor
e.Cell.BackColor = Calendar1.SelectedDayStyle.BackColor
End If
End Sub


Sub Button1_Click(sender As Object, e As EventArgs)
Response.Write("<br>Current date = " & Me.SavedDate)
End Sub
I believe that these techniques cover a lot of requirements that people have for being able to select calendar dates. However, I'll poke around in my notes to see what else I have. If you have a specific scenario that you can't get working, I'd be interested in hearing about it.

[categories]  

[5] |